aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:04 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-11 12:38:11 +0000
commite3b557809604d036af6e00c60f012c2025b59a5e (patch)
tree8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib
parent08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff)
downloadsrc-e3b557809604d036af6e00c60f012c2025b59a5e.tar.gz
src-e3b557809604d036af6e00c60f012c2025b59a5e.zip
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/APINotes/APINotesYAMLCompiler.cpp76
-rw-r--r--clang/lib/ARCMigrate/ARCMTActions.cpp4
-rw-r--r--clang/lib/ARCMigrate/Internals.h6
-rw-r--r--clang/lib/ARCMigrate/ObjCMT.cpp18
-rw-r--r--clang/lib/ARCMigrate/TransGCAttrs.cpp4
-rw-r--r--clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp2
-rw-r--r--clang/lib/ARCMigrate/TransformActions.cpp2
-rw-r--r--clang/lib/AST/APValue.cpp18
-rw-r--r--clang/lib/AST/ASTConcept.cpp72
-rw-r--r--clang/lib/AST/ASTContext.cpp1683
-rw-r--r--clang/lib/AST/ASTDiagnostic.cpp39
-rw-r--r--clang/lib/AST/ASTDumper.cpp55
-rw-r--r--clang/lib/AST/ASTImporter.cpp496
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp159
-rw-r--r--clang/lib/AST/AttrDocTable.cpp2
-rw-r--r--clang/lib/AST/AttrImpl.cpp41
-rw-r--r--clang/lib/AST/CXXInheritance.cpp1
-rw-r--r--clang/lib/AST/Comment.cpp6
-rw-r--r--clang/lib/AST/CommentCommandTraits.cpp8
-rw-r--r--clang/lib/AST/CommentLexer.cpp2
-rw-r--r--clang/lib/AST/CommentParser.cpp31
-rw-r--r--clang/lib/AST/CommentSema.cpp6
-rw-r--r--clang/lib/AST/ComparisonCategories.cpp5
-rw-r--r--clang/lib/AST/ComputeDependence.cpp20
-rw-r--r--clang/lib/AST/Decl.cpp258
-rw-r--r--clang/lib/AST/DeclBase.cpp47
-rw-r--r--clang/lib/AST/DeclCXX.cpp188
-rw-r--r--clang/lib/AST/DeclObjC.cpp100
-rw-r--r--clang/lib/AST/DeclOpenMP.cpp2
-rw-r--r--clang/lib/AST/DeclPrinter.cpp35
-rw-r--r--clang/lib/AST/DeclTemplate.cpp191
-rw-r--r--clang/lib/AST/DeclarationName.cpp12
-rw-r--r--clang/lib/AST/Expr.cpp101
-rw-r--r--clang/lib/AST/ExprCXX.cpp148
-rw-r--r--clang/lib/AST/ExprClassification.cpp10
-rw-r--r--clang/lib/AST/ExprConcepts.cpp77
-rw-r--r--clang/lib/AST/ExprConstant.cpp688
-rw-r--r--clang/lib/AST/ExternalASTSource.cpp6
-rw-r--r--clang/lib/AST/FormatString.cpp134
-rw-r--r--clang/lib/AST/Interp/Boolean.h27
-rw-r--r--clang/lib/AST/Interp/ByteCodeEmitter.cpp135
-rw-r--r--clang/lib/AST/Interp/ByteCodeEmitter.h4
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.cpp1138
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.h171
-rw-r--r--clang/lib/AST/Interp/ByteCodeGenError.h12
-rw-r--r--clang/lib/AST/Interp/ByteCodeStmtGen.cpp203
-rw-r--r--clang/lib/AST/Interp/ByteCodeStmtGen.h16
-rw-r--r--clang/lib/AST/Interp/Context.cpp39
-rw-r--r--clang/lib/AST/Interp/Context.h6
-rw-r--r--clang/lib/AST/Interp/Descriptor.cpp93
-rw-r--r--clang/lib/AST/Interp/Descriptor.h92
-rw-r--r--clang/lib/AST/Interp/Disasm.cpp28
-rw-r--r--clang/lib/AST/Interp/EvalEmitter.cpp29
-rw-r--r--clang/lib/AST/Interp/EvalEmitter.h12
-rw-r--r--clang/lib/AST/Interp/Function.cpp15
-rw-r--r--clang/lib/AST/Interp/Function.h74
-rw-r--r--clang/lib/AST/Interp/Integral.h126
-rw-r--r--clang/lib/AST/Interp/Interp.cpp93
-rw-r--r--clang/lib/AST/Interp/Interp.h547
-rw-r--r--clang/lib/AST/Interp/InterpBlock.h53
-rw-r--r--clang/lib/AST/Interp/InterpFrame.cpp90
-rw-r--r--clang/lib/AST/Interp/InterpFrame.h42
-rw-r--r--clang/lib/AST/Interp/InterpStack.cpp2
-rw-r--r--clang/lib/AST/Interp/InterpStack.h67
-rw-r--r--clang/lib/AST/Interp/InterpState.h3
-rw-r--r--clang/lib/AST/Interp/Opcodes.td118
-rw-r--r--clang/lib/AST/Interp/Pointer.cpp26
-rw-r--r--clang/lib/AST/Interp/Pointer.h49
-rw-r--r--clang/lib/AST/Interp/PrimType.cpp4
-rw-r--r--clang/lib/AST/Interp/PrimType.h14
-rw-r--r--clang/lib/AST/Interp/Program.cpp123
-rw-r--r--clang/lib/AST/Interp/Program.h54
-rw-r--r--clang/lib/AST/Interp/Record.h22
-rw-r--r--clang/lib/AST/Interp/Source.cpp4
-rw-r--r--clang/lib/AST/Interp/Source.h16
-rw-r--r--clang/lib/AST/Interp/State.h5
-rw-r--r--clang/lib/AST/ItaniumCXXABI.cpp17
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp101
-rw-r--r--clang/lib/AST/JSONNodeDumper.cpp40
-rw-r--r--clang/lib/AST/Linkage.h8
-rw-r--r--clang/lib/AST/Mangle.cpp8
-rw-r--r--clang/lib/AST/MicrosoftCXXABI.cpp4
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp51
-rw-r--r--clang/lib/AST/NSAPI.cpp25
-rw-r--r--clang/lib/AST/NestedNameSpecifier.cpp4
-rw-r--r--clang/lib/AST/ODRDiagsEmitter.cpp2206
-rw-r--r--clang/lib/AST/ODRHash.cpp186
-rw-r--r--clang/lib/AST/OSLog.cpp11
-rw-r--r--clang/lib/AST/OpenMPClause.cpp109
-rw-r--r--clang/lib/AST/ParentMap.cpp4
-rw-r--r--clang/lib/AST/ParentMapContext.cpp23
-rw-r--r--clang/lib/AST/PrintfFormatString.cpp37
-rw-r--r--clang/lib/AST/QualTypeNames.cpp23
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp72
-rw-r--r--clang/lib/AST/ScanfFormatString.cpp8
-rw-r--r--clang/lib/AST/Stmt.cpp11
-rw-r--r--clang/lib/AST/StmtOpenMP.cpp21
-rw-r--r--clang/lib/AST/StmtPrinter.cpp26
-rw-r--r--clang/lib/AST/StmtProfile.cpp28
-rw-r--r--clang/lib/AST/TemplateBase.cpp32
-rw-r--r--clang/lib/AST/TemplateName.cpp65
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp36
-rw-r--r--clang/lib/AST/Type.cpp276
-rw-r--r--clang/lib/AST/TypeLoc.cpp40
-rw-r--r--clang/lib/AST/TypePrinter.cpp294
-rw-r--r--clang/lib/AST/VTableBuilder.cpp5
-rw-r--r--clang/lib/ASTMatchers/ASTMatchFinder.cpp14
-rw-r--r--clang/lib/ASTMatchers/ASTMatchersInternal.cpp17
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Marshallers.cpp61
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Marshallers.h74
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Parser.cpp23
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp14
-rw-r--r--clang/lib/ASTMatchers/Dynamic/VariantValue.cpp33
-rw-r--r--clang/lib/Analysis/AnalysisDeclContext.cpp9
-rw-r--r--clang/lib/Analysis/BodyFarm.cpp13
-rw-r--r--clang/lib/Analysis/CFG.cpp210
-rw-r--r--clang/lib/Analysis/CFGStmtMap.cpp3
-rw-r--r--clang/lib/Analysis/CalledOnceCheck.cpp60
-rw-r--r--clang/lib/Analysis/Consumed.cpp6
-rw-r--r--clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp8
-rw-r--r--clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp58
-rw-r--r--clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp472
-rw-r--r--clang/lib/Analysis/FlowSensitive/DebugSupport.cpp35
-rw-r--r--clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp6
-rw-r--r--clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp367
-rw-r--r--clang/lib/Analysis/FlowSensitive/Transfer.cpp288
-rw-r--r--clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp340
-rw-r--r--clang/lib/Analysis/FlowSensitive/Value.cpp56
-rw-r--r--clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp5
-rw-r--r--clang/lib/Analysis/IssueHash.cpp5
-rw-r--r--clang/lib/Analysis/LiveVariables.cpp3
-rw-r--r--clang/lib/Analysis/MacroExpansionContext.cpp15
-rw-r--r--clang/lib/Analysis/PathDiagnostic.cpp72
-rw-r--r--clang/lib/Analysis/ReachableCode.cpp17
-rw-r--r--clang/lib/Analysis/RetainSummaryManager.cpp39
-rw-r--r--clang/lib/Analysis/ThreadSafety.cpp231
-rw-r--r--clang/lib/Analysis/ThreadSafetyCommon.cpp48
-rw-r--r--clang/lib/Analysis/UninitializedValues.cpp23
-rw-r--r--clang/lib/Analysis/UnsafeBufferUsage.cpp695
-rw-r--r--clang/lib/Basic/Attributes.cpp1
-rw-r--r--clang/lib/Basic/BuiltinTargetFeatures.h2
-rw-r--r--clang/lib/Basic/Builtins.cpp95
-rw-r--r--clang/lib/Basic/CLWarnings.cpp3
-rw-r--r--clang/lib/Basic/Cuda.cpp153
-rw-r--r--clang/lib/Basic/DarwinSDKInfo.cpp40
-rw-r--r--clang/lib/Basic/DiagnosticIDs.cpp17
-rw-r--r--clang/lib/Basic/DiagnosticOptions.cpp2
-rw-r--r--clang/lib/Basic/FileManager.cpp40
-rw-r--r--clang/lib/Basic/IdentifierTable.cpp217
-rw-r--r--clang/lib/Basic/LangStandards.cpp14
-rw-r--r--clang/lib/Basic/Module.cpp28
-rw-r--r--clang/lib/Basic/OpenMPKinds.cpp96
-rw-r--r--clang/lib/Basic/ProfileList.cpp58
-rw-r--r--clang/lib/Basic/SanitizerSpecialCaseList.cpp2
-rw-r--r--clang/lib/Basic/Sanitizers.cpp2
-rw-r--r--clang/lib/Basic/Sarif.cpp65
-rw-r--r--clang/lib/Basic/SourceLocation.cpp8
-rw-r--r--clang/lib/Basic/SourceManager.cpp373
-rw-r--r--clang/lib/Basic/Stack.cpp1
-rw-r--r--clang/lib/Basic/TargetID.cpp42
-rw-r--r--clang/lib/Basic/TargetInfo.cpp94
-rw-r--r--clang/lib/Basic/Targets.cpp22
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp673
-rw-r--r--clang/lib/Basic/Targets/AArch64.h107
-rw-r--r--clang/lib/Basic/Targets/AMDGPU.cpp99
-rw-r--r--clang/lib/Basic/Targets/AMDGPU.h28
-rw-r--r--clang/lib/Basic/Targets/ARC.h8
-rw-r--r--clang/lib/Basic/Targets/ARM.cpp57
-rw-r--r--clang/lib/Basic/Targets/ARM.h6
-rw-r--r--clang/lib/Basic/Targets/AVR.cpp746
-rw-r--r--clang/lib/Basic/Targets/AVR.h14
-rw-r--r--clang/lib/Basic/Targets/BPF.cpp8
-rw-r--r--clang/lib/Basic/Targets/BPF.h7
-rw-r--r--clang/lib/Basic/Targets/CSKY.cpp4
-rw-r--r--clang/lib/Basic/Targets/DirectX.h15
-rw-r--r--clang/lib/Basic/Targets/Hexagon.cpp32
-rw-r--r--clang/lib/Basic/Targets/Hexagon.h1
-rw-r--r--clang/lib/Basic/Targets/Lanai.cpp4
-rw-r--r--clang/lib/Basic/Targets/Lanai.h4
-rw-r--r--clang/lib/Basic/Targets/Le64.h6
-rw-r--r--clang/lib/Basic/Targets/LoongArch.cpp217
-rw-r--r--clang/lib/Basic/Targets/LoongArch.h136
-rw-r--r--clang/lib/Basic/Targets/M68k.cpp17
-rw-r--r--clang/lib/Basic/Targets/M68k.h3
-rw-r--r--clang/lib/Basic/Targets/MSP430.cpp2
-rw-r--r--clang/lib/Basic/Targets/MSP430.h4
-rw-r--r--clang/lib/Basic/Targets/Mips.cpp24
-rw-r--r--clang/lib/Basic/Targets/Mips.h7
-rw-r--r--clang/lib/Basic/Targets/NVPTX.cpp53
-rw-r--r--clang/lib/Basic/Targets/NVPTX.h19
-rw-r--r--clang/lib/Basic/Targets/OSTargets.cpp132
-rw-r--r--clang/lib/Basic/Targets/OSTargets.h60
-rw-r--r--clang/lib/Basic/Targets/PNaCl.cpp6
-rw-r--r--clang/lib/Basic/Targets/PNaCl.h4
-rw-r--r--clang/lib/Basic/Targets/PPC.cpp17
-rw-r--r--clang/lib/Basic/Targets/PPC.h5
-rw-r--r--clang/lib/Basic/Targets/RISCV.cpp110
-rw-r--r--clang/lib/Basic/Targets/RISCV.h22
-rw-r--r--clang/lib/Basic/Targets/SPIR.h19
-rw-r--r--clang/lib/Basic/Targets/Sparc.cpp4
-rw-r--r--clang/lib/Basic/Targets/Sparc.h2
-rw-r--r--clang/lib/Basic/Targets/SystemZ.cpp16
-rw-r--r--clang/lib/Basic/Targets/SystemZ.h24
-rw-r--r--clang/lib/Basic/Targets/TCE.h11
-rw-r--r--clang/lib/Basic/Targets/VE.cpp13
-rw-r--r--clang/lib/Basic/Targets/VE.h5
-rw-r--r--clang/lib/Basic/Targets/WebAssembly.cpp26
-rw-r--r--clang/lib/Basic/Targets/WebAssembly.h5
-rw-r--r--clang/lib/Basic/Targets/X86.cpp153
-rw-r--r--clang/lib/Basic/Targets/X86.h42
-rw-r--r--clang/lib/Basic/Targets/XCore.cpp10
-rw-r--r--clang/lib/Basic/Targets/XCore.h5
-rw-r--r--clang/lib/Basic/TypeTraits.cpp14
-rw-r--r--clang/lib/CodeGen/ABIInfo.h46
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp249
-rw-r--r--clang/lib/CodeGen/CGAtomic.cpp40
-rw-r--r--clang/lib/CodeGen/CGBlocks.cpp22
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp1789
-rw-r--r--clang/lib/CodeGen/CGCUDANV.cpp71
-rw-r--r--clang/lib/CodeGen/CGCUDARuntime.h2
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h12
-rw-r--r--clang/lib/CodeGen/CGCall.cpp251
-rw-r--r--clang/lib/CodeGen/CGClass.cpp94
-rw-r--r--clang/lib/CodeGen/CGCleanup.cpp10
-rw-r--r--clang/lib/CodeGen/CGCoroutine.cpp20
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.cpp381
-rw-r--r--clang/lib/CodeGen/CGDebugInfo.h29
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp14
-rw-r--r--clang/lib/CodeGen/CGDeclCXX.cpp97
-rw-r--r--clang/lib/CodeGen/CGException.cpp17
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp195
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp108
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp2
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp257
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp60
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp316
-rw-r--r--clang/lib/CodeGen/CGGPUBuiltin.cpp2
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.cpp413
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.h67
-rw-r--r--clang/lib/CodeGen/CGLoopInfo.cpp17
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp172
-rw-r--r--clang/lib/CodeGen/CGObjCGNU.cpp17
-rw-r--r--clang/lib/CodeGen/CGObjCMac.cpp56
-rw-r--r--clang/lib/CodeGen/CGObjCRuntime.cpp28
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.cpp1695
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.h319
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp431
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntimeGPU.h31
-rw-r--r--clang/lib/CodeGen/CGRecordLayoutBuilder.cpp2
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp87
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp257
-rw-r--r--clang/lib/CodeGen/CGVTT.cpp2
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp58
-rw-r--r--clang/lib/CodeGen/CGVTables.h7
-rw-r--r--clang/lib/CodeGen/CodeGenAction.cpp41
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp185
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h71
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp508
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h54
-rw-r--r--clang/lib/CodeGen/CodeGenPGO.cpp13
-rw-r--r--clang/lib/CodeGen/CodeGenPGO.h7
-rw-r--r--clang/lib/CodeGen/CodeGenTBAA.cpp2
-rw-r--r--clang/lib/CodeGen/CodeGenTypeCache.h3
-rw-r--r--clang/lib/CodeGen/CodeGenTypes.cpp28
-rw-r--r--clang/lib/CodeGen/CodeGenTypes.h3
-rw-r--r--clang/lib/CodeGen/ConstantEmitter.h3
-rw-r--r--clang/lib/CodeGen/ConstantInitBuilder.cpp11
-rw-r--r--clang/lib/CodeGen/CoverageMappingGen.cpp112
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp201
-rw-r--r--clang/lib/CodeGen/MacroPPCallbacks.cpp4
-rw-r--r--clang/lib/CodeGen/MacroPPCallbacks.h2
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp89
-rw-r--r--clang/lib/CodeGen/ModuleBuilder.cpp1
-rw-r--r--clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp4
-rw-r--r--clang/lib/CodeGen/PatternInit.cpp4
-rw-r--r--clang/lib/CodeGen/SanitizerMetadata.cpp2
-rw-r--r--clang/lib/CodeGen/SwiftCallingConv.cpp36
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp1072
-rw-r--r--clang/lib/CodeGen/TargetInfo.h13
-rw-r--r--clang/lib/CodeGen/VarBypassDetector.cpp2
-rw-r--r--clang/lib/CrossTU/CrossTranslationUnit.cpp14
-rw-r--r--clang/lib/DirectoryWatcher/DirectoryScanner.cpp5
-rw-r--r--clang/lib/DirectoryWatcher/DirectoryScanner.h5
-rw-r--r--clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp5
-rw-r--r--clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp2
-rw-r--r--clang/lib/Driver/Action.cpp37
-rw-r--r--clang/lib/Driver/Compilation.cpp13
-rw-r--r--clang/lib/Driver/Distro.cpp1
-rw-r--r--clang/lib/Driver/Driver.cpp1199
-rw-r--r--clang/lib/Driver/DriverOptions.cpp39
-rw-r--r--clang/lib/Driver/Job.cpp31
-rw-r--r--clang/lib/Driver/OffloadBundler.cpp1283
-rw-r--r--clang/lib/Driver/SanitizerArgs.cpp129
-rw-r--r--clang/lib/Driver/ToolChain.cpp111
-rw-r--r--clang/lib/Driver/ToolChains/AIX.cpp100
-rw-r--r--clang/lib/Driver/ToolChains/AIX.h4
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPU.cpp229
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPU.h18
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp281
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPUOpenMP.h49
-rw-r--r--clang/lib/Driver/ToolChains/AVR.cpp81
-rw-r--r--clang/lib/Driver/ToolChains/AVR.h4
-rw-r--r--clang/lib/Driver/ToolChains/Arch/AArch64.cpp79
-rw-r--r--clang/lib/Driver/ToolChains/Arch/ARM.cpp26
-rw-r--r--clang/lib/Driver/ToolChains/Arch/CSKY.cpp15
-rw-r--r--clang/lib/Driver/ToolChains/Arch/CSKY.h6
-rw-r--r--clang/lib/Driver/ToolChains/Arch/LoongArch.cpp115
-rw-r--r--clang/lib/Driver/ToolChains/Arch/LoongArch.h31
-rw-r--r--clang/lib/Driver/ToolChains/Arch/Mips.cpp4
-rw-r--r--clang/lib/Driver/ToolChains/Arch/PPC.cpp62
-rw-r--r--clang/lib/Driver/ToolChains/Arch/PPC.h3
-rw-r--r--clang/lib/Driver/ToolChains/Arch/RISCV.cpp63
-rw-r--r--clang/lib/Driver/ToolChains/Arch/RISCV.h2
-rw-r--r--clang/lib/Driver/ToolChains/Arch/Sparc.cpp78
-rw-r--r--clang/lib/Driver/ToolChains/Arch/Sparc.h3
-rw-r--r--clang/lib/Driver/ToolChains/Arch/VE.cpp1
-rw-r--r--clang/lib/Driver/ToolChains/Arch/X86.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/BareMetal.cpp64
-rw-r--r--clang/lib/Driver/ToolChains/BareMetal.h23
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp947
-rw-r--r--clang/lib/Driver/ToolChains/Clang.h15
-rw-r--r--clang/lib/Driver/ToolChains/CommonArgs.cpp626
-rw-r--r--clang/lib/Driver/ToolChains/CommonArgs.h26
-rw-r--r--clang/lib/Driver/ToolChains/CrossWindows.cpp5
-rw-r--r--clang/lib/Driver/ToolChains/CrossWindows.h3
-rw-r--r--clang/lib/Driver/ToolChains/Cuda.cpp359
-rw-r--r--clang/lib/Driver/ToolChains/Cuda.h129
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.cpp363
-rw-r--r--clang/lib/Driver/ToolChains/Darwin.h22
-rw-r--r--clang/lib/Driver/ToolChains/Flang.cpp202
-rw-r--r--clang/lib/Driver/ToolChains/Flang.h23
-rw-r--r--clang/lib/Driver/ToolChains/FreeBSD.cpp40
-rw-r--r--clang/lib/Driver/ToolChains/FreeBSD.h6
-rw-r--r--clang/lib/Driver/ToolChains/Fuchsia.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/Fuchsia.h5
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.cpp146
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.h9
-rw-r--r--clang/lib/Driver/ToolChains/HIPAMD.cpp27
-rw-r--r--clang/lib/Driver/ToolChains/HIPAMD.h2
-rw-r--r--clang/lib/Driver/ToolChains/HIPSPV.cpp6
-rw-r--r--clang/lib/Driver/ToolChains/HIPSPV.h2
-rw-r--r--clang/lib/Driver/ToolChains/HLSL.cpp45
-rw-r--r--clang/lib/Driver/ToolChains/HLSL.h3
-rw-r--r--clang/lib/Driver/ToolChains/Hexagon.cpp27
-rw-r--r--clang/lib/Driver/ToolChains/Hexagon.h4
-rw-r--r--clang/lib/Driver/ToolChains/Linux.cpp67
-rw-r--r--clang/lib/Driver/ToolChains/Linux.h2
-rw-r--r--clang/lib/Driver/ToolChains/MSP430.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.cpp15
-rw-r--r--clang/lib/Driver/ToolChains/MSVC.h5
-rw-r--r--clang/lib/Driver/ToolChains/MinGW.cpp157
-rw-r--r--clang/lib/Driver/ToolChains/MinGW.h10
-rw-r--r--clang/lib/Driver/ToolChains/Myriad.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/NetBSD.cpp35
-rw-r--r--clang/lib/Driver/ToolChains/NetBSD.h8
-rw-r--r--clang/lib/Driver/ToolChains/OpenBSD.cpp15
-rw-r--r--clang/lib/Driver/ToolChains/OpenBSD.h3
-rw-r--r--clang/lib/Driver/ToolChains/PPCLinux.cpp22
-rw-r--r--clang/lib/Driver/ToolChains/PPCLinux.h2
-rw-r--r--clang/lib/Driver/ToolChains/PS4CPU.cpp43
-rw-r--r--clang/lib/Driver/ToolChains/ROCm.h12
-rw-r--r--clang/lib/Driver/ToolChains/Solaris.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/WebAssembly.cpp4
-rw-r--r--clang/lib/Driver/Types.cpp129
-rw-r--r--clang/lib/Driver/XRayArgs.cpp3
-rw-r--r--clang/lib/Edit/RewriteObjCFoundationAPI.cpp19
-rw-r--r--clang/lib/ExtractAPI/API.cpp225
-rw-r--r--clang/lib/ExtractAPI/APIIgnoresList.cpp53
-rw-r--r--clang/lib/ExtractAPI/AvailabilityInfo.cpp50
-rw-r--r--clang/lib/ExtractAPI/DeclarationFragments.cpp34
-rw-r--r--clang/lib/ExtractAPI/ExtractAPIConsumer.cpp612
-rw-r--r--clang/lib/ExtractAPI/ExtractAPIVisitor.cpp560
-rw-r--r--clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp379
-rw-r--r--clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp7
-rw-r--r--clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h2
-rw-r--r--clang/lib/Format/BreakableToken.cpp8
-rw-r--r--clang/lib/Format/ContinuationIndenter.cpp95
-rw-r--r--clang/lib/Format/ContinuationIndenter.h9
-rw-r--r--clang/lib/Format/DefinitionBlockSeparator.cpp6
-rw-r--r--clang/lib/Format/Format.cpp1250
-rw-r--r--clang/lib/Format/FormatToken.cpp3
-rw-r--r--clang/lib/Format/FormatToken.h92
-rw-r--r--clang/lib/Format/FormatTokenLexer.cpp184
-rw-r--r--clang/lib/Format/FormatTokenLexer.h7
-rw-r--r--clang/lib/Format/IntegerLiteralSeparatorFixer.cpp199
-rw-r--r--clang/lib/Format/IntegerLiteralSeparatorFixer.h38
-rw-r--r--clang/lib/Format/MacroCallReconstructor.cpp23
-rw-r--r--clang/lib/Format/QualifierAlignmentFixer.cpp4
-rw-r--r--clang/lib/Format/TokenAnalyzer.cpp6
-rw-r--r--clang/lib/Format/TokenAnalyzer.h3
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp445
-rw-r--r--clang/lib/Format/TokenAnnotator.h15
-rw-r--r--clang/lib/Format/UnwrappedLineFormatter.cpp50
-rw-r--r--clang/lib/Format/UnwrappedLineFormatter.h2
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp598
-rw-r--r--clang/lib/Format/UnwrappedLineParser.h30
-rw-r--r--clang/lib/Format/UsingDeclarationsSorter.cpp57
-rw-r--r--clang/lib/Format/WhitespaceManager.cpp57
-rw-r--r--clang/lib/Format/WhitespaceManager.h2
-rw-r--r--clang/lib/Frontend/ASTUnit.cpp49
-rw-r--r--clang/lib/Frontend/ChainedIncludesSource.cpp39
-rw-r--r--clang/lib/Frontend/CompilerInstance.cpp98
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp311
-rw-r--r--clang/lib/Frontend/DependencyFile.cpp30
-rw-r--r--clang/lib/Frontend/DependencyGraph.cpp16
-rw-r--r--clang/lib/Frontend/DiagnosticRenderer.cpp5
-rw-r--r--clang/lib/Frontend/FrontendAction.cpp59
-rw-r--r--clang/lib/Frontend/FrontendActions.cpp104
-rw-r--r--clang/lib/Frontend/FrontendOptions.cpp1
-rw-r--r--clang/lib/Frontend/HeaderIncludeGen.cpp137
-rw-r--r--clang/lib/Frontend/InitPreprocessor.cpp64
-rw-r--r--clang/lib/Frontend/ModuleDependencyCollector.cpp15
-rw-r--r--clang/lib/Frontend/PrecompiledPreamble.cpp4
-rw-r--r--clang/lib/Frontend/PrintPreprocessedOutput.cpp16
-rw-r--r--clang/lib/Frontend/Rewrite/InclusionRewriter.cpp48
-rw-r--r--clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp10
-rw-r--r--clang/lib/Frontend/SARIFDiagnostic.cpp225
-rw-r--r--clang/lib/Frontend/SARIFDiagnosticPrinter.cpp83
-rw-r--r--clang/lib/Frontend/SerializedDiagnosticReader.cpp8
-rw-r--r--clang/lib/Frontend/TextDiagnostic.cpp11
-rw-r--r--clang/lib/Frontend/VerifyDiagnosticConsumer.cpp2
-rw-r--r--clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp2
-rw-r--r--clang/lib/Headers/__clang_cuda_texture_intrinsics.h2
-rw-r--r--clang/lib/Headers/__clang_hip_libdevice_declares.h5
-rw-r--r--clang/lib/Headers/__clang_hip_math.h23
-rw-r--r--clang/lib/Headers/__clang_hip_runtime_wrapper.h1
-rw-r--r--clang/lib/Headers/__clang_hip_stdlib.h43
-rw-r--r--clang/lib/Headers/altivec.h28
-rw-r--r--clang/lib/Headers/amxfp16intrin.h58
-rw-r--r--clang/lib/Headers/amxintrin.h32
-rw-r--r--clang/lib/Headers/arm_acle.h151
-rw-r--r--clang/lib/Headers/arm_neon_sve_bridge.h2
-rw-r--r--clang/lib/Headers/avx512bf16intrin.h33
-rw-r--r--clang/lib/Headers/avx512fintrin.h4
-rw-r--r--clang/lib/Headers/avx512fp16intrin.h15
-rw-r--r--clang/lib/Headers/avx512ifmavlintrin.h40
-rw-r--r--clang/lib/Headers/avx512vlbf16intrin.h69
-rw-r--r--clang/lib/Headers/avx512vlbwintrin.h352
-rw-r--r--clang/lib/Headers/avx512vlfp16intrin.h3
-rw-r--r--clang/lib/Headers/avxifmaintrin.h177
-rw-r--r--clang/lib/Headers/avxintrin.h14
-rw-r--r--clang/lib/Headers/avxneconvertintrin.h484
-rw-r--r--clang/lib/Headers/avxvnniint8intrin.h471
-rw-r--r--clang/lib/Headers/cmpccxaddintrin.h70
-rw-r--r--clang/lib/Headers/cpuid.h13
-rw-r--r--clang/lib/Headers/cuda_wrappers/cmath90
-rw-r--r--clang/lib/Headers/emmintrin.h12
-rw-r--r--clang/lib/Headers/float.h27
-rw-r--r--clang/lib/Headers/gfniintrin.h12
-rw-r--r--clang/lib/Headers/hlsl/hlsl_basic_types.h3
-rw-r--r--clang/lib/Headers/hlsl/hlsl_intrinsics.h208
-rw-r--r--clang/lib/Headers/immintrin.h48
-rw-r--r--clang/lib/Headers/larchintrin.h234
-rw-r--r--clang/lib/Headers/limits.h5
-rw-r--r--clang/lib/Headers/opencl-c-base.h19
-rw-r--r--clang/lib/Headers/opencl-c.h320
-rw-r--r--clang/lib/Headers/openmp_wrappers/stdlib.h29
-rw-r--r--clang/lib/Headers/ppc_wrappers/emmintrin.h4
-rw-r--r--clang/lib/Headers/ppc_wrappers/mm_malloc.h2
-rw-r--r--clang/lib/Headers/ppc_wrappers/mmintrin.h4
-rw-r--r--clang/lib/Headers/ppc_wrappers/pmmintrin.h4
-rw-r--r--clang/lib/Headers/ppc_wrappers/smmintrin.h4
-rw-r--r--clang/lib/Headers/ppc_wrappers/tmmintrin.h4
-rw-r--r--clang/lib/Headers/ppc_wrappers/xmmintrin.h4
-rw-r--r--clang/lib/Headers/prfchiintrin.h61
-rw-r--r--clang/lib/Headers/raointintrin.h203
-rw-r--r--clang/lib/Headers/smmintrin.h2
-rw-r--r--clang/lib/Headers/stdarg.h30
-rw-r--r--clang/lib/Headers/stdatomic.h9
-rw-r--r--clang/lib/Headers/stdbool.h4
-rw-r--r--clang/lib/Headers/stddef.h9
-rw-r--r--clang/lib/Headers/stdint.h198
-rw-r--r--clang/lib/Headers/stdnoreturn.h2
-rw-r--r--clang/lib/Headers/unwind.h3
-rw-r--r--clang/lib/Headers/velintrin.h2
-rw-r--r--clang/lib/Headers/x86gprintrin.h26
-rw-r--r--clang/lib/Headers/xmmintrin.h3
-rw-r--r--clang/lib/Index/FileIndexRecord.cpp12
-rw-r--r--clang/lib/Index/IndexBody.cpp2
-rw-r--r--clang/lib/Index/IndexingContext.h14
-rw-r--r--clang/lib/Index/USRGeneration.cpp148
-rw-r--r--clang/lib/Interpreter/IncrementalExecutor.cpp6
-rw-r--r--clang/lib/Interpreter/IncrementalExecutor.h1
-rw-r--r--clang/lib/Interpreter/IncrementalParser.cpp18
-rw-r--r--clang/lib/Interpreter/Interpreter.cpp26
-rw-r--r--clang/lib/Lex/DependencyDirectivesScanner.cpp94
-rw-r--r--clang/lib/Lex/HeaderMap.cpp21
-rw-r--r--clang/lib/Lex/HeaderSearch.cpp220
-rw-r--r--clang/lib/Lex/InitHeaderSearch.cpp146
-rw-r--r--clang/lib/Lex/Lexer.cpp283
-rw-r--r--clang/lib/Lex/LiteralSupport.cpp36
-rw-r--r--clang/lib/Lex/MacroArgs.cpp6
-rw-r--r--clang/lib/Lex/MacroInfo.cpp12
-rw-r--r--clang/lib/Lex/ModuleMap.cpp192
-rw-r--r--clang/lib/Lex/PPCallbacks.cpp5
-rw-r--r--clang/lib/Lex/PPDirectives.cpp119
-rw-r--r--clang/lib/Lex/PPExpressions.cpp2
-rw-r--r--clang/lib/Lex/PPLexerChange.cpp7
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp144
-rw-r--r--clang/lib/Lex/Pragma.cpp33
-rw-r--r--clang/lib/Lex/PreprocessingRecord.cpp23
-rw-r--r--clang/lib/Lex/Preprocessor.cpp98
-rw-r--r--clang/lib/Lex/TokenConcatenation.cpp2
-rw-r--r--clang/lib/Lex/TokenLexer.cpp114
-rw-r--r--clang/lib/Lex/UnicodeCharSets.h305
-rw-r--r--clang/lib/Parse/ParseAST.cpp14
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp13
-rw-r--r--clang/lib/Parse/ParseDecl.cpp414
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp253
-rw-r--r--clang/lib/Parse/ParseExpr.cpp166
-rw-r--r--clang/lib/Parse/ParseExprCXX.cpp198
-rw-r--r--clang/lib/Parse/ParseHLSL.cpp168
-rw-r--r--clang/lib/Parse/ParseInit.cpp4
-rw-r--r--clang/lib/Parse/ParseObjc.cpp91
-rw-r--r--clang/lib/Parse/ParseOpenMP.cpp491
-rw-r--r--clang/lib/Parse/ParsePragma.cpp108
-rw-r--r--clang/lib/Parse/ParseStmt.cpp134
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp55
-rw-r--r--clang/lib/Parse/ParseTentative.cpp183
-rw-r--r--clang/lib/Parse/Parser.cpp161
-rw-r--r--clang/lib/Rewrite/HTMLRewrite.cpp4
-rw-r--r--clang/lib/Sema/AnalysisBasedWarnings.cpp108
-rw-r--r--clang/lib/Sema/CodeCompleteConsumer.cpp2
-rw-r--r--clang/lib/Sema/DeclSpec.cpp25
-rw-r--r--clang/lib/Sema/HLSLExternalSemaSource.cpp425
-rw-r--r--clang/lib/Sema/IdentifierResolver.cpp8
-rw-r--r--clang/lib/Sema/JumpDiagnostics.cpp2
-rw-r--r--clang/lib/Sema/MultiplexExternalSemaSource.cpp24
-rw-r--r--clang/lib/Sema/OpenCLBuiltins.td1
-rw-r--r--clang/lib/Sema/ParsedAttr.cpp4
-rw-r--r--clang/lib/Sema/Scope.cpp9
-rw-r--r--clang/lib/Sema/ScopeInfo.cpp9
-rw-r--r--clang/lib/Sema/Sema.cpp135
-rw-r--r--clang/lib/Sema/SemaAccess.cpp2
-rw-r--r--clang/lib/Sema/SemaAttr.cpp24
-rw-r--r--clang/lib/Sema/SemaAvailability.cpp31
-rw-r--r--clang/lib/Sema/SemaCUDA.cpp18
-rw-r--r--clang/lib/Sema/SemaCXXScopeSpec.cpp7
-rw-r--r--clang/lib/Sema/SemaCast.cpp86
-rw-r--r--clang/lib/Sema/SemaChecking.cpp938
-rw-r--r--clang/lib/Sema/SemaCodeComplete.cpp161
-rw-r--r--clang/lib/Sema/SemaConcept.cpp692
-rw-r--r--clang/lib/Sema/SemaCoroutine.cpp244
-rw-r--r--clang/lib/Sema/SemaDecl.cpp1221
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp454
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp804
-rw-r--r--clang/lib/Sema/SemaDeclObjC.cpp108
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp5
-rw-r--r--clang/lib/Sema/SemaExpr.cpp1133
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp401
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp29
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp114
-rw-r--r--clang/lib/Sema/SemaFixItUtils.cpp6
-rw-r--r--clang/lib/Sema/SemaHLSL.cpp34
-rw-r--r--clang/lib/Sema/SemaInit.cpp402
-rw-r--r--clang/lib/Sema/SemaLambda.cpp222
-rw-r--r--clang/lib/Sema/SemaLookup.cpp119
-rw-r--r--clang/lib/Sema/SemaModule.cpp115
-rw-r--r--clang/lib/Sema/SemaObjCProperty.cpp19
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp919
-rw-r--r--clang/lib/Sema/SemaOverload.cpp606
-rw-r--r--clang/lib/Sema/SemaPseudoObject.cpp10
-rw-r--r--clang/lib/Sema/SemaRISCVVectorLookup.cpp106
-rw-r--r--clang/lib/Sema/SemaStmt.cpp166
-rw-r--r--clang/lib/Sema/SemaStmtAsm.cpp31
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp51
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp1261
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp1170
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp1000
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp406
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp286
-rw-r--r--clang/lib/Sema/SemaType.cpp701
-rw-r--r--clang/lib/Sema/TreeTransform.h729
-rw-r--r--clang/lib/Sema/TypeLocBuilder.cpp29
-rw-r--r--clang/lib/Sema/TypeLocBuilder.h12
-rw-r--r--clang/lib/Sema/UsedDeclVisitor.h17
-rw-r--r--clang/lib/Serialization/ASTCommon.cpp7
-rw-r--r--clang/lib/Serialization/ASTReader.cpp2306
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp386
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp88
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp500
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp181
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp63
-rw-r--r--clang/lib/Serialization/ModuleManager.cpp21
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp9
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp46
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp22
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp211
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp28
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp35
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp11
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp76
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h62
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp72
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp315
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp270
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp38
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp21
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp136
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp21
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp76
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp17
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp38
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp14
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp14
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp16
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp635
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp241
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Taint.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp80
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp17
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp41
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp9
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp49
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h21
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Yaml.h11
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp22
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp61
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporter.cpp72
-rw-r--r--clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp334
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallDescription.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallEvent.cpp83
-rw-r--r--clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Core/CheckerManager.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Core/CoreEngine.cpp15
-rw-r--r--clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/Environment.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp530
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp30
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp171
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp155
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Core/MemRegion.cpp55
-rw-r--r--clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Core/ProgramState.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp304
-rw-r--r--clang/lib/StaticAnalyzer/Core/RegionStore.cpp309
-rw-r--r--clang/lib/StaticAnalyzer/Core/SValBuilder.cpp34
-rw-r--r--clang/lib/StaticAnalyzer/Core/SVals.cpp16
-rw-r--r--clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp389
-rw-r--r--clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp51
-rw-r--r--clang/lib/StaticAnalyzer/Core/Store.cpp15
-rw-r--r--clang/lib/StaticAnalyzer/Core/SymbolManager.cpp20
-rw-r--r--clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp1
-rw-r--r--clang/lib/Support/RISCVVIntrinsicUtils.cpp226
-rw-r--r--clang/lib/Testing/TestAST.cpp3
-rw-r--r--clang/lib/Tooling/ASTDiff/ASTDiff.cpp15
-rw-r--r--clang/lib/Tooling/AllTUsExecution.cpp2
-rw-r--r--clang/lib/Tooling/ArgumentsAdjusters.cpp2
-rw-r--r--clang/lib/Tooling/CommonOptionsParser.cpp8
-rw-r--r--clang/lib/Tooling/Core/Replacement.cpp4
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp5
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp8
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp170
-rw-r--r--clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp267
-rw-r--r--clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp478
-rw-r--r--clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp2
-rw-r--r--clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h2
-rw-r--r--clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp2
-rw-r--r--clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp9
-rw-r--r--clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp119
-rw-r--r--clang/lib/Tooling/Inclusions/HeaderIncludes.cpp34
-rw-r--r--clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp (renamed from clang/lib/Tooling/Inclusions/StandardLibrary.cpp)18
-rw-r--r--clang/lib/Tooling/InterpolatingCompilationDatabase.cpp21
-rw-r--r--clang/lib/Tooling/JSONCompilationDatabase.cpp9
-rw-r--r--clang/lib/Tooling/Refactoring/ASTSelection.cpp19
-rw-r--r--clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp8
-rw-r--r--clang/lib/Tooling/Refactoring/Extract/Extract.cpp3
-rw-r--r--clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp3
-rw-r--r--clang/lib/Tooling/Syntax/BuildTree.cpp8
-rw-r--r--clang/lib/Tooling/Syntax/ComputeReplacements.cpp12
-rw-r--r--clang/lib/Tooling/Syntax/Mutations.cpp1
-rw-r--r--clang/lib/Tooling/Syntax/Tokens.cpp259
-rw-r--r--clang/lib/Tooling/Tooling.cpp19
-rw-r--r--clang/lib/Tooling/Transformer/Parsing.cpp14
-rw-r--r--clang/lib/Tooling/Transformer/RewriteRule.cpp40
-rw-r--r--clang/lib/Tooling/Transformer/SourceCode.cpp92
-rw-r--r--clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp49
-rw-r--r--clang/lib/Tooling/Transformer/Stencil.cpp4
723 files changed, 53226 insertions, 25974 deletions
diff --git a/clang/lib/APINotes/APINotesYAMLCompiler.cpp b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
index 75100fde59b8..ff94f61940bf 100644
--- a/clang/lib/APINotes/APINotesYAMLCompiler.cpp
+++ b/clang/lib/APINotes/APINotesYAMLCompiler.cpp
@@ -17,10 +17,10 @@
#include "clang/APINotes/Types.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Specifiers.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/YAMLTraits.h"
+#include <optional>
#include <vector>
using namespace clang;
using namespace api_notes;
@@ -70,9 +70,9 @@ template <> struct ScalarEnumerationTraits<MethodKind> {
namespace {
struct Param {
unsigned Position;
- Optional<bool> NoEscape = false;
- Optional<NullabilityKind> Nullability;
- Optional<RetainCountConventionKind> RetainCountConvention;
+ std::optional<bool> NoEscape = false;
+ std::optional<NullabilityKind> Nullability;
+ std::optional<RetainCountConventionKind> RetainCountConvention;
StringRef Type;
};
@@ -119,7 +119,7 @@ template <> struct ScalarEnumerationTraits<RetainCountConventionKind> {
template <> struct MappingTraits<Param> {
static void mapping(IO &IO, Param &P) {
IO.mapRequired("Position", P.Position);
- IO.mapOptional("Nullability", P.Nullability, llvm::None);
+ IO.mapOptional("Nullability", P.Nullability, std::nullopt);
IO.mapOptional("RetainCountConvention", P.RetainCountConvention);
IO.mapOptional("NoEscape", P.NoEscape);
IO.mapOptional("Type", P.Type, StringRef(""));
@@ -151,10 +151,10 @@ struct Method {
MethodKind Kind;
ParamsSeq Params;
NullabilitySeq Nullability;
- Optional<NullabilityKind> NullabilityOfRet;
- Optional<RetainCountConventionKind> RetainCountConvention;
+ std::optional<NullabilityKind> NullabilityOfRet;
+ std::optional<RetainCountConventionKind> RetainCountConvention;
AvailabilityItem Availability;
- Optional<bool> SwiftPrivate;
+ std::optional<bool> SwiftPrivate;
StringRef SwiftName;
FactoryAsInitKind FactoryAsInit = FactoryAsInitKind::Infer;
bool DesignatedInit = false;
@@ -183,7 +183,7 @@ template <> struct MappingTraits<Method> {
IO.mapRequired("MethodKind", M.Kind);
IO.mapOptional("Parameters", M.Params);
IO.mapOptional("Nullability", M.Nullability);
- IO.mapOptional("NullabilityOfRet", M.NullabilityOfRet, llvm::None);
+ IO.mapOptional("NullabilityOfRet", M.NullabilityOfRet, std::nullopt);
IO.mapOptional("RetainCountConvention", M.RetainCountConvention);
IO.mapOptional("Availability", M.Availability.Mode,
APIAvailability::Available);
@@ -202,12 +202,12 @@ template <> struct MappingTraits<Method> {
namespace {
struct Property {
StringRef Name;
- llvm::Optional<MethodKind> Kind;
- llvm::Optional<NullabilityKind> Nullability;
+ std::optional<MethodKind> Kind;
+ std::optional<NullabilityKind> Nullability;
AvailabilityItem Availability;
- Optional<bool> SwiftPrivate;
+ std::optional<bool> SwiftPrivate;
StringRef SwiftName;
- Optional<bool> SwiftImportAsAccessors;
+ std::optional<bool> SwiftImportAsAccessors;
StringRef Type;
};
@@ -222,7 +222,7 @@ template <> struct MappingTraits<Property> {
static void mapping(IO &IO, Property &P) {
IO.mapRequired("Name", P.Name);
IO.mapOptional("PropertyKind", P.Kind);
- IO.mapOptional("Nullability", P.Nullability, llvm::None);
+ IO.mapOptional("Nullability", P.Nullability, std::nullopt);
IO.mapOptional("Availability", P.Availability.Mode,
APIAvailability::Available);
IO.mapOptional("AvailabilityMsg", P.Availability.Msg, StringRef(""));
@@ -240,12 +240,12 @@ struct Class {
StringRef Name;
bool AuditedForNullability = false;
AvailabilityItem Availability;
- Optional<bool> SwiftPrivate;
+ std::optional<bool> SwiftPrivate;
StringRef SwiftName;
- Optional<StringRef> SwiftBridge;
- Optional<StringRef> NSErrorDomain;
- Optional<bool> SwiftImportAsNonGeneric;
- Optional<bool> SwiftObjCMembers;
+ std::optional<StringRef> SwiftBridge;
+ std::optional<StringRef> NSErrorDomain;
+ std::optional<bool> SwiftImportAsNonGeneric;
+ std::optional<bool> SwiftObjCMembers;
MethodsSeq Methods;
PropertiesSeq Properties;
};
@@ -282,10 +282,10 @@ struct Function {
StringRef Name;
ParamsSeq Params;
NullabilitySeq Nullability;
- Optional<NullabilityKind> NullabilityOfRet;
- Optional<api_notes::RetainCountConventionKind> RetainCountConvention;
+ std::optional<NullabilityKind> NullabilityOfRet;
+ std::optional<api_notes::RetainCountConventionKind> RetainCountConvention;
AvailabilityItem Availability;
- Optional<bool> SwiftPrivate;
+ std::optional<bool> SwiftPrivate;
StringRef SwiftName;
StringRef Type;
StringRef ResultType;
@@ -303,7 +303,7 @@ template <> struct MappingTraits<Function> {
IO.mapRequired("Name", F.Name);
IO.mapOptional("Parameters", F.Params);
IO.mapOptional("Nullability", F.Nullability);
- IO.mapOptional("NullabilityOfRet", F.NullabilityOfRet, llvm::None);
+ IO.mapOptional("NullabilityOfRet", F.NullabilityOfRet, std::nullopt);
IO.mapOptional("RetainCountConvention", F.RetainCountConvention);
IO.mapOptional("Availability", F.Availability.Mode,
APIAvailability::Available);
@@ -319,9 +319,9 @@ template <> struct MappingTraits<Function> {
namespace {
struct GlobalVariable {
StringRef Name;
- llvm::Optional<NullabilityKind> Nullability;
+ std::optional<NullabilityKind> Nullability;
AvailabilityItem Availability;
- Optional<bool> SwiftPrivate;
+ std::optional<bool> SwiftPrivate;
StringRef SwiftName;
StringRef Type;
};
@@ -336,7 +336,7 @@ namespace yaml {
template <> struct MappingTraits<GlobalVariable> {
static void mapping(IO &IO, GlobalVariable &GV) {
IO.mapRequired("Name", GV.Name);
- IO.mapOptional("Nullability", GV.Nullability, llvm::None);
+ IO.mapOptional("Nullability", GV.Nullability, std::nullopt);
IO.mapOptional("Availability", GV.Availability.Mode,
APIAvailability::Available);
IO.mapOptional("AvailabilityMsg", GV.Availability.Msg, StringRef(""));
@@ -352,7 +352,7 @@ namespace {
struct EnumConstant {
StringRef Name;
AvailabilityItem Availability;
- Optional<bool> SwiftPrivate;
+ std::optional<bool> SwiftPrivate;
StringRef SwiftName;
};
@@ -411,12 +411,12 @@ struct Tag {
StringRef Name;
AvailabilityItem Availability;
StringRef SwiftName;
- Optional<bool> SwiftPrivate;
- Optional<StringRef> SwiftBridge;
- Optional<StringRef> NSErrorDomain;
- Optional<EnumExtensibilityKind> EnumExtensibility;
- Optional<bool> FlagEnum;
- Optional<EnumConvenienceAliasKind> EnumConvenienceKind;
+ std::optional<bool> SwiftPrivate;
+ std::optional<StringRef> SwiftBridge;
+ std::optional<StringRef> NSErrorDomain;
+ std::optional<EnumExtensibilityKind> EnumExtensibility;
+ std::optional<bool> FlagEnum;
+ std::optional<EnumConvenienceAliasKind> EnumConvenienceKind;
};
typedef std::vector<Tag> TagsSeq;
@@ -457,10 +457,10 @@ struct Typedef {
StringRef Name;
AvailabilityItem Availability;
StringRef SwiftName;
- Optional<bool> SwiftPrivate;
- Optional<StringRef> SwiftBridge;
- Optional<StringRef> NSErrorDomain;
- Optional<SwiftNewTypeKind> SwiftType;
+ std::optional<bool> SwiftPrivate;
+ std::optional<StringRef> SwiftBridge;
+ std::optional<StringRef> NSErrorDomain;
+ std::optional<SwiftNewTypeKind> SwiftType;
};
typedef std::vector<Typedef> TypedefsSeq;
@@ -549,7 +549,7 @@ struct Module {
TopLevelItems TopLevel;
VersionedSeq SwiftVersions;
- llvm::Optional<bool> SwiftInferImportAsMember = {llvm::None};
+ std::optional<bool> SwiftInferImportAsMember;
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void dump() /*const*/;
diff --git a/clang/lib/ARCMigrate/ARCMTActions.cpp b/clang/lib/ARCMigrate/ARCMTActions.cpp
index d72f53806e37..0805d90d25aa 100644
--- a/clang/lib/ARCMigrate/ARCMTActions.cpp
+++ b/clang/lib/ARCMigrate/ARCMTActions.cpp
@@ -39,7 +39,7 @@ ModifyAction::ModifyAction(std::unique_ptr<FrontendAction> WrappedAction)
bool MigrateAction::BeginInvocation(CompilerInstance &CI) {
if (arcmt::migrateWithTemporaryFiles(
CI.getInvocation(), getCurrentInput(), CI.getPCHContainerOperations(),
- CI.getDiagnostics().getClient(), MigrateDir, EmitPremigrationARCErros,
+ CI.getDiagnostics().getClient(), MigrateDir, EmitPremigrationARCErrors,
PlistOut))
return false; // errors, stop the action.
@@ -53,7 +53,7 @@ MigrateAction::MigrateAction(std::unique_ptr<FrontendAction> WrappedAction,
StringRef plistOut,
bool emitPremigrationARCErrors)
: WrapperFrontendAction(std::move(WrappedAction)), MigrateDir(migrateDir),
- PlistOut(plistOut), EmitPremigrationARCErros(emitPremigrationARCErrors) {
+ PlistOut(plistOut), EmitPremigrationARCErrors(emitPremigrationARCErrors) {
if (MigrateDir.empty())
MigrateDir = "."; // user current directory if none is given.
}
diff --git a/clang/lib/ARCMigrate/Internals.h b/clang/lib/ARCMigrate/Internals.h
index 8b482738cc89..d790c7c02189 100644
--- a/clang/lib/ARCMigrate/Internals.h
+++ b/clang/lib/ARCMigrate/Internals.h
@@ -13,8 +13,8 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/MigratorOptions.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/Optional.h"
#include <list>
+#include <optional>
namespace clang {
class ASTContext;
@@ -74,7 +74,7 @@ public:
bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range);
bool clearAllDiagnostics(SourceRange range) {
- return clearDiagnostic(None, range);
+ return clearDiagnostic(std::nullopt, range);
}
bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) {
unsigned IDs[] = { ID1, ID2 };
@@ -152,7 +152,7 @@ public:
TransformActions &TA;
const CapturedDiagList &CapturedDiags;
std::vector<SourceLocation> &ARCMTMacroLocs;
- Optional<bool> EnableCFBridgeFns;
+ std::optional<bool> EnableCFBridgeFns;
MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode, Sema &sema,
TransformActions &TA, const CapturedDiagList &capturedDiags,
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp
index 3dfa9a0218a7..ce1decd3ba3e 100644
--- a/clang/lib/ARCMigrate/ObjCMT.cpp
+++ b/clang/lib/ARCMigrate/ObjCMT.cpp
@@ -156,7 +156,7 @@ protected:
return AllowListFilenames.find(llvm::sys::path::filename(Path)) !=
AllowListFilenames.end();
}
- bool canModifyFile(Optional<FileEntryRef> FE) {
+ bool canModifyFile(OptionalFileEntryRef FE) {
if (!FE)
return false;
return canModifyFile(FE->getName());
@@ -202,7 +202,7 @@ ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile));
Consumers.push_back(std::make_unique<ObjCMigrateASTConsumer>(
MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec,
- CompInst->getPreprocessor(), false, None));
+ CompInst->getPreprocessor(), false, std::nullopt));
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}
@@ -505,7 +505,7 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
if (LParenAdded)
PropertyString += ')';
QualType RT = Getter->getReturnType();
- if (!isa<TypedefType>(RT)) {
+ if (!RT->getAs<TypedefType>()) {
// strip off any ARC lifetime qualifier.
QualType CanResultTy = Context.getCanonicalType(RT);
if (CanResultTy.getQualifiers().hasObjCLifetime()) {
@@ -792,7 +792,7 @@ static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
bool PowerOfTwo = true;
bool AllHexdecimalEnumerator = true;
uint64_t MaxPowerOfTwoVal = 0;
- for (auto Enumerator : EnumDcl->enumerators()) {
+ for (auto *Enumerator : EnumDcl->enumerators()) {
const Expr *InitExpr = Enumerator->getInitExpr();
if (!InitExpr) {
PowerOfTwo = false;
@@ -1053,7 +1053,7 @@ static bool TypeIsInnerPointer(QualType T) {
// Also, typedef-of-pointer-to-incomplete-struct is something that we assume
// is not an innter pointer type.
QualType OrigT = T;
- while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr()))
+ while (const auto *TD = T->getAs<TypedefType>())
T = TD->getDecl()->getUnderlyingType();
if (OrigT == T || !T->isPointerType())
return true;
@@ -1356,9 +1356,6 @@ static bool IsVoidStarType(QualType Ty) {
if (!Ty->isPointerType())
return false;
- while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr()))
- Ty = TD->getDecl()->getUnderlyingType();
-
// Is the type void*?
const PointerType* PT = Ty->castAs<PointerType>();
if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
@@ -1961,7 +1958,8 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
FileID FID = I->first;
RewriteBuffer &buf = I->second;
- Optional<FileEntryRef> file = Ctx.getSourceManager().getFileEntryRefForID(FID);
+ OptionalFileEntryRef file =
+ Ctx.getSourceManager().getFileEntryRefForID(FID);
assert(file);
SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
@@ -2031,7 +2029,7 @@ MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
namespace {
struct EditEntry {
- Optional<FileEntryRef> File;
+ OptionalFileEntryRef File;
unsigned Offset = 0;
unsigned RemoveLen = 0;
std::string Text;
diff --git a/clang/lib/ARCMigrate/TransGCAttrs.cpp b/clang/lib/ARCMigrate/TransGCAttrs.cpp
index 99a61e0842a7..28d1db7f4376 100644
--- a/clang/lib/ARCMigrate/TransGCAttrs.cpp
+++ b/clang/lib/ARCMigrate/TransGCAttrs.cpp
@@ -46,7 +46,7 @@ public:
if (!D || D->isImplicit())
return true;
- SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
+ SaveAndRestore Save(FullyMigratable, isMigratable(D));
if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
lookForAttribute(PropD, PropD->getTypeSourceInfo());
@@ -158,7 +158,7 @@ public:
if (!D)
return false;
- for (auto I : D->redecls())
+ for (auto *I : D->redecls())
if (!isInMainFile(I->getLocation()))
return false;
diff --git a/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index b76fc65574dd..baa503d8a39d 100644
--- a/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -78,7 +78,7 @@ public:
}
}
// Pass through.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMF_retain:
case OMF_release:
if (E->getReceiverKind() == ObjCMessageExpr::Instance)
diff --git a/clang/lib/ARCMigrate/TransformActions.cpp b/clang/lib/ARCMigrate/TransformActions.cpp
index 2c48e479dce8..bd5c79356867 100644
--- a/clang/lib/ARCMigrate/TransformActions.cpp
+++ b/clang/lib/ARCMigrate/TransformActions.cpp
@@ -540,7 +540,7 @@ void TransformActionsImpl::addRemoval(CharSourceRange range) {
return;
case Range_Contains:
RI->End = newRange.End;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Range_ExtendsBegin:
newRange.End = RI->End;
Removals.erase(RI);
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index a22031142c7c..5b0a5e256e41 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -156,10 +156,10 @@ void APValue::LValuePathEntry::Profile(llvm::FoldingSetNodeID &ID) const {
APValue::LValuePathSerializationHelper::LValuePathSerializationHelper(
ArrayRef<LValuePathEntry> Path, QualType ElemTy)
- : ElemTy((const void *)ElemTy.getTypePtrOrNull()), Path(Path) {}
+ : Ty((const void *)ElemTy.getTypePtrOrNull()), Path(Path) {}
QualType APValue::LValuePathSerializationHelper::getType() {
- return QualType::getFromOpaquePtr(ElemTy);
+ return QualType::getFromOpaquePtr(Ty);
}
namespace {
@@ -637,10 +637,10 @@ static bool TryPrintAsStringLiteral(raw_ostream &Out,
return false;
// Nothing we can do about a sequence that is not null-terminated
- if (!Inits.back().getInt().isZero())
+ if (!Inits.back().isInt() || !Inits.back().getInt().isZero())
return false;
- else
- Inits = Inits.drop_back();
+
+ Inits = Inits.drop_back();
llvm::SmallString<40> Buf;
Buf.push_back('"');
@@ -655,6 +655,8 @@ static bool TryPrintAsStringLiteral(raw_ostream &Out,
}
for (auto &Val : Inits) {
+ if (!Val.isInt())
+ return false;
int64_t Char64 = Val.getInt().getExtValue();
if (!isASCII(Char64))
return false; // Bye bye, see you in integers.
@@ -871,7 +873,7 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy,
Out << "...}";
return;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
getArrayInitializedElt(I).printPretty(Out, Policy, ElemTy, Ctx);
}
@@ -982,7 +984,7 @@ bool APValue::hasLValuePath() const {
ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
assert(isLValue() && hasLValuePath() && "Invalid accessor");
const LV &LVal = *((const LV *)(const char *)&Data);
- return llvm::makeArrayRef(LVal.getPath(), LVal.PathLength);
+ return llvm::ArrayRef(LVal.getPath(), LVal.PathLength);
}
unsigned APValue::getLValueCallIndex() const {
@@ -1060,7 +1062,7 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
assert(isMemberPointer() && "Invalid accessor");
const MemberPointerData &MPD =
*((const MemberPointerData *)(const char *)&Data);
- return llvm::makeArrayRef(MPD.getPath(), MPD.PathLength);
+ return llvm::ArrayRef(MPD.getPath(), MPD.PathLength);
}
void APValue::MakeLValue() {
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index 18582782888c..8f2d94572184 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -19,33 +19,49 @@
#include "llvm/ADT/FoldingSet.h"
using namespace clang;
-ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C,
- const ConstraintSatisfaction &Satisfaction):
- NumRecords{Satisfaction.Details.size()},
- IsSatisfied{Satisfaction.IsSatisfied} {
- for (unsigned I = 0; I < NumRecords; ++I) {
- auto &Detail = Satisfaction.Details[I];
- if (Detail.second.is<Expr *>())
- new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
- UnsatisfiedConstraintRecord{Detail.first,
- UnsatisfiedConstraintRecord::second_type(
- Detail.second.get<Expr *>())};
- else {
- auto &SubstitutionDiagnostic =
- *Detail.second.get<std::pair<SourceLocation, StringRef> *>();
- unsigned MessageSize = SubstitutionDiagnostic.second.size();
- char *Mem = new (C) char[MessageSize];
- memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize);
- auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
- SubstitutionDiagnostic.first, StringRef(Mem, MessageSize));
- new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
- UnsatisfiedConstraintRecord{Detail.first,
- UnsatisfiedConstraintRecord::second_type(
- NewSubstDiag)};
- }
+namespace {
+void CreatUnsatisfiedConstraintRecord(
+ const ASTContext &C, const UnsatisfiedConstraintRecord &Detail,
+ UnsatisfiedConstraintRecord *TrailingObject) {
+ if (Detail.second.is<Expr *>())
+ new (TrailingObject) UnsatisfiedConstraintRecord{
+ Detail.first,
+ UnsatisfiedConstraintRecord::second_type(Detail.second.get<Expr *>())};
+ else {
+ auto &SubstitutionDiagnostic =
+ *Detail.second.get<std::pair<SourceLocation, StringRef> *>();
+ unsigned MessageSize = SubstitutionDiagnostic.second.size();
+ char *Mem = new (C) char[MessageSize];
+ memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize);
+ auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
+ SubstitutionDiagnostic.first, StringRef(Mem, MessageSize));
+ new (TrailingObject) UnsatisfiedConstraintRecord{
+ Detail.first, UnsatisfiedConstraintRecord::second_type(NewSubstDiag)};
}
}
+} // namespace
+ASTConstraintSatisfaction::ASTConstraintSatisfaction(
+ const ASTContext &C, const ConstraintSatisfaction &Satisfaction)
+ : NumRecords{Satisfaction.Details.size()},
+ IsSatisfied{Satisfaction.IsSatisfied}, ContainsErrors{
+ Satisfaction.ContainsErrors} {
+ for (unsigned I = 0; I < NumRecords; ++I)
+ CreatUnsatisfiedConstraintRecord(
+ C, Satisfaction.Details[I],
+ getTrailingObjects<UnsatisfiedConstraintRecord>() + I);
+}
+
+ASTConstraintSatisfaction::ASTConstraintSatisfaction(
+ const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction)
+ : NumRecords{Satisfaction.NumRecords},
+ IsSatisfied{Satisfaction.IsSatisfied},
+ ContainsErrors{Satisfaction.ContainsErrors} {
+ for (unsigned I = 0; I < NumRecords; ++I)
+ CreatUnsatisfiedConstraintRecord(
+ C, *(Satisfaction.begin() + I),
+ getTrailingObjects<UnsatisfiedConstraintRecord>() + I);
+}
ASTConstraintSatisfaction *
ASTConstraintSatisfaction::Create(const ASTContext &C,
@@ -57,6 +73,14 @@ ASTConstraintSatisfaction::Create(const ASTContext &C,
return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
}
+ASTConstraintSatisfaction *ASTConstraintSatisfaction::Rebuild(
+ const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction) {
+ std::size_t size =
+ totalSizeToAlloc<UnsatisfiedConstraintRecord>(Satisfaction.NumRecords);
+ void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));
+ return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
+}
+
void ConstraintSatisfaction::Profile(
llvm::FoldingSetNodeID &ID, const ASTContext &C,
const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cfd7bf604542..2884fe660422 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -71,8 +71,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -94,6 +92,7 @@
#include <cstdlib>
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -298,6 +297,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return nullptr;
const FileID File = SourceMgr.getDecomposedLoc(DeclLoc).first;
+ if (!File.isValid()) {
+ return nullptr;
+ }
const auto CommentsInThisFile = Comments.getCommentsInFile(File);
if (!CommentsInThisFile || CommentsInThisFile->empty())
return nullptr;
@@ -693,7 +695,11 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
ID.AddInteger(1);
ID.AddBoolean(NTTP->isParameterPack());
+ const Expr *TC = NTTP->getPlaceholderTypeConstraint();
+ ID.AddBoolean(TC != nullptr);
ID.AddPointer(NTTP->getType().getCanonicalType().getAsOpaquePtr());
+ if (TC)
+ TC->Profile(ID, C, /*Canonical=*/true);
if (NTTP->isExpandedParameterPack()) {
ID.AddBoolean(true);
ID.AddInteger(NTTP->getNumExpansionTypes());
@@ -754,15 +760,19 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
NewConverted.push_back(ConstrainedType);
llvm::append_range(NewConverted, OldConverted.drop_front(1));
}
+ auto *CSD = ImplicitConceptSpecializationDecl::Create(
+ C, CSE->getNamedConcept()->getDeclContext(),
+ CSE->getNamedConcept()->getLocation(), NewConverted);
+
Expr *NewIDC = ConceptSpecializationExpr::Create(
- C, CSE->getNamedConcept(), NewConverted, nullptr,
- CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack());
+ C, CSE->getNamedConcept(), CSD, nullptr, CSE->isInstantiationDependent(),
+ CSE->containsUnexpandedParameterPack());
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
NewIDC = new (C) CXXFoldExpr(
- OrigFold->getType(), /*Callee*/nullptr, SourceLocation(), NewIDC,
+ OrigFold->getType(), /*Callee*/ nullptr, SourceLocation(), NewIDC,
BinaryOperatorKind::BO_LAnd, SourceLocation(), /*RHS=*/nullptr,
- SourceLocation(), /*NumExpansions=*/None);
+ SourceLocation(), /*NumExpansions=*/std::nullopt);
return NewIDC;
}
@@ -786,23 +796,18 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
PEnd = Params->end();
P != PEnd; ++P) {
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
- TemplateTypeParmDecl *NewTTP = TemplateTypeParmDecl::Create(*this,
- getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+ TemplateTypeParmDecl *NewTTP = TemplateTypeParmDecl::Create(
+ *this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
TTP->getDepth(), TTP->getIndex(), nullptr, false,
TTP->isParameterPack(), TTP->hasTypeConstraint(),
- TTP->isExpandedParameterPack() ?
- llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
+ TTP->isExpandedParameterPack()
+ ? std::optional<unsigned>(TTP->getNumExpansionParameters())
+ : std::nullopt);
if (const auto *TC = TTP->getTypeConstraint()) {
QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0);
Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint(
*this, TC->getImmediatelyDeclaredConstraint(),
ParamAsArgument);
- TemplateArgumentListInfo CanonArgsAsWritten;
- if (auto *Args = TC->getTemplateArgsAsWritten())
- for (const auto &ArgLoc : Args->arguments())
- CanonArgsAsWritten.addArgument(
- TemplateArgumentLoc(ArgLoc.getArgument(),
- TemplateArgumentLocInfo()));
NewTTP->setTypeConstraint(
NestedNameSpecifierLoc(),
DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),
@@ -924,38 +929,6 @@ ParentMapContext &ASTContext::getParentMapContext() {
return *ParentMapCtx.get();
}
-static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
- const LangOptions &LOpts) {
- if (LOpts.FakeAddressSpaceMap) {
- // The fake address space map must have a distinct entry for each
- // language-specific address space.
- static const unsigned FakeAddrSpaceMap[] = {
- 0, // Default
- 1, // opencl_global
- 3, // opencl_local
- 2, // opencl_constant
- 0, // opencl_private
- 4, // opencl_generic
- 5, // opencl_global_device
- 6, // opencl_global_host
- 7, // cuda_device
- 8, // cuda_constant
- 9, // cuda_shared
- 1, // sycl_global
- 5, // sycl_global_device
- 6, // sycl_global_host
- 3, // sycl_local
- 0, // sycl_private
- 10, // ptr32_sptr
- 11, // ptr32_uptr
- 12 // ptr64
- };
- return &FakeAddrSpaceMap;
- } else {
- return &T.getAddressSpaceMap();
- }
-}
-
static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
const LangOptions &LangOpts) {
switch (LangOpts.getAddressSpaceMapMangling()) {
@@ -1133,7 +1106,7 @@ ASTContext::getModulesWithMergedDefinition(const NamedDecl *Def) {
auto MergedIt =
MergedDefModules.find(cast<NamedDecl>(Def->getCanonicalDecl()));
if (MergedIt == MergedDefModules.end())
- return None;
+ return std::nullopt;
return MergedIt->second;
}
@@ -1191,7 +1164,7 @@ void ASTContext::addLazyModuleInitializers(Module *M, ArrayRef<uint32_t> IDs) {
ArrayRef<Decl *> ASTContext::getModuleInitializers(Module *M) {
auto It = ModuleInitializers.find(M);
if (It == ModuleInitializers.end())
- return None;
+ return std::nullopt;
auto *Inits = It->second;
Inits->resolve(*this);
@@ -1286,7 +1259,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
this->AuxTarget = AuxTarget;
ABI.reset(createCXXABI(Target));
- AddrSpaceMap = getAddressSpaceMap(Target, LangOpts);
AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts);
// C99 6.2.5p19.
@@ -1873,7 +1845,7 @@ static getConstantArrayInfoInChars(const ASTContext &Context,
uint64_t Width = EltInfo.Width.getQuantity() * Size;
unsigned Align = EltInfo.Align.getQuantity();
if (!Context.getTargetInfo().getCXXABI().isMicrosoft() ||
- Context.getTargetInfo().getPointerWidth(0) == 64)
+ Context.getTargetInfo().getPointerWidth(LangAS::Default) == 64)
Width = llvm::alignTo(Width, Align);
return TypeInfoChars(CharUnits::fromQuantity(Width),
CharUnits::fromQuantity(Align),
@@ -1892,6 +1864,44 @@ TypeInfoChars ASTContext::getTypeInfoInChars(QualType T) const {
return getTypeInfoInChars(T.getTypePtr());
}
+bool ASTContext::isPromotableIntegerType(QualType T) const {
+ // HLSL doesn't promote all small integer types to int, it
+ // just uses the rank-based promotion rules for all types.
+ if (getLangOpts().HLSL)
+ return false;
+
+ if (const auto *BT = T->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Bool:
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char8:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ return true;
+ default:
+ return false;
+ }
+
+ // Enumerated types are promotable to their compatible integer types
+ // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2).
+ if (const auto *ET = T->getAs<EnumType>()) {
+ if (T->isDependentType() || ET->getDecl()->getPromotionType().isNull() ||
+ ET->getDecl()->isScoped())
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
bool ASTContext::isAlignmentRequired(const Type *T) const {
return getTypeInfo(T).AlignRequirement != AlignRequirementKind::None;
}
@@ -1946,7 +1956,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
uint64_t Width = 0;
unsigned Align = 8;
AlignRequirementKind AlignRequirement = AlignRequirementKind::None;
- unsigned AS = 0;
+ LangAS AS = LangAS::Default;
switch (T->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@@ -1981,7 +1991,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Align = EltInfo.Align;
AlignRequirement = EltInfo.AlignRequirement;
if (!getTargetInfo().getCXXABI().isMicrosoft() ||
- getTargetInfo().getPointerWidth(0) == 64)
+ getTargetInfo().getPointerWidth(LangAS::Default) == 64)
Width = llvm::alignTo(Width, Align);
break;
}
@@ -2082,7 +2092,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case BuiltinType::Int128:
case BuiltinType::UInt128:
Width = 128;
- Align = 128; // int128_t is 128-bit aligned on all targets.
+ Align = Target->getInt128Align();
break;
case BuiltinType::ShortAccum:
case BuiltinType::UShortAccum:
@@ -2181,14 +2191,15 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
}
break;
case BuiltinType::NullPtr:
- Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t)
- Align = Target->getPointerAlign(0); // == sizeof(void*)
+ // C++ 3.9.1p11: sizeof(nullptr_t) == sizeof(void*)
+ Width = Target->getPointerWidth(LangAS::Default);
+ Align = Target->getPointerAlign(LangAS::Default);
break;
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
- Width = Target->getPointerWidth(0);
- Align = Target->getPointerAlign(0);
+ Width = Target->getPointerWidth(LangAS::Default);
+ Align = Target->getPointerAlign(LangAS::Default);
break;
case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
@@ -2201,8 +2212,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
- AS = getTargetAddressSpace(
- Target->getOpenCLTypeAddrSpace(getOpenCLTypeKind(T)));
+ AS = Target->getOpenCLTypeAddrSpace(getOpenCLTypeKind(T));
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
@@ -2247,11 +2257,11 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
}
break;
case Type::ObjCObjectPointer:
- Width = Target->getPointerWidth(0);
- Align = Target->getPointerAlign(0);
+ Width = Target->getPointerWidth(LangAS::Default);
+ Align = Target->getPointerAlign(LangAS::Default);
break;
case Type::BlockPointer:
- AS = getTargetAddressSpace(cast<BlockPointerType>(T)->getPointeeType());
+ AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace();
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
@@ -2259,12 +2269,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::RValueReference:
// alignof and sizeof should never enter this code path here, so we go
// the pointer route.
- AS = getTargetAddressSpace(cast<ReferenceType>(T)->getPointeeType());
+ AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace();
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
case Type::Pointer:
- AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType());
+ AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
@@ -2367,12 +2377,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
return getTypeInfo(cast<UsingType>(T)->desugar().getTypePtr());
case Type::Typedef: {
- const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
- TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
+ const auto *TT = cast<TypedefType>(T);
+ TypeInfo Info = getTypeInfo(TT->desugar().getTypePtr());
// If the typedef has an aligned attribute on it, it overrides any computed
// alignment we have. This violates the GCC documentation (which says that
// attribute(aligned) can only round up) but matches its implementation.
- if (unsigned AttrAlign = Typedef->getMaxAlignment()) {
+ if (unsigned AttrAlign = TT->getDecl()->getMaxAlignment()) {
Align = AttrAlign;
AlignRequirement = AlignRequirementKind::RequiredByTypedef;
} else {
@@ -2421,8 +2431,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
break;
case Type::Pipe:
- Width = Target->getPointerWidth(getTargetAddressSpace(LangAS::opencl_global));
- Align = Target->getPointerAlign(getTargetAddressSpace(LangAS::opencl_global));
+ Width = Target->getPointerWidth(LangAS::opencl_global);
+ Align = Target->getPointerAlign(LangAS::opencl_global);
break;
}
@@ -2485,7 +2495,7 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const {
}
/// getTypeUnadjustedAlignInChars - Return the ABI-specified alignment of a
-/// type, in characters, before alignment adustments. This method does
+/// type, in characters, before alignment adjustments. This method does
/// not work on incomplete types.
CharUnits ASTContext::getTypeUnadjustedAlignInChars(QualType T) const {
return toCharUnitsFromBits(getTypeUnadjustedAlign(T));
@@ -2682,11 +2692,11 @@ static int64_t getSubobjectOffset(const CXXRecordDecl *RD,
return Context.toBits(Layout.getBaseClassOffset(RD));
}
-static llvm::Optional<int64_t>
+static std::optional<int64_t>
structHasUniqueObjectRepresentations(const ASTContext &Context,
const RecordDecl *RD);
-static llvm::Optional<int64_t>
+static std::optional<int64_t>
getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) {
if (Field->getType()->isRecordType()) {
const RecordDecl *RD = Field->getType()->getAsRecordDecl();
@@ -2699,7 +2709,7 @@ getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) {
bool IsBitIntType = Field->getType()->isBitIntType();
if (!Field->getType()->isReferenceType() && !IsBitIntType &&
!Context.hasUniqueObjectRepresentations(Field->getType()))
- return llvm::None;
+ return std::nullopt;
int64_t FieldSizeInBits =
Context.toBits(Context.getTypeSizeInChars(Field->getType()));
@@ -2708,43 +2718,43 @@ getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) {
if (IsBitIntType) {
if ((unsigned)BitfieldSize >
cast<BitIntType>(Field->getType())->getNumBits())
- return llvm::None;
+ return std::nullopt;
} else if (BitfieldSize > FieldSizeInBits) {
- return llvm::None;
+ return std::nullopt;
}
FieldSizeInBits = BitfieldSize;
} else if (IsBitIntType &&
!Context.hasUniqueObjectRepresentations(Field->getType())) {
- return llvm::None;
+ return std::nullopt;
}
return FieldSizeInBits;
}
-static llvm::Optional<int64_t>
+static std::optional<int64_t>
getSubobjectSizeInBits(const CXXRecordDecl *RD, const ASTContext &Context) {
return structHasUniqueObjectRepresentations(Context, RD);
}
template <typename RangeT>
-static llvm::Optional<int64_t> structSubobjectsHaveUniqueObjectRepresentations(
+static std::optional<int64_t> structSubobjectsHaveUniqueObjectRepresentations(
const RangeT &Subobjects, int64_t CurOffsetInBits,
const ASTContext &Context, const clang::ASTRecordLayout &Layout) {
for (const auto *Subobject : Subobjects) {
- llvm::Optional<int64_t> SizeInBits =
+ std::optional<int64_t> SizeInBits =
getSubobjectSizeInBits(Subobject, Context);
if (!SizeInBits)
- return llvm::None;
+ return std::nullopt;
if (*SizeInBits != 0) {
int64_t Offset = getSubobjectOffset(Subobject, Context, Layout);
if (Offset != CurOffsetInBits)
- return llvm::None;
+ return std::nullopt;
CurOffsetInBits += *SizeInBits;
}
}
return CurOffsetInBits;
}
-static llvm::Optional<int64_t>
+static std::optional<int64_t>
structHasUniqueObjectRepresentations(const ASTContext &Context,
const RecordDecl *RD) {
assert(!RD->isUnion() && "Must be struct/class type");
@@ -2753,7 +2763,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
int64_t CurOffsetInBits = 0;
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
if (ClassDecl->isDynamicClass())
- return llvm::None;
+ return std::nullopt;
SmallVector<CXXRecordDecl *, 4> Bases;
for (const auto &Base : ClassDecl->bases()) {
@@ -2766,19 +2776,19 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R);
});
- llvm::Optional<int64_t> OffsetAfterBases =
+ std::optional<int64_t> OffsetAfterBases =
structSubobjectsHaveUniqueObjectRepresentations(Bases, CurOffsetInBits,
Context, Layout);
if (!OffsetAfterBases)
- return llvm::None;
+ return std::nullopt;
CurOffsetInBits = *OffsetAfterBases;
}
- llvm::Optional<int64_t> OffsetAfterFields =
+ std::optional<int64_t> OffsetAfterFields =
structSubobjectsHaveUniqueObjectRepresentations(
RD->fields(), CurOffsetInBits, Context, Layout);
if (!OffsetAfterFields)
- return llvm::None;
+ return std::nullopt;
CurOffsetInBits = *OffsetAfterFields;
return CurOffsetInBits;
@@ -2839,7 +2849,7 @@ bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const {
if (Record->isUnion())
return unionHasUniqueObjectRepresentations(*this, Record);
- Optional<int64_t> StructSize =
+ std::optional<int64_t> StructSize =
structHasUniqueObjectRepresentations(*this, Record);
return StructSize && *StructSize == static_cast<int64_t>(getTypeSize(Ty));
@@ -3001,6 +3011,18 @@ ASTContext::getASTObjCImplementationLayout(
return getObjCLayout(D->getClassInterface(), D);
}
+static auto getCanonicalTemplateArguments(const ASTContext &C,
+ ArrayRef<TemplateArgument> Args,
+ bool &AnyNonCanonArgs) {
+ SmallVector<TemplateArgument, 16> CanonArgs(Args);
+ for (auto &Arg : CanonArgs) {
+ TemplateArgument OrigArg = Arg;
+ Arg = C.getCanonicalTemplateArgument(Arg);
+ AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg);
+ }
+ return CanonArgs;
+}
+
//===----------------------------------------------------------------------===//
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
@@ -3204,9 +3226,9 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) {
if (const auto *Proto = T->getAs<FunctionProtoType>()) {
QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
- SmallVector<QualType, 16> Args(Proto->param_types());
+ SmallVector<QualType, 16> Args(Proto->param_types().size());
for (unsigned i = 0, n = Args.size(); i != n; ++i)
- Args[i] = removePtrSizeAddrSpace(Args[i]);
+ Args[i] = removePtrSizeAddrSpace(Proto->param_types()[i]);
return getFunctionType(RetTy, Args, Proto->getExtProtoInfo());
}
@@ -3329,6 +3351,26 @@ QualType ASTContext::getAdjustedType(QualType Orig, QualType New) const {
return QualType(AT, 0);
}
+QualType ASTContext::getDecayedType(QualType Orig, QualType Decayed) const {
+ llvm::FoldingSetNodeID ID;
+ AdjustedType::Profile(ID, Orig, Decayed);
+ void *InsertPos = nullptr;
+ AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (AT)
+ return QualType(AT, 0);
+
+ QualType Canonical = getCanonicalType(Decayed);
+
+ // Get the new insert position for the node we care about.
+ AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!AT && "Shouldn't be in the map!");
+
+ AT = new (*this, TypeAlignment) DecayedType(Orig, Decayed, Canonical);
+ Types.push_back(AT);
+ AdjustedTypes.InsertNode(AT, InsertPos);
+ return QualType(AT, 0);
+}
+
QualType ASTContext::getDecayedType(QualType T) const {
assert((T->isArrayType() || T->isFunctionType()) && "T does not decay");
@@ -3349,23 +3391,7 @@ QualType ASTContext::getDecayedType(QualType T) const {
if (T->isFunctionType())
Decayed = getPointerType(T);
- llvm::FoldingSetNodeID ID;
- AdjustedType::Profile(ID, T, Decayed);
- void *InsertPos = nullptr;
- AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (AT)
- return QualType(AT, 0);
-
- QualType Canonical = getCanonicalType(Decayed);
-
- // Get the new insert position for the node we care about.
- AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!AT && "Shouldn't be in the map!");
-
- AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
- Types.push_back(AT);
- AdjustedTypes.InsertNode(AT, InsertPos);
- return QualType(AT, 0);
+ return getDecayedType(T, Decayed);
}
/// getBlockPointerType - Return the uniqued reference to the type for
@@ -3541,6 +3567,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// is instantiation-dependent, this won't be a canonical type either, so fill
// in the canonical type field.
QualType Canon;
+ // FIXME: Check below should look for qualifiers behind sugar.
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || SizeExpr) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize, nullptr,
@@ -3716,6 +3743,7 @@ QualType ASTContext::getVariableArrayType(QualType EltTy,
QualType Canon;
// Be sure to pull qualifiers off the element type.
+ // FIXME: Check below should look for qualifiers behind sugar.
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
Canon = getVariableArrayType(QualType(canonSplit.Ty, 0), NumElts, ASM,
@@ -3818,6 +3846,7 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType,
// qualifiers off the element type.
QualType canon;
+ // FIXME: Check below should look for qualifiers behind sugar.
if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(elementType).split();
canon = getIncompleteArrayType(QualType(canonSplit.Ty, 0),
@@ -4009,7 +4038,11 @@ QualType ASTContext::getScalableVectorType(QualType EltTy,
/// the specified element type and size. VectorType must be a built-in type.
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
VectorType::VectorKind VecKind) const {
- assert(vecType->isBuiltinType());
+ assert(vecType->isBuiltinType() ||
+ (vecType->isBitIntType() &&
+ // Only support _BitInt elements with byte-sized power of 2 NumBits.
+ llvm::isPowerOf2_32(vecType->getAs<BitIntType>()->getNumBits()) &&
+ vecType->getAs<BitIntType>()->getNumBits() >= 8));
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
@@ -4077,9 +4110,13 @@ ASTContext::getDependentVectorType(QualType VecType, Expr *SizeExpr,
/// getExtVectorType - Return the unique reference to an extended vector type of
/// the specified element type and size. VectorType must be a built-in type.
-QualType
-ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const {
- assert(vecType->isBuiltinType() || vecType->isDependentType());
+QualType ASTContext::getExtVectorType(QualType vecType,
+ unsigned NumElts) const {
+ assert(vecType->isBuiltinType() || vecType->isDependentType() ||
+ (vecType->isBitIntType() &&
+ // Only support _BitInt elements with byte-sized power of 2 NumBits.
+ llvm::isPowerOf2_32(vecType->getAs<BitIntType>()->getNumBits()) &&
+ vecType->getAs<BitIntType>()->getNumBits() >= 8));
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
@@ -4420,7 +4457,7 @@ QualType ASTContext::getFunctionTypeInternal(
case EST_Unparsed: case EST_Unevaluated: case EST_Uninstantiated:
// We don't know yet. It shouldn't matter what we pick here; no-one
// should ever look at this.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case EST_None: case EST_MSAny: case EST_NoexceptFalse:
CanonicalEPI.ExceptionSpec.Type = EST_None;
break;
@@ -4626,34 +4663,60 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
/// specified typedef name decl.
QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
QualType Underlying) const {
- if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+ if (!Decl->TypeForDecl) {
+ if (Underlying.isNull())
+ Underlying = Decl->getUnderlyingType();
+ auto *NewType = new (*this, TypeAlignment) TypedefType(
+ Type::Typedef, Decl, QualType(), getCanonicalType(Underlying));
+ Decl->TypeForDecl = NewType;
+ Types.push_back(NewType);
+ return QualType(NewType, 0);
+ }
+ if (Underlying.isNull() || Decl->getUnderlyingType() == Underlying)
+ return QualType(Decl->TypeForDecl, 0);
+ assert(hasSameType(Decl->getUnderlyingType(), Underlying));
- if (Underlying.isNull())
- Underlying = Decl->getUnderlyingType();
- QualType Canonical = getCanonicalType(Underlying);
- auto *newType = new (*this, TypeAlignment)
- TypedefType(Type::Typedef, Decl, Underlying, Canonical);
- Decl->TypeForDecl = newType;
- Types.push_back(newType);
- return QualType(newType, 0);
+ llvm::FoldingSetNodeID ID;
+ TypedefType::Profile(ID, Decl, Underlying);
+
+ void *InsertPos = nullptr;
+ if (TypedefType *T = TypedefTypes.FindNodeOrInsertPos(ID, InsertPos)) {
+ assert(!T->typeMatchesDecl() &&
+ "non-divergent case should be handled with TypeDecl");
+ return QualType(T, 0);
+ }
+
+ void *Mem =
+ Allocate(TypedefType::totalSizeToAlloc<QualType>(true), TypeAlignment);
+ auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying,
+ getCanonicalType(Underlying));
+ TypedefTypes.InsertNode(NewType, InsertPos);
+ Types.push_back(NewType);
+ return QualType(NewType, 0);
}
QualType ASTContext::getUsingType(const UsingShadowDecl *Found,
QualType Underlying) const {
llvm::FoldingSetNodeID ID;
- UsingType::Profile(ID, Found);
+ UsingType::Profile(ID, Found, Underlying);
void *InsertPos = nullptr;
- UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (T)
+ if (UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(T, 0);
- assert(!Underlying.hasLocalQualifiers());
- assert(Underlying == getTypeDeclType(cast<TypeDecl>(Found->getTargetDecl())));
- QualType Canon = Underlying.getCanonicalType();
+ const Type *TypeForDecl =
+ cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl();
- UsingType *NewType =
- new (*this, TypeAlignment) UsingType(Found, Underlying, Canon);
+ assert(!Underlying.hasLocalQualifiers());
+ QualType Canon = Underlying->getCanonicalTypeInternal();
+ assert(TypeForDecl->getCanonicalTypeInternal() == Canon);
+
+ if (Underlying.getTypePtr() == TypeForDecl)
+ Underlying = QualType();
+ void *Mem =
+ Allocate(UsingType::totalSizeToAlloc<QualType>(!Underlying.isNull()),
+ TypeAlignment);
+ UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon);
Types.push_back(NewType);
UsingTypes.InsertNode(NewType, InsertPos);
return QualType(NewType, 0);
@@ -4742,21 +4805,22 @@ QualType ASTContext::getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
}
/// Retrieve a substitution-result type.
-QualType
-ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
- QualType Replacement) const {
- assert(Replacement.isCanonical()
- && "replacement types must always be canonical");
-
+QualType ASTContext::getSubstTemplateTypeParmType(
+ QualType Replacement, Decl *AssociatedDecl, unsigned Index,
+ std::optional<unsigned> PackIndex) const {
llvm::FoldingSetNodeID ID;
- SubstTemplateTypeParmType::Profile(ID, Parm, Replacement);
+ SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index,
+ PackIndex);
void *InsertPos = nullptr;
- SubstTemplateTypeParmType *SubstParm
- = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
+ SubstTemplateTypeParmType *SubstParm =
+ SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
if (!SubstParm) {
- SubstParm = new (*this, TypeAlignment)
- SubstTemplateTypeParmType(Parm, Replacement);
+ void *Mem = Allocate(SubstTemplateTypeParmType::totalSizeToAlloc<QualType>(
+ !Replacement.isCanonical()),
+ TypeAlignment);
+ SubstParm = new (Mem) SubstTemplateTypeParmType(Replacement, AssociatedDecl,
+ Index, PackIndex);
Types.push_back(SubstParm);
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
}
@@ -4765,34 +4829,38 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
}
/// Retrieve a
-QualType ASTContext::getSubstTemplateTypeParmPackType(
- const TemplateTypeParmType *Parm,
- const TemplateArgument &ArgPack) {
+QualType
+ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
+ unsigned Index, bool Final,
+ const TemplateArgument &ArgPack) {
#ifndef NDEBUG
- for (const auto &P : ArgPack.pack_elements()) {
- assert(P.getKind() == TemplateArgument::Type &&"Pack contains a non-type");
- assert(P.getAsType().isCanonical() && "Pack contains non-canonical type");
- }
+ for (const auto &P : ArgPack.pack_elements())
+ assert(P.getKind() == TemplateArgument::Type && "Pack contains a non-type");
#endif
llvm::FoldingSetNodeID ID;
- SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack);
+ SubstTemplateTypeParmPackType::Profile(ID, AssociatedDecl, Index, Final,
+ ArgPack);
void *InsertPos = nullptr;
- if (SubstTemplateTypeParmPackType *SubstParm
- = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
+ if (SubstTemplateTypeParmPackType *SubstParm =
+ SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(SubstParm, 0);
QualType Canon;
- if (!Parm->isCanonicalUnqualified()) {
- Canon = getCanonicalType(QualType(Parm, 0));
- Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon),
- ArgPack);
- SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos);
+ {
+ TemplateArgument CanonArgPack = getCanonicalTemplateArgument(ArgPack);
+ if (!AssociatedDecl->isCanonicalDecl() ||
+ !CanonArgPack.structurallyEquals(ArgPack)) {
+ Canon = getSubstTemplateTypeParmPackType(
+ AssociatedDecl->getCanonicalDecl(), Index, Final, CanonArgPack);
+ [[maybe_unused]] const auto *Nothing =
+ SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!Nothing);
+ }
}
- auto *SubstParm
- = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon,
- ArgPack);
+ auto *SubstParm = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(
+ Canon, AssociatedDecl, Index, Final, ArgPack);
Types.push_back(SubstParm);
SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos);
return QualType(SubstParm, 0);
@@ -4838,7 +4906,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType Underlying) const {
assert(!Name.getAsDependentTemplateName() &&
"No dependent template names here!");
- QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
+ QualType TST =
+ getTemplateSpecializationType(Name, Args.arguments(), Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL =
@@ -4854,14 +4923,14 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
- const TemplateArgumentListInfo &Args,
+ ArrayRef<TemplateArgumentLoc> Args,
QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
SmallVector<TemplateArgument, 4> ArgVec;
ArgVec.reserve(Args.size());
- for (const TemplateArgumentLoc &Arg : Args.arguments())
+ for (const TemplateArgumentLoc &Arg : Args)
ArgVec.push_back(Arg.getArgument());
return getTemplateSpecializationType(Template, ArgVec, Underlying);
@@ -4887,8 +4956,8 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = QTN->getUnderlyingTemplate();
- bool IsTypeAlias =
- isa_and_nonnull<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
+ const auto *TD = Template.getAsTemplateDecl();
+ bool IsTypeAlias = TD && TD->isTypeAlias();
QualType CanonType;
if (!Underlying.isNull())
CanonType = getCanonicalType(Underlying);
@@ -4916,23 +4985,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
return QualType(Spec, 0);
}
-static bool
-getCanonicalTemplateArguments(const ASTContext &C,
- ArrayRef<TemplateArgument> OrigArgs,
- SmallVectorImpl<TemplateArgument> &CanonArgs) {
- bool AnyNonCanonArgs = false;
- unsigned NumArgs = OrigArgs.size();
- CanonArgs.resize(NumArgs);
- for (unsigned I = 0; I != NumArgs; ++I) {
- const TemplateArgument &OrigArg = OrigArgs[I];
- TemplateArgument &CanonArg = CanonArgs[I];
- CanonArg = C.getCanonicalTemplateArgument(OrigArg);
- if (!CanonArg.structurallyEquals(OrigArg))
- AnyNonCanonArgs = true;
- }
- return AnyNonCanonArgs;
-}
-
QualType ASTContext::getCanonicalTemplateSpecializationType(
TemplateName Template, ArrayRef<TemplateArgument> Args) const {
assert(!Template.getAsDependentTemplateName() &&
@@ -4944,8 +4996,9 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
- SmallVector<TemplateArgument, 4> CanonArgs;
- ::getCanonicalTemplateArguments(*this, Args, CanonArgs);
+ bool AnyNonCanonArgs = false;
+ auto CanonArgs =
+ ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
// Determine whether this canonical template specialization type already
// exists.
@@ -5065,12 +5118,9 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
return QualType(T, 0);
}
-QualType
-ASTContext::getDependentTemplateSpecializationType(
- ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- const TemplateArgumentListInfo &Args) const {
+QualType ASTContext::getDependentTemplateSpecializationType(
+ ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name, ArrayRef<TemplateArgumentLoc> Args) const {
// TODO: avoid this copy
SmallVector<TemplateArgument, 16> ArgCopy;
for (unsigned I = 0, E = Args.size(); I != E; ++I)
@@ -5102,9 +5152,9 @@ ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword CanonKeyword = Keyword;
if (Keyword == ETK_None) CanonKeyword = ETK_Typename;
- SmallVector<TemplateArgument, 16> CanonArgs;
- bool AnyNonCanonArgs =
- ::getCanonicalTemplateArguments(*this, Args, CanonArgs);
+ bool AnyNonCanonArgs = false;
+ auto CanonArgs =
+ ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
QualType Canon;
if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) {
@@ -5113,7 +5163,9 @@ ASTContext::getDependentTemplateSpecializationType(
CanonArgs);
// Find the insert position again.
- DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+ [[maybe_unused]] auto *Nothing =
+ DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!Nothing && "canonical type broken");
}
void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) +
@@ -5131,7 +5183,7 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
QualType ArgType = getTypeDeclType(TTP);
if (TTP->isParameterPack())
- ArgType = getPackExpansionType(ArgType, None);
+ ArgType = getPackExpansionType(ArgType, std::nullopt);
Arg = TemplateArgument(ArgType);
} else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
@@ -5144,17 +5196,17 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
if (T->isRecordType())
T.addConst();
Expr *E = new (*this) DeclRefExpr(
- *this, NTTP, /*enclosing*/ false, T,
+ *this, NTTP, /*RefersToEnclosingVariableOrCapture*/ false, T,
Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
if (NTTP->isParameterPack())
- E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(),
- None);
+ E = new (*this)
+ PackExpansionExpr(DependentTy, E, NTTP->getLocation(), std::nullopt);
Arg = TemplateArgument(E);
} else {
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
if (TTP->isParameterPack())
- Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
+ Arg = TemplateArgument(TemplateName(TTP), std::optional<unsigned>());
else
Arg = TemplateArgument(TemplateName(TTP));
}
@@ -5175,7 +5227,7 @@ ASTContext::getInjectedTemplateArgs(const TemplateParameterList *Params,
}
QualType ASTContext::getPackExpansionType(QualType Pattern,
- Optional<unsigned> NumExpansions,
+ std::optional<unsigned> NumExpansions,
bool ExpectPackInType) {
assert((!ExpectPackInType || Pattern->containsUnexpandedParameterPack()) &&
"Pack expansions must expand one or more parameter packs");
@@ -5243,7 +5295,7 @@ QualType ASTContext::getObjCObjectType(QualType BaseType,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) const {
return getObjCObjectType(BaseType, {},
- llvm::makeArrayRef(Protocols, NumProtocols),
+ llvm::ArrayRef(Protocols, NumProtocols),
/*isKindOf=*/false);
}
@@ -5565,30 +5617,31 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
/// multiple declarations that refer to "typeof(x)" all contain different
/// DeclRefExpr's. This doesn't effect the type checker, since it operates
/// on canonical type's (which are always unique).
-QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const {
+QualType ASTContext::getTypeOfExprType(Expr *tofExpr, TypeOfKind Kind) const {
TypeOfExprType *toe;
if (tofExpr->isTypeDependent()) {
llvm::FoldingSetNodeID ID;
- DependentTypeOfExprType::Profile(ID, *this, tofExpr);
+ DependentTypeOfExprType::Profile(ID, *this, tofExpr,
+ Kind == TypeOfKind::Unqualified);
void *InsertPos = nullptr;
- DependentTypeOfExprType *Canon
- = DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentTypeOfExprType *Canon =
+ DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos);
if (Canon) {
// We already have a "canonical" version of an identical, dependent
// typeof(expr) type. Use that as our canonical type.
- toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr,
- QualType((TypeOfExprType*)Canon, 0));
+ toe = new (*this, TypeAlignment)
+ TypeOfExprType(tofExpr, Kind, QualType((TypeOfExprType *)Canon, 0));
} else {
// Build a new, canonical typeof(expr) type.
- Canon
- = new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr);
+ Canon = new (*this, TypeAlignment)
+ DependentTypeOfExprType(*this, tofExpr, Kind);
DependentTypeOfExprTypes.InsertNode(Canon, InsertPos);
toe = Canon;
}
} else {
QualType Canonical = getCanonicalType(tofExpr->getType());
- toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Canonical);
+ toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Kind, Canonical);
}
Types.push_back(toe);
return QualType(toe, 0);
@@ -5599,9 +5652,10 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const {
/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be
/// an issue. This doesn't affect the type checker, since it operates
/// on canonical types (which are always unique).
-QualType ASTContext::getTypeOfType(QualType tofType) const {
+QualType ASTContext::getTypeOfType(QualType tofType, TypeOfKind Kind) const {
QualType Canonical = getCanonicalType(tofType);
- auto *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical);
+ auto *tot =
+ new (*this, TypeAlignment) TypeOfType(tofType, Canonical, Kind);
Types.push_back(tot);
return QualType(tot, 0);
}
@@ -5707,9 +5761,6 @@ QualType ASTContext::getAutoTypeInternal(
!TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
- if (TypeConstraintConcept)
- TypeConstraintConcept = TypeConstraintConcept->getCanonicalDecl();
-
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
@@ -5720,18 +5771,15 @@ QualType ASTContext::getAutoTypeInternal(
QualType Canon;
if (!IsCanon) {
- if (DeducedType.isNull()) {
- SmallVector<TemplateArgument, 4> CanonArgs;
- bool AnyNonCanonArgs =
- ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs);
- if (AnyNonCanonArgs) {
- Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
- TypeConstraintConcept, CanonArgs, true);
- // Find the insert position again.
- AutoTypes.FindNodeOrInsertPos(ID, InsertPos);
- }
- } else {
+ if (!DeducedType.isNull()) {
Canon = DeducedType.getCanonicalType();
+ } else if (TypeConstraintConcept) {
+ Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
+ nullptr, {}, true);
+ // Find the insert position again.
+ [[maybe_unused]] auto *Nothing =
+ AutoTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!Nothing && "canonical type broken");
}
}
@@ -5892,14 +5940,14 @@ QualType ASTContext::getUIntPtrType() const {
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
- return getFromTargetType(Target->getPtrDiffType(0));
+ return getFromTargetType(Target->getPtrDiffType(LangAS::Default));
}
/// Return the unique unsigned counterpart of "ptrdiff_t"
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
/// in the definition of %tu format specifier.
QualType ASTContext::getUnsignedPointerDiffType() const {
- return getFromTargetType(Target->getUnsignedPtrDiffType(0));
+ return getFromTargetType(Target->getUnsignedPtrDiffType(LangAS::Default));
}
/// Return the unique type for "pid_t" defined in
@@ -6199,13 +6247,13 @@ ASTContext::getCanonicalTemplateName(const TemplateName &Name) const {
}
case TemplateName::SubstTemplateTemplateParmPack: {
- SubstTemplateTemplateParmPackStorage *subst
- = Name.getAsSubstTemplateTemplateParmPack();
- TemplateTemplateParmDecl *canonParameter
- = getCanonicalTemplateTemplateParmDecl(subst->getParameterPack());
- TemplateArgument canonArgPack
- = getCanonicalTemplateArgument(subst->getArgumentPack());
- return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack);
+ SubstTemplateTemplateParmPackStorage *subst =
+ Name.getAsSubstTemplateTemplateParmPack();
+ TemplateArgument canonArgPack =
+ getCanonicalTemplateArgument(subst->getArgumentPack());
+ return getSubstTemplateTemplateParmPack(
+ canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(),
+ subst->getFinal(), subst->getIndex());
}
}
@@ -6287,7 +6335,9 @@ bool ASTContext::isSameTemplateParameter(const NamedDecl *X,
if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
auto *TY = cast<NonTypeTemplateParmDecl>(Y);
return TX->isParameterPack() == TY->isParameterPack() &&
- TX->getASTContext().hasSameType(TX->getType(), TY->getType());
+ TX->getASTContext().hasSameType(TX->getType(), TY->getType()) &&
+ isSameConstraintExpr(TX->getPlaceholderTypeConstraint(),
+ TY->getPlaceholderTypeConstraint());
}
auto *TX = cast<TemplateTemplateParmDecl>(X);
@@ -6407,8 +6457,8 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>();
for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) {
- Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
- Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
+ std::optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
+ std::optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
// Return false if the number of enable_if attributes is different.
if (!Cand1A || !Cand2A)
@@ -6428,6 +6478,31 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
return true;
}
+bool ASTContext::FriendsDifferByConstraints(const FunctionDecl *X,
+ const FunctionDecl *Y) const {
+ // If these aren't friends, then they aren't friends that differ by
+ // constraints.
+ if (!X->getFriendObjectKind() || !Y->getFriendObjectKind())
+ return false;
+
+ // If the two functions share lexical declaration context, they are not in
+ // separate instantations, and thus in the same scope.
+ if (X->getLexicalDeclContext() == Y->getLexicalDeclContext())
+ return false;
+
+ if (!X->getDescribedFunctionTemplate()) {
+ assert(!Y->getDescribedFunctionTemplate() &&
+ "How would these be the same if they aren't both templates?");
+
+ // If these friends don't have constraints, they aren't constrained, and
+ // thus don't fall under temp.friend p9. Else the simple presence of a
+ // constraint makes them unique.
+ return X->getTrailingRequiresClause();
+ }
+
+ return X->FriendConstraintRefersToEnclosingTemplate();
+}
+
bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
if (X == Y)
return true;
@@ -6508,6 +6583,10 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
FuncY->getTrailingRequiresClause()))
return false;
+ // Constrained friends are different in certain cases, see: [temp.friend]p9.
+ if (FriendsDifferByConstraints(FuncX, FuncY))
+ return false;
+
auto GetTypeAsWritten = [](const FunctionDecl *FD) {
// Map to the first declaration that we've already merged into this one.
// The TSI of redeclarations might not match (due to calling conventions
@@ -6660,7 +6739,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
case TemplateArgument::Declaration: {
auto *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl());
- return TemplateArgument(D, Arg.getParamTypeForDecl());
+ return TemplateArgument(D, getCanonicalType(Arg.getParamTypeForDecl()));
}
case TemplateArgument::NullPtr:
@@ -6682,17 +6761,13 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
return TemplateArgument(getCanonicalType(Arg.getAsType()));
case TemplateArgument::Pack: {
- if (Arg.pack_size() == 0)
+ bool AnyNonCanonArgs = false;
+ auto CanonArgs = ::getCanonicalTemplateArguments(
+ *this, Arg.pack_elements(), AnyNonCanonArgs);
+ if (!AnyNonCanonArgs)
return Arg;
-
- auto *CanonArgs = new (*this) TemplateArgument[Arg.pack_size()];
- unsigned Idx = 0;
- for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
- AEnd = Arg.pack_end();
- A != AEnd; (void)++A, ++Idx)
- CanonArgs[Idx] = getCanonicalTemplateArgument(*A);
-
- return TemplateArgument(llvm::makeArrayRef(CanonArgs, Arg.pack_size()));
+ return TemplateArgument::CreatePackCopy(const_cast<ASTContext &>(*this),
+ CanonArgs);
}
}
@@ -6864,7 +6939,7 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) const {
PrettyArrayType->getIndexTypeQualifiers());
// int x[_Nullable] -> int * _Nullable
- if (auto Nullability = Ty->getNullability(*this)) {
+ if (auto Nullability = Ty->getNullability()) {
Result = const_cast<ASTContext *>(this)->getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability), Result, Result);
}
@@ -6901,6 +6976,21 @@ ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
return ElementCount;
}
+uint64_t ASTContext::getArrayInitLoopExprElementCount(
+ const ArrayInitLoopExpr *AILE) const {
+ if (!AILE)
+ return 0;
+
+ uint64_t ElementCount = 1;
+
+ do {
+ ElementCount *= AILE->getArraySize().getZExtValue();
+ AILE = dyn_cast<ArrayInitLoopExpr>(AILE->getSubExpr());
+ } while (AILE);
+
+ return ElementCount;
+}
+
/// getFloatingRank - Return a relative rank for floating point types.
/// This routine will assert if passed a built-in type that isn't a float.
static FloatingRank getFloatingRank(QualType T) {
@@ -6976,6 +7066,21 @@ unsigned ASTContext::getIntegerRank(const Type *T) const {
case BuiltinType::Int128:
case BuiltinType::UInt128:
return 7 + (getIntWidth(Int128Ty) << 3);
+
+ // "The ranks of char8_t, char16_t, char32_t, and wchar_t equal the ranks of
+ // their underlying types" [c++20 conv.rank]
+ case BuiltinType::Char8:
+ return getIntegerRank(UnsignedCharTy.getTypePtr());
+ case BuiltinType::Char16:
+ return getIntegerRank(
+ getFromTargetType(Target->getChar16Type()).getTypePtr());
+ case BuiltinType::Char32:
+ return getIntegerRank(
+ getFromTargetType(Target->getChar32Type()).getTypePtr());
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ return getIntegerRank(
+ getFromTargetType(Target->getWCharType()).getTypePtr());
}
}
@@ -7041,7 +7146,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) const {
/// integer type.
QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
assert(!Promotable.isNull());
- assert(Promotable->isPromotableIntegerType());
+ assert(isPromotableIntegerType(Promotable));
if (const auto *ET = Promotable->getAs<EnumType>())
return ET->getDecl()->getPromotionType();
@@ -7061,12 +7166,11 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
uint64_t FromSize = getTypeSize(BT);
QualType PromoteTypes[] = { IntTy, UnsignedIntTy, LongTy, UnsignedLongTy,
LongLongTy, UnsignedLongLongTy };
- for (size_t Idx = 0; Idx < llvm::array_lengthof(PromoteTypes); ++Idx) {
- uint64_t ToSize = getTypeSize(PromoteTypes[Idx]);
+ for (const auto &PT : PromoteTypes) {
+ uint64_t ToSize = getTypeSize(PT);
if (FromSize < ToSize ||
- (FromSize == ToSize &&
- FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType()))
- return PromoteTypes[Idx];
+ (FromSize == ToSize && FromIsSigned == PT->isSignedIntegerType()))
+ return PT;
}
llvm_unreachable("char type should fit into long long");
}
@@ -7551,7 +7655,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
// FIXME: There might(should) be a better way of doing this computation!
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
CharUnits ParmOffset = PtrSize;
- for (auto PI : Decl->parameters()) {
+ for (auto *PI : Decl->parameters()) {
QualType PType = PI->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
if (sz.isZero())
@@ -7566,7 +7670,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
// Argument types.
ParmOffset = PtrSize;
- for (auto PVDecl : Decl->parameters()) {
+ for (auto *PVDecl : Decl->parameters()) {
QualType PType = PVDecl->getOriginalType();
if (const auto *AT =
dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
@@ -7595,7 +7699,7 @@ ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl) const {
getObjCEncodingForType(Decl->getReturnType(), S);
CharUnits ParmOffset;
// Compute size of all parameters.
- for (auto PI : Decl->parameters()) {
+ for (auto *PI : Decl->parameters()) {
QualType PType = PI->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
if (sz.isZero())
@@ -7609,7 +7713,7 @@ ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl) const {
ParmOffset = CharUnits::Zero();
// Argument types.
- for (auto PVDecl : Decl->parameters()) {
+ for (auto *PVDecl : Decl->parameters()) {
QualType PType = PVDecl->getOriginalType();
if (const auto *AT =
dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
@@ -7816,7 +7920,7 @@ ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
/// 'l' or 'L' , but not always. For typedefs, we need to use
/// 'i' or 'I' instead if encoding a struct field, or a pointer!
void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const {
- if (isa<TypedefType>(PointeeTy.getTypePtr())) {
+ if (PointeeTy->getAs<TypedefType>()) {
if (const auto *BT = PointeeTy->getAs<BuiltinType>()) {
if (BT->getKind() == BuiltinType::ULong && getIntWidth(PointeeTy) == 32)
PointeeTy = UnsignedIntTy;
@@ -8104,7 +8208,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
// pointee gets emitted _before_ the '^'. The read-only qualifier of
// the pointer itself gets ignored, _unless_ we are looking at a typedef!
// Also, do not emit the 'r' for anything but the outermost type!
- if (isa<TypedefType>(T.getTypePtr())) {
+ if (T->getAs<TypedefType>()) {
if (Options.IsOutermostType() && T.isConstQualified()) {
isReadOnly = true;
S += 'r';
@@ -8286,7 +8390,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
return;
}
// TODO: Double check to make sure this intentionally falls through.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case Type::ObjCInterface: {
@@ -8641,9 +8745,9 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
// namespace std { struct __va_list {
auto *NS = NamespaceDecl::Create(
const_cast<ASTContext &>(*Context), Context->getTranslationUnitDecl(),
- /*Inline*/ false, SourceLocation(), SourceLocation(),
+ /*Inline=*/false, SourceLocation(), SourceLocation(),
&Context->Idents.get("std"),
- /*PrevDecl*/ nullptr);
+ /*PrevDecl=*/nullptr, /*Nested=*/false);
NS->setImplicit();
VaListTagDecl->setDeclContext(NS);
}
@@ -8830,9 +8934,9 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
NamespaceDecl *NS;
NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
Context->getTranslationUnitDecl(),
- /*Inline*/false, SourceLocation(),
+ /*Inline=*/false, SourceLocation(),
SourceLocation(), &Context->Idents.get("std"),
- /*PrevDecl*/ nullptr);
+ /*PrevDecl=*/nullptr, /*Nested=*/false);
NS->setImplicit();
VaListDecl->setDeclContext(NS);
}
@@ -9020,6 +9124,10 @@ TypedefDecl *ASTContext::getBuiltinMSVaListDecl() const {
}
bool ASTContext::canBuiltinBeRedeclared(const FunctionDecl *FD) const {
+ // Allow redecl custom type checking builtin for HLSL.
+ if (LangOpts.HLSL && FD->getBuiltinID() != Builtin::NotBuiltin &&
+ BuiltinInfo.hasCustomTypechecking(FD->getBuiltinID()))
+ return true;
return BuiltinInfo.canBeRedeclared(FD->getBuiltinID());
}
@@ -9158,18 +9266,20 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
return TemplateName(QTN);
}
-TemplateName
-ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param,
- TemplateName replacement) const {
+TemplateName ASTContext::getSubstTemplateTemplateParm(
+ TemplateName Replacement, Decl *AssociatedDecl, unsigned Index,
+ std::optional<unsigned> PackIndex) const {
llvm::FoldingSetNodeID ID;
- SubstTemplateTemplateParmStorage::Profile(ID, param, replacement);
+ SubstTemplateTemplateParmStorage::Profile(ID, Replacement, AssociatedDecl,
+ Index, PackIndex);
void *insertPos = nullptr;
SubstTemplateTemplateParmStorage *subst
= SubstTemplateTemplateParms.FindNodeOrInsertPos(ID, insertPos);
if (!subst) {
- subst = new (*this) SubstTemplateTemplateParmStorage(param, replacement);
+ subst = new (*this) SubstTemplateTemplateParmStorage(
+ Replacement, AssociatedDecl, Index, PackIndex);
SubstTemplateTemplateParms.InsertNode(subst, insertPos);
}
@@ -9177,20 +9287,21 @@ ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param,
}
TemplateName
-ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
- const TemplateArgument &ArgPack) const {
+ASTContext::getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack,
+ Decl *AssociatedDecl,
+ unsigned Index, bool Final) const {
auto &Self = const_cast<ASTContext &>(*this);
llvm::FoldingSetNodeID ID;
- SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack);
+ SubstTemplateTemplateParmPackStorage::Profile(ID, Self, ArgPack,
+ AssociatedDecl, Index, Final);
void *InsertPos = nullptr;
SubstTemplateTemplateParmPackStorage *Subst
= SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos);
if (!Subst) {
- Subst = new (*this) SubstTemplateTemplateParmPackStorage(Param,
- ArgPack.pack_size(),
- ArgPack.pack_begin());
+ Subst = new (*this) SubstTemplateTemplateParmPackStorage(
+ ArgPack.pack_elements(), AssociatedDecl, Index, Final);
SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos);
}
@@ -9707,7 +9818,7 @@ void getIntersectionOfProtocols(ASTContext &Context,
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSProtocolSet;
// Start with the protocol qualifiers.
- for (auto proto : LHS->quals()) {
+ for (auto *proto : LHS->quals()) {
Context.CollectInheritedProtocols(proto, LHSProtocolSet);
}
@@ -9718,7 +9829,7 @@ void getIntersectionOfProtocols(ASTContext &Context,
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSProtocolSet;
// Start with the protocol qualifiers.
- for (auto proto : RHS->quals()) {
+ for (auto *proto : RHS->quals()) {
Context.CollectInheritedProtocols(proto, RHSProtocolSet);
}
@@ -9726,7 +9837,7 @@ void getIntersectionOfProtocols(ASTContext &Context,
Context.CollectInheritedProtocols(RHS->getInterface(), RHSProtocolSet);
// Compute the intersection of the collected protocol sets.
- for (auto proto : LHSProtocolSet) {
+ for (auto *proto : LHSProtocolSet) {
if (RHSProtocolSet.count(proto))
IntersectionSet.push_back(proto);
}
@@ -10077,7 +10188,8 @@ QualType ASTContext::mergeFunctionParameterTypes(QualType lhs, QualType rhs,
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
bool OfBlockPointer, bool Unqualified,
- bool AllowCXX) {
+ bool AllowCXX,
+ bool IsConditionalOperator) {
const auto *lbase = lhs->castAs<FunctionType>();
const auto *rbase = rhs->castAs<FunctionType>();
const auto *lproto = dyn_cast<FunctionProtoType>(lbase);
@@ -10140,9 +10252,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getNoCfCheck() != rbaseInfo.getNoCfCheck())
return {};
- // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
- bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
-
+ // When merging declarations, it's common for supplemental information like
+ // attributes to only be present in one of the declarations, and we generally
+ // want type merging to preserve the union of information. So a merged
+ // function type should be noreturn if it was noreturn in *either* operand
+ // type.
+ //
+ // But for the conditional operator, this is backwards. The result of the
+ // operator could be either operand, and its type should conservatively
+ // reflect that. So a function type in a composite type is noreturn only
+ // if it's noreturn in *both* operand types.
+ //
+ // Arguably, noreturn is a kind of subtype, and the conditional operator
+ // ought to produce the most specific common supertype of its operand types.
+ // That would differ from this rule in contravariant positions. However,
+ // neither C nor C++ generally uses this kind of subtype reasoning. Also,
+ // as a practical matter, it would only affect C code that does abstraction of
+ // higher-order functions (taking noreturn callbacks!), which is uncommon to
+ // say the least. So we use the simpler rule.
+ bool NoReturn = IsConditionalOperator
+ ? lbaseInfo.getNoReturn() && rbaseInfo.getNoReturn()
+ : lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
if (lbaseInfo.getNoReturn() != NoReturn)
allLTypes = false;
if (rbaseInfo.getNoReturn() != NoReturn)
@@ -10235,7 +10365,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
return {};
}
- if (paramTy->isPromotableIntegerType() ||
+ if (isPromotableIntegerType(paramTy) ||
getCanonicalType(paramTy).getUnqualifiedType() == FloatTy)
return {};
}
@@ -10275,9 +10405,9 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET,
return {};
}
-QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
- bool OfBlockPointer,
- bool Unqualified, bool BlockReturnType) {
+QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
+ bool Unqualified, bool BlockReturnType,
+ bool IsConditionalOperator) {
// For C++ we will not reach this code with reference types (see below),
// for OpenMP variant call overloading we might.
//
@@ -10517,7 +10647,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
const ConstantArrayType* CAT)
-> std::pair<bool,llvm::APInt> {
if (VAT) {
- Optional<llvm::APSInt> TheInt;
+ std::optional<llvm::APSInt> TheInt;
Expr *E = VAT->getSizeExpr();
if (E && (TheInt = E->getIntegerConstantExpr(*this)))
return std::make_pair(true, *TheInt);
@@ -10570,7 +10700,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
ArrayType::ArraySizeModifier(), 0);
}
case Type::FunctionNoProto:
- return mergeFunctionTypes(LHS, RHS, OfBlockPointer, Unqualified);
+ return mergeFunctionTypes(LHS, RHS, OfBlockPointer, Unqualified,
+ /*AllowCXX=*/false, IsConditionalOperator);
case Type::Record:
case Type::Enum:
return {};
@@ -10778,7 +10909,8 @@ unsigned ASTContext::getIntWidth(QualType T) const {
}
QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
- assert((T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) &&
+ assert((T->hasIntegerRepresentation() || T->isEnumeralType() ||
+ T->isFixedPointType()) &&
"Unexpected type");
// Turn <4 x signed int> -> <4 x unsigned int>
@@ -10796,8 +10928,11 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
T = ETy->getDecl()->getIntegerType();
switch (T->castAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Char_U:
+ // Plain `char` is mapped to `unsigned char` even if it's already unsigned
case BuiltinType::Char_S:
case BuiltinType::SChar:
+ case BuiltinType::Char8:
return UnsignedCharTy;
case BuiltinType::Short:
return UnsignedShortTy;
@@ -10811,7 +10946,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
return UnsignedInt128Ty;
// wchar_t is special. It is either signed or not, but when it's signed,
// there's no matching "unsigned wchar_t". Therefore we return the unsigned
- // version of it's underlying type instead.
+ // version of its underlying type instead.
case BuiltinType::WChar_S:
return getUnsignedWCharType();
@@ -10840,13 +10975,16 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
case BuiltinType::SatLongFract:
return SatUnsignedLongFractTy;
default:
- llvm_unreachable("Unexpected signed integer or fixed point type");
+ assert((T->hasUnsignedIntegerRepresentation() ||
+ T->isUnsignedFixedPointType()) &&
+ "Unexpected signed integer or fixed point type");
+ return T;
}
}
QualType ASTContext::getCorrespondingSignedType(QualType T) const {
- assert((T->hasUnsignedIntegerRepresentation() ||
- T->isUnsignedFixedPointType()) &&
+ assert((T->hasIntegerRepresentation() || T->isEnumeralType() ||
+ T->isFixedPointType()) &&
"Unexpected type");
// Turn <4 x unsigned int> -> <4 x signed int>
@@ -10864,8 +11002,11 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
T = ETy->getDecl()->getIntegerType();
switch (T->castAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Char_S:
+ // Plain `char` is mapped to `signed char` even if it's already signed
case BuiltinType::Char_U:
case BuiltinType::UChar:
+ case BuiltinType::Char8:
return SignedCharTy;
case BuiltinType::UShort:
return ShortTy;
@@ -10879,7 +11020,7 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
return Int128Ty;
// wchar_t is special. It is either unsigned or not, but when it's unsigned,
// there's no matching "signed wchar_t". Therefore we return the signed
- // version of it's underlying type instead.
+ // version of its underlying type instead.
case BuiltinType::WChar_U:
return getSignedWCharType();
@@ -10908,7 +11049,10 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
case BuiltinType::SatULongFract:
return SatLongFractTy;
default:
- llvm_unreachable("Unexpected unsigned integer or fixed point type");
+ assert(
+ (T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) &&
+ "Unexpected signed integer or fixed point type");
+ return T;
}
}
@@ -11673,7 +11817,7 @@ void ASTContext::forEachMultiversionedFunctionVersion(
FD->getDeclContext()->getRedeclContext()->lookup(FD->getDeclName())) {
FunctionDecl *CurFD = CurDecl->getAsFunction()->getMostRecentDecl();
if (CurFD && hasSameType(CurFD->getType(), FD->getType()) &&
- std::end(SeenDecls) == llvm::find(SeenDecls, CurFD)) {
+ !llvm::is_contained(SeenDecls, CurFD)) {
SeenDecls.insert(CurFD);
Pred(CurFD);
}
@@ -11775,10 +11919,10 @@ MangleContext *ASTContext::createDeviceMangleContext(const TargetInfo &T) {
case TargetCXXABI::XL:
return ItaniumMangleContext::create(
*this, getDiagnostics(),
- [](ASTContext &, const NamedDecl *ND) -> llvm::Optional<unsigned> {
+ [](ASTContext &, const NamedDecl *ND) -> std::optional<unsigned> {
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND))
return RD->getDeviceLambdaManglingNumber();
- return llvm::None;
+ return std::nullopt;
},
/*IsAux=*/true);
case TargetCXXABI::Microsoft:
@@ -12082,25 +12226,885 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
return getTargetInfo().getNullPointerValue(AS);
}
-unsigned ASTContext::getTargetAddressSpace(QualType T) const {
- // Return the address space for the type. If the type is a
- // function type without an address space qualifier, the
- // program address space is used. Otherwise, the target picks
- // the best address space based on the type information
- return T->isFunctionType() && !T.hasAddressSpace()
- ? getTargetInfo().getProgramAddressSpace()
- : getTargetAddressSpace(T.getQualifiers());
+unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
+ return getTargetInfo().getTargetAddressSpace(AS);
}
-unsigned ASTContext::getTargetAddressSpace(Qualifiers Q) const {
- return getTargetAddressSpace(Q.getAddressSpace());
+bool ASTContext::hasSameExpr(const Expr *X, const Expr *Y) const {
+ if (X == Y)
+ return true;
+ if (!X || !Y)
+ return false;
+ llvm::FoldingSetNodeID IDX, IDY;
+ X->Profile(IDX, *this, /*Canonical=*/true);
+ Y->Profile(IDY, *this, /*Canonical=*/true);
+ return IDX == IDY;
}
-unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
- if (isTargetAddressSpace(AS))
- return toTargetAddressSpace(AS);
+// The getCommon* helpers return, for given 'same' X and Y entities given as
+// inputs, another entity which is also the 'same' as the inputs, but which
+// is closer to the canonical form of the inputs, each according to a given
+// criteria.
+// The getCommon*Checked variants are 'null inputs not-allowed' equivalents of
+// the regular ones.
+
+static Decl *getCommonDecl(Decl *X, Decl *Y) {
+ if (!declaresSameEntity(X, Y))
+ return nullptr;
+ for (const Decl *DX : X->redecls()) {
+ // If we reach Y before reaching the first decl, that means X is older.
+ if (DX == Y)
+ return X;
+ // If we reach the first decl, then Y is older.
+ if (DX->isFirstDecl())
+ return Y;
+ }
+ llvm_unreachable("Corrupt redecls chain");
+}
+
+template <class T, std::enable_if_t<std::is_base_of_v<Decl, T>, bool> = true>
+static T *getCommonDecl(T *X, T *Y) {
+ return cast_or_null<T>(
+ getCommonDecl(const_cast<Decl *>(cast_or_null<Decl>(X)),
+ const_cast<Decl *>(cast_or_null<Decl>(Y))));
+}
+
+template <class T, std::enable_if_t<std::is_base_of_v<Decl, T>, bool> = true>
+static T *getCommonDeclChecked(T *X, T *Y) {
+ return cast<T>(getCommonDecl(const_cast<Decl *>(cast<Decl>(X)),
+ const_cast<Decl *>(cast<Decl>(Y))));
+}
+
+static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X,
+ TemplateName Y) {
+ if (X.getAsVoidPointer() == Y.getAsVoidPointer())
+ return X;
+ // FIXME: There are cases here where we could find a common template name
+ // with more sugar. For example one could be a SubstTemplateTemplate*
+ // replacing the other.
+ TemplateName CX = Ctx.getCanonicalTemplateName(X);
+ if (CX.getAsVoidPointer() !=
+ Ctx.getCanonicalTemplateName(Y).getAsVoidPointer())
+ return TemplateName();
+ return CX;
+}
+
+static TemplateName
+getCommonTemplateNameChecked(ASTContext &Ctx, TemplateName X, TemplateName Y) {
+ TemplateName R = getCommonTemplateName(Ctx, X, Y);
+ assert(R.getAsVoidPointer() != nullptr);
+ return R;
+}
+
+static auto getCommonTypes(ASTContext &Ctx, ArrayRef<QualType> Xs,
+ ArrayRef<QualType> Ys, bool Unqualified = false) {
+ assert(Xs.size() == Ys.size());
+ SmallVector<QualType, 8> Rs(Xs.size());
+ for (size_t I = 0; I < Rs.size(); ++I)
+ Rs[I] = Ctx.getCommonSugaredType(Xs[I], Ys[I], Unqualified);
+ return Rs;
+}
+
+template <class T>
+static SourceLocation getCommonAttrLoc(const T *X, const T *Y) {
+ return X->getAttributeLoc() == Y->getAttributeLoc() ? X->getAttributeLoc()
+ : SourceLocation();
+}
+
+static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx,
+ const TemplateArgument &X,
+ const TemplateArgument &Y) {
+ if (X.getKind() != Y.getKind())
+ return TemplateArgument();
+
+ switch (X.getKind()) {
+ case TemplateArgument::ArgKind::Type:
+ if (!Ctx.hasSameType(X.getAsType(), Y.getAsType()))
+ return TemplateArgument();
+ return TemplateArgument(
+ Ctx.getCommonSugaredType(X.getAsType(), Y.getAsType()));
+ case TemplateArgument::ArgKind::NullPtr:
+ if (!Ctx.hasSameType(X.getNullPtrType(), Y.getNullPtrType()))
+ return TemplateArgument();
+ return TemplateArgument(
+ Ctx.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()),
+ /*Unqualified=*/true);
+ case TemplateArgument::ArgKind::Expression:
+ if (!Ctx.hasSameType(X.getAsExpr()->getType(), Y.getAsExpr()->getType()))
+ return TemplateArgument();
+ // FIXME: Try to keep the common sugar.
+ return X;
+ case TemplateArgument::ArgKind::Template: {
+ TemplateName TX = X.getAsTemplate(), TY = Y.getAsTemplate();
+ TemplateName CTN = ::getCommonTemplateName(Ctx, TX, TY);
+ if (!CTN.getAsVoidPointer())
+ return TemplateArgument();
+ return TemplateArgument(CTN);
+ }
+ case TemplateArgument::ArgKind::TemplateExpansion: {
+ TemplateName TX = X.getAsTemplateOrTemplatePattern(),
+ TY = Y.getAsTemplateOrTemplatePattern();
+ TemplateName CTN = ::getCommonTemplateName(Ctx, TX, TY);
+ if (!CTN.getAsVoidPointer())
+ return TemplateName();
+ auto NExpX = X.getNumTemplateExpansions();
+ assert(NExpX == Y.getNumTemplateExpansions());
+ return TemplateArgument(CTN, NExpX);
+ }
+ default:
+ // FIXME: Handle the other argument kinds.
+ return X;
+ }
+}
+
+static bool getCommonTemplateArguments(ASTContext &Ctx,
+ SmallVectorImpl<TemplateArgument> &R,
+ ArrayRef<TemplateArgument> Xs,
+ ArrayRef<TemplateArgument> Ys) {
+ if (Xs.size() != Ys.size())
+ return true;
+ R.resize(Xs.size());
+ for (size_t I = 0; I < R.size(); ++I) {
+ R[I] = getCommonTemplateArgument(Ctx, Xs[I], Ys[I]);
+ if (R[I].isNull())
+ return true;
+ }
+ return false;
+}
+
+static auto getCommonTemplateArguments(ASTContext &Ctx,
+ ArrayRef<TemplateArgument> Xs,
+ ArrayRef<TemplateArgument> Ys) {
+ SmallVector<TemplateArgument, 8> R;
+ bool Different = getCommonTemplateArguments(Ctx, R, Xs, Ys);
+ assert(!Different);
+ (void)Different;
+ return R;
+}
+
+template <class T>
+static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) {
+ return X->getKeyword() == Y->getKeyword() ? X->getKeyword()
+ : ElaboratedTypeKeyword::ETK_None;
+}
+
+template <class T>
+static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, const T *X,
+ const T *Y) {
+ // FIXME: Try to keep the common NNS sugar.
+ return X->getQualifier() == Y->getQualifier()
+ ? X->getQualifier()
+ : Ctx.getCanonicalNestedNameSpecifier(X->getQualifier());
+}
+
+template <class T>
+static QualType getCommonElementType(ASTContext &Ctx, const T *X, const T *Y) {
+ return Ctx.getCommonSugaredType(X->getElementType(), Y->getElementType());
+}
+
+template <class T>
+static QualType getCommonArrayElementType(ASTContext &Ctx, const T *X,
+ Qualifiers &QX, const T *Y,
+ Qualifiers &QY) {
+ QualType EX = X->getElementType(), EY = Y->getElementType();
+ QualType R = Ctx.getCommonSugaredType(EX, EY,
+ /*Unqualified=*/true);
+ Qualifiers RQ = R.getQualifiers();
+ QX += EX.getQualifiers() - RQ;
+ QY += EY.getQualifiers() - RQ;
+ return R;
+}
+
+template <class T>
+static QualType getCommonPointeeType(ASTContext &Ctx, const T *X, const T *Y) {
+ return Ctx.getCommonSugaredType(X->getPointeeType(), Y->getPointeeType());
+}
+
+template <class T> static auto *getCommonSizeExpr(ASTContext &Ctx, T *X, T *Y) {
+ assert(Ctx.hasSameExpr(X->getSizeExpr(), Y->getSizeExpr()));
+ return X->getSizeExpr();
+}
+
+static auto getCommonSizeModifier(const ArrayType *X, const ArrayType *Y) {
+ assert(X->getSizeModifier() == Y->getSizeModifier());
+ return X->getSizeModifier();
+}
+
+static auto getCommonIndexTypeCVRQualifiers(const ArrayType *X,
+ const ArrayType *Y) {
+ assert(X->getIndexTypeCVRQualifiers() == Y->getIndexTypeCVRQualifiers());
+ return X->getIndexTypeCVRQualifiers();
+}
+
+// Merges two type lists such that the resulting vector will contain
+// each type (in a canonical sense) only once, in the order they appear
+// from X to Y. If they occur in both X and Y, the result will contain
+// the common sugared type between them.
+static void mergeTypeLists(ASTContext &Ctx, SmallVectorImpl<QualType> &Out,
+ ArrayRef<QualType> X, ArrayRef<QualType> Y) {
+ llvm::DenseMap<QualType, unsigned> Found;
+ for (auto Ts : {X, Y}) {
+ for (QualType T : Ts) {
+ auto Res = Found.try_emplace(Ctx.getCanonicalType(T), Out.size());
+ if (!Res.second) {
+ QualType &U = Out[Res.first->second];
+ U = Ctx.getCommonSugaredType(U, T);
+ } else {
+ Out.emplace_back(T);
+ }
+ }
+ }
+}
+
+FunctionProtoType::ExceptionSpecInfo
+ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
+ FunctionProtoType::ExceptionSpecInfo ESI2,
+ SmallVectorImpl<QualType> &ExceptionTypeStorage,
+ bool AcceptDependent) {
+ ExceptionSpecificationType EST1 = ESI1.Type, EST2 = ESI2.Type;
+
+ // If either of them can throw anything, that is the result.
+ for (auto I : {EST_None, EST_MSAny, EST_NoexceptFalse}) {
+ if (EST1 == I)
+ return ESI1;
+ if (EST2 == I)
+ return ESI2;
+ }
+
+ // If either of them is non-throwing, the result is the other.
+ for (auto I :
+ {EST_NoThrow, EST_DynamicNone, EST_BasicNoexcept, EST_NoexceptTrue}) {
+ if (EST1 == I)
+ return ESI2;
+ if (EST2 == I)
+ return ESI1;
+ }
+
+ // If we're left with value-dependent computed noexcept expressions, we're
+ // stuck. Before C++17, we can just drop the exception specification entirely,
+ // since it's not actually part of the canonical type. And this should never
+ // happen in C++17, because it would mean we were computing the composite
+ // pointer type of dependent types, which should never happen.
+ if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) {
+ assert(AcceptDependent &&
+ "computing composite pointer type of dependent types");
+ return FunctionProtoType::ExceptionSpecInfo();
+ }
+
+ // Switch over the possibilities so that people adding new values know to
+ // update this function.
+ switch (EST1) {
+ case EST_None:
+ case EST_DynamicNone:
+ case EST_MSAny:
+ case EST_BasicNoexcept:
+ case EST_DependentNoexcept:
+ case EST_NoexceptFalse:
+ case EST_NoexceptTrue:
+ case EST_NoThrow:
+ llvm_unreachable("These ESTs should be handled above");
+
+ case EST_Dynamic: {
+ // This is the fun case: both exception specifications are dynamic. Form
+ // the union of the two lists.
+ assert(EST2 == EST_Dynamic && "other cases should already be handled");
+ mergeTypeLists(*this, ExceptionTypeStorage, ESI1.Exceptions,
+ ESI2.Exceptions);
+ FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic);
+ Result.Exceptions = ExceptionTypeStorage;
+ return Result;
+ }
+
+ case EST_Unevaluated:
+ case EST_Uninstantiated:
+ case EST_Unparsed:
+ llvm_unreachable("shouldn't see unresolved exception specifications here");
+ }
+
+ llvm_unreachable("invalid ExceptionSpecificationType");
+}
+
+static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
+ Qualifiers &QX, const Type *Y,
+ Qualifiers &QY) {
+ Type::TypeClass TC = X->getTypeClass();
+ assert(TC == Y->getTypeClass());
+ switch (TC) {
+#define UNEXPECTED_TYPE(Class, Kind) \
+ case Type::Class: \
+ llvm_unreachable("Unexpected " Kind ": " #Class);
+
+#define NON_CANONICAL_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "non-canonical")
+#define TYPE(Class, Base)
+#include "clang/AST/TypeNodes.inc"
+
+#define SUGAR_FREE_TYPE(Class) UNEXPECTED_TYPE(Class, "sugar-free")
+ SUGAR_FREE_TYPE(Builtin)
+ SUGAR_FREE_TYPE(Decltype)
+ SUGAR_FREE_TYPE(DeducedTemplateSpecialization)
+ SUGAR_FREE_TYPE(DependentBitInt)
+ SUGAR_FREE_TYPE(Enum)
+ SUGAR_FREE_TYPE(BitInt)
+ SUGAR_FREE_TYPE(ObjCInterface)
+ SUGAR_FREE_TYPE(Record)
+ SUGAR_FREE_TYPE(SubstTemplateTypeParmPack)
+ SUGAR_FREE_TYPE(UnresolvedUsing)
+#undef SUGAR_FREE_TYPE
+#define NON_UNIQUE_TYPE(Class) UNEXPECTED_TYPE(Class, "non-unique")
+ NON_UNIQUE_TYPE(TypeOfExpr)
+ NON_UNIQUE_TYPE(VariableArray)
+#undef NON_UNIQUE_TYPE
+
+ UNEXPECTED_TYPE(TypeOf, "sugar")
+
+#undef UNEXPECTED_TYPE
+
+ case Type::Auto: {
+ const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y);
+ assert(AX->getDeducedType().isNull());
+ assert(AY->getDeducedType().isNull());
+ assert(AX->getKeyword() == AY->getKeyword());
+ assert(AX->isInstantiationDependentType() ==
+ AY->isInstantiationDependentType());
+ auto As = getCommonTemplateArguments(Ctx, AX->getTypeConstraintArguments(),
+ AY->getTypeConstraintArguments());
+ return Ctx.getAutoType(QualType(), AX->getKeyword(),
+ AX->isInstantiationDependentType(),
+ AX->containsUnexpandedParameterPack(),
+ getCommonDeclChecked(AX->getTypeConstraintConcept(),
+ AY->getTypeConstraintConcept()),
+ As);
+ }
+ case Type::IncompleteArray: {
+ const auto *AX = cast<IncompleteArrayType>(X),
+ *AY = cast<IncompleteArrayType>(Y);
+ return Ctx.getIncompleteArrayType(
+ getCommonArrayElementType(Ctx, AX, QX, AY, QY),
+ getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY));
+ }
+ case Type::DependentSizedArray: {
+ const auto *AX = cast<DependentSizedArrayType>(X),
+ *AY = cast<DependentSizedArrayType>(Y);
+ return Ctx.getDependentSizedArrayType(
+ getCommonArrayElementType(Ctx, AX, QX, AY, QY),
+ getCommonSizeExpr(Ctx, AX, AY), getCommonSizeModifier(AX, AY),
+ getCommonIndexTypeCVRQualifiers(AX, AY),
+ AX->getBracketsRange() == AY->getBracketsRange()
+ ? AX->getBracketsRange()
+ : SourceRange());
+ }
+ case Type::ConstantArray: {
+ const auto *AX = cast<ConstantArrayType>(X),
+ *AY = cast<ConstantArrayType>(Y);
+ assert(AX->getSize() == AY->getSize());
+ const Expr *SizeExpr = Ctx.hasSameExpr(AX->getSizeExpr(), AY->getSizeExpr())
+ ? AX->getSizeExpr()
+ : nullptr;
+ return Ctx.getConstantArrayType(
+ getCommonArrayElementType(Ctx, AX, QX, AY, QY), AX->getSize(), SizeExpr,
+ getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY));
+ }
+ case Type::Atomic: {
+ const auto *AX = cast<AtomicType>(X), *AY = cast<AtomicType>(Y);
+ return Ctx.getAtomicType(
+ Ctx.getCommonSugaredType(AX->getValueType(), AY->getValueType()));
+ }
+ case Type::Complex: {
+ const auto *CX = cast<ComplexType>(X), *CY = cast<ComplexType>(Y);
+ return Ctx.getComplexType(getCommonArrayElementType(Ctx, CX, QX, CY, QY));
+ }
+ case Type::Pointer: {
+ const auto *PX = cast<PointerType>(X), *PY = cast<PointerType>(Y);
+ return Ctx.getPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::BlockPointer: {
+ const auto *PX = cast<BlockPointerType>(X), *PY = cast<BlockPointerType>(Y);
+ return Ctx.getBlockPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::ObjCObjectPointer: {
+ const auto *PX = cast<ObjCObjectPointerType>(X),
+ *PY = cast<ObjCObjectPointerType>(Y);
+ return Ctx.getObjCObjectPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::MemberPointer: {
+ const auto *PX = cast<MemberPointerType>(X),
+ *PY = cast<MemberPointerType>(Y);
+ return Ctx.getMemberPointerType(
+ getCommonPointeeType(Ctx, PX, PY),
+ Ctx.getCommonSugaredType(QualType(PX->getClass(), 0),
+ QualType(PY->getClass(), 0))
+ .getTypePtr());
+ }
+ case Type::LValueReference: {
+ const auto *PX = cast<LValueReferenceType>(X),
+ *PY = cast<LValueReferenceType>(Y);
+ // FIXME: Preserve PointeeTypeAsWritten.
+ return Ctx.getLValueReferenceType(getCommonPointeeType(Ctx, PX, PY),
+ PX->isSpelledAsLValue() ||
+ PY->isSpelledAsLValue());
+ }
+ case Type::RValueReference: {
+ const auto *PX = cast<RValueReferenceType>(X),
+ *PY = cast<RValueReferenceType>(Y);
+ // FIXME: Preserve PointeeTypeAsWritten.
+ return Ctx.getRValueReferenceType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::DependentAddressSpace: {
+ const auto *PX = cast<DependentAddressSpaceType>(X),
+ *PY = cast<DependentAddressSpaceType>(Y);
+ assert(Ctx.hasSameExpr(PX->getAddrSpaceExpr(), PY->getAddrSpaceExpr()));
+ return Ctx.getDependentAddressSpaceType(getCommonPointeeType(Ctx, PX, PY),
+ PX->getAddrSpaceExpr(),
+ getCommonAttrLoc(PX, PY));
+ }
+ case Type::FunctionNoProto: {
+ const auto *FX = cast<FunctionNoProtoType>(X),
+ *FY = cast<FunctionNoProtoType>(Y);
+ assert(FX->getExtInfo() == FY->getExtInfo());
+ return Ctx.getFunctionNoProtoType(
+ Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType()),
+ FX->getExtInfo());
+ }
+ case Type::FunctionProto: {
+ const auto *FX = cast<FunctionProtoType>(X),
+ *FY = cast<FunctionProtoType>(Y);
+ FunctionProtoType::ExtProtoInfo EPIX = FX->getExtProtoInfo(),
+ EPIY = FY->getExtProtoInfo();
+ assert(EPIX.ExtInfo == EPIY.ExtInfo);
+ assert(EPIX.ExtParameterInfos == EPIY.ExtParameterInfos);
+ assert(EPIX.RefQualifier == EPIY.RefQualifier);
+ assert(EPIX.TypeQuals == EPIY.TypeQuals);
+ assert(EPIX.Variadic == EPIY.Variadic);
+
+ // FIXME: Can we handle an empty EllipsisLoc?
+ // Use emtpy EllipsisLoc if X and Y differ.
+
+ EPIX.HasTrailingReturn = EPIX.HasTrailingReturn && EPIY.HasTrailingReturn;
+
+ QualType R =
+ Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType());
+ auto P = getCommonTypes(Ctx, FX->param_types(), FY->param_types(),
+ /*Unqualified=*/true);
+
+ SmallVector<QualType, 8> Exceptions;
+ EPIX.ExceptionSpec = Ctx.mergeExceptionSpecs(
+ EPIX.ExceptionSpec, EPIY.ExceptionSpec, Exceptions, true);
+ return Ctx.getFunctionType(R, P, EPIX);
+ }
+ case Type::ObjCObject: {
+ const auto *OX = cast<ObjCObjectType>(X), *OY = cast<ObjCObjectType>(Y);
+ assert(
+ std::equal(OX->getProtocols().begin(), OX->getProtocols().end(),
+ OY->getProtocols().begin(), OY->getProtocols().end(),
+ [](const ObjCProtocolDecl *P0, const ObjCProtocolDecl *P1) {
+ return P0->getCanonicalDecl() == P1->getCanonicalDecl();
+ }) &&
+ "protocol lists must be the same");
+ auto TAs = getCommonTypes(Ctx, OX->getTypeArgsAsWritten(),
+ OY->getTypeArgsAsWritten());
+ return Ctx.getObjCObjectType(
+ Ctx.getCommonSugaredType(OX->getBaseType(), OY->getBaseType()), TAs,
+ OX->getProtocols(),
+ OX->isKindOfTypeAsWritten() && OY->isKindOfTypeAsWritten());
+ }
+ case Type::ConstantMatrix: {
+ const auto *MX = cast<ConstantMatrixType>(X),
+ *MY = cast<ConstantMatrixType>(Y);
+ assert(MX->getNumRows() == MY->getNumRows());
+ assert(MX->getNumColumns() == MY->getNumColumns());
+ return Ctx.getConstantMatrixType(getCommonElementType(Ctx, MX, MY),
+ MX->getNumRows(), MX->getNumColumns());
+ }
+ case Type::DependentSizedMatrix: {
+ const auto *MX = cast<DependentSizedMatrixType>(X),
+ *MY = cast<DependentSizedMatrixType>(Y);
+ assert(Ctx.hasSameExpr(MX->getRowExpr(), MY->getRowExpr()));
+ assert(Ctx.hasSameExpr(MX->getColumnExpr(), MY->getColumnExpr()));
+ return Ctx.getDependentSizedMatrixType(
+ getCommonElementType(Ctx, MX, MY), MX->getRowExpr(),
+ MX->getColumnExpr(), getCommonAttrLoc(MX, MY));
+ }
+ case Type::Vector: {
+ const auto *VX = cast<VectorType>(X), *VY = cast<VectorType>(Y);
+ assert(VX->getNumElements() == VY->getNumElements());
+ assert(VX->getVectorKind() == VY->getVectorKind());
+ return Ctx.getVectorType(getCommonElementType(Ctx, VX, VY),
+ VX->getNumElements(), VX->getVectorKind());
+ }
+ case Type::ExtVector: {
+ const auto *VX = cast<ExtVectorType>(X), *VY = cast<ExtVectorType>(Y);
+ assert(VX->getNumElements() == VY->getNumElements());
+ return Ctx.getExtVectorType(getCommonElementType(Ctx, VX, VY),
+ VX->getNumElements());
+ }
+ case Type::DependentSizedExtVector: {
+ const auto *VX = cast<DependentSizedExtVectorType>(X),
+ *VY = cast<DependentSizedExtVectorType>(Y);
+ return Ctx.getDependentSizedExtVectorType(getCommonElementType(Ctx, VX, VY),
+ getCommonSizeExpr(Ctx, VX, VY),
+ getCommonAttrLoc(VX, VY));
+ }
+ case Type::DependentVector: {
+ const auto *VX = cast<DependentVectorType>(X),
+ *VY = cast<DependentVectorType>(Y);
+ assert(VX->getVectorKind() == VY->getVectorKind());
+ return Ctx.getDependentVectorType(
+ getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(Ctx, VX, VY),
+ getCommonAttrLoc(VX, VY), VX->getVectorKind());
+ }
+ case Type::InjectedClassName: {
+ const auto *IX = cast<InjectedClassNameType>(X),
+ *IY = cast<InjectedClassNameType>(Y);
+ return Ctx.getInjectedClassNameType(
+ getCommonDeclChecked(IX->getDecl(), IY->getDecl()),
+ Ctx.getCommonSugaredType(IX->getInjectedSpecializationType(),
+ IY->getInjectedSpecializationType()));
+ }
+ case Type::TemplateSpecialization: {
+ const auto *TX = cast<TemplateSpecializationType>(X),
+ *TY = cast<TemplateSpecializationType>(Y);
+ auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
+ TY->template_arguments());
+ return Ctx.getTemplateSpecializationType(
+ ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(),
+ TY->getTemplateName()),
+ As, X->getCanonicalTypeInternal());
+ }
+ case Type::DependentName: {
+ const auto *NX = cast<DependentNameType>(X),
+ *NY = cast<DependentNameType>(Y);
+ assert(NX->getIdentifier() == NY->getIdentifier());
+ return Ctx.getDependentNameType(
+ getCommonTypeKeyword(NX, NY), getCommonNNS(Ctx, NX, NY),
+ NX->getIdentifier(), NX->getCanonicalTypeInternal());
+ }
+ case Type::DependentTemplateSpecialization: {
+ const auto *TX = cast<DependentTemplateSpecializationType>(X),
+ *TY = cast<DependentTemplateSpecializationType>(Y);
+ assert(TX->getIdentifier() == TY->getIdentifier());
+ auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
+ TY->template_arguments());
+ return Ctx.getDependentTemplateSpecializationType(
+ getCommonTypeKeyword(TX, TY), getCommonNNS(Ctx, TX, TY),
+ TX->getIdentifier(), As);
+ }
+ case Type::UnaryTransform: {
+ const auto *TX = cast<UnaryTransformType>(X),
+ *TY = cast<UnaryTransformType>(Y);
+ assert(TX->getUTTKind() == TY->getUTTKind());
+ return Ctx.getUnaryTransformType(
+ Ctx.getCommonSugaredType(TX->getBaseType(), TY->getBaseType()),
+ Ctx.getCommonSugaredType(TX->getUnderlyingType(),
+ TY->getUnderlyingType()),
+ TX->getUTTKind());
+ }
+ case Type::PackExpansion: {
+ const auto *PX = cast<PackExpansionType>(X),
+ *PY = cast<PackExpansionType>(Y);
+ assert(PX->getNumExpansions() == PY->getNumExpansions());
+ return Ctx.getPackExpansionType(
+ Ctx.getCommonSugaredType(PX->getPattern(), PY->getPattern()),
+ PX->getNumExpansions(), false);
+ }
+ case Type::Pipe: {
+ const auto *PX = cast<PipeType>(X), *PY = cast<PipeType>(Y);
+ assert(PX->isReadOnly() == PY->isReadOnly());
+ auto MP = PX->isReadOnly() ? &ASTContext::getReadPipeType
+ : &ASTContext::getWritePipeType;
+ return (Ctx.*MP)(getCommonElementType(Ctx, PX, PY));
+ }
+ case Type::TemplateTypeParm: {
+ const auto *TX = cast<TemplateTypeParmType>(X),
+ *TY = cast<TemplateTypeParmType>(Y);
+ assert(TX->getDepth() == TY->getDepth());
+ assert(TX->getIndex() == TY->getIndex());
+ assert(TX->isParameterPack() == TY->isParameterPack());
+ return Ctx.getTemplateTypeParmType(
+ TX->getDepth(), TX->getIndex(), TX->isParameterPack(),
+ getCommonDecl(TX->getDecl(), TY->getDecl()));
+ }
+ }
+ llvm_unreachable("Unknown Type Class");
+}
+
+static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
+ const Type *Y,
+ SplitQualType Underlying) {
+ Type::TypeClass TC = X->getTypeClass();
+ if (TC != Y->getTypeClass())
+ return QualType();
+ switch (TC) {
+#define UNEXPECTED_TYPE(Class, Kind) \
+ case Type::Class: \
+ llvm_unreachable("Unexpected " Kind ": " #Class);
+#define TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "dependent")
+#include "clang/AST/TypeNodes.inc"
+
+#define CANONICAL_TYPE(Class) UNEXPECTED_TYPE(Class, "canonical")
+ CANONICAL_TYPE(Atomic)
+ CANONICAL_TYPE(BitInt)
+ CANONICAL_TYPE(BlockPointer)
+ CANONICAL_TYPE(Builtin)
+ CANONICAL_TYPE(Complex)
+ CANONICAL_TYPE(ConstantArray)
+ CANONICAL_TYPE(ConstantMatrix)
+ CANONICAL_TYPE(Enum)
+ CANONICAL_TYPE(ExtVector)
+ CANONICAL_TYPE(FunctionNoProto)
+ CANONICAL_TYPE(FunctionProto)
+ CANONICAL_TYPE(IncompleteArray)
+ CANONICAL_TYPE(LValueReference)
+ CANONICAL_TYPE(MemberPointer)
+ CANONICAL_TYPE(ObjCInterface)
+ CANONICAL_TYPE(ObjCObject)
+ CANONICAL_TYPE(ObjCObjectPointer)
+ CANONICAL_TYPE(Pipe)
+ CANONICAL_TYPE(Pointer)
+ CANONICAL_TYPE(Record)
+ CANONICAL_TYPE(RValueReference)
+ CANONICAL_TYPE(VariableArray)
+ CANONICAL_TYPE(Vector)
+#undef CANONICAL_TYPE
+
+#undef UNEXPECTED_TYPE
+
+ case Type::Adjusted: {
+ const auto *AX = cast<AdjustedType>(X), *AY = cast<AdjustedType>(Y);
+ QualType OX = AX->getOriginalType(), OY = AY->getOriginalType();
+ if (!Ctx.hasSameType(OX, OY))
+ return QualType();
+ // FIXME: It's inefficient to have to unify the original types.
+ return Ctx.getAdjustedType(Ctx.getCommonSugaredType(OX, OY),
+ Ctx.getQualifiedType(Underlying));
+ }
+ case Type::Decayed: {
+ const auto *DX = cast<DecayedType>(X), *DY = cast<DecayedType>(Y);
+ QualType OX = DX->getOriginalType(), OY = DY->getOriginalType();
+ if (!Ctx.hasSameType(OX, OY))
+ return QualType();
+ // FIXME: It's inefficient to have to unify the original types.
+ return Ctx.getDecayedType(Ctx.getCommonSugaredType(OX, OY),
+ Ctx.getQualifiedType(Underlying));
+ }
+ case Type::Attributed: {
+ const auto *AX = cast<AttributedType>(X), *AY = cast<AttributedType>(Y);
+ AttributedType::Kind Kind = AX->getAttrKind();
+ if (Kind != AY->getAttrKind())
+ return QualType();
+ QualType MX = AX->getModifiedType(), MY = AY->getModifiedType();
+ if (!Ctx.hasSameType(MX, MY))
+ return QualType();
+ // FIXME: It's inefficient to have to unify the modified types.
+ return Ctx.getAttributedType(Kind, Ctx.getCommonSugaredType(MX, MY),
+ Ctx.getQualifiedType(Underlying));
+ }
+ case Type::BTFTagAttributed: {
+ const auto *BX = cast<BTFTagAttributedType>(X);
+ const BTFTypeTagAttr *AX = BX->getAttr();
+ // The attribute is not uniqued, so just compare the tag.
+ if (AX->getBTFTypeTag() !=
+ cast<BTFTagAttributedType>(Y)->getAttr()->getBTFTypeTag())
+ return QualType();
+ return Ctx.getBTFTagAttributedType(AX, Ctx.getQualifiedType(Underlying));
+ }
+ case Type::Auto: {
+ const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y);
+
+ AutoTypeKeyword KW = AX->getKeyword();
+ if (KW != AY->getKeyword())
+ return QualType();
+
+ ConceptDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(),
+ AY->getTypeConstraintConcept());
+ SmallVector<TemplateArgument, 8> As;
+ if (CD &&
+ getCommonTemplateArguments(Ctx, As, AX->getTypeConstraintArguments(),
+ AY->getTypeConstraintArguments()))
+ CD = nullptr; // The arguments differ, so make it unconstrained.
+
+ // Both auto types can't be dependent, otherwise they wouldn't have been
+ // sugar. This implies they can't contain unexpanded packs either.
+ return Ctx.getAutoType(Ctx.getQualifiedType(Underlying), AX->getKeyword(),
+ /*IsDependent=*/false, /*IsPack=*/false, CD, As);
+ }
+ case Type::Decltype:
+ return QualType();
+ case Type::DeducedTemplateSpecialization:
+ // FIXME: Try to merge these.
+ return QualType();
+
+ case Type::Elaborated: {
+ const auto *EX = cast<ElaboratedType>(X), *EY = cast<ElaboratedType>(Y);
+ return Ctx.getElaboratedType(
+ ::getCommonTypeKeyword(EX, EY), ::getCommonNNS(Ctx, EX, EY),
+ Ctx.getQualifiedType(Underlying),
+ ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl()));
+ }
+ case Type::MacroQualified: {
+ const auto *MX = cast<MacroQualifiedType>(X),
+ *MY = cast<MacroQualifiedType>(Y);
+ const IdentifierInfo *IX = MX->getMacroIdentifier();
+ if (IX != MY->getMacroIdentifier())
+ return QualType();
+ return Ctx.getMacroQualifiedType(Ctx.getQualifiedType(Underlying), IX);
+ }
+ case Type::SubstTemplateTypeParm: {
+ const auto *SX = cast<SubstTemplateTypeParmType>(X),
+ *SY = cast<SubstTemplateTypeParmType>(Y);
+ Decl *CD =
+ ::getCommonDecl(SX->getAssociatedDecl(), SY->getAssociatedDecl());
+ if (!CD)
+ return QualType();
+ unsigned Index = SX->getIndex();
+ if (Index != SY->getIndex())
+ return QualType();
+ auto PackIndex = SX->getPackIndex();
+ if (PackIndex != SY->getPackIndex())
+ return QualType();
+ return Ctx.getSubstTemplateTypeParmType(Ctx.getQualifiedType(Underlying),
+ CD, Index, PackIndex);
+ }
+ case Type::ObjCTypeParam:
+ // FIXME: Try to merge these.
+ return QualType();
+ case Type::Paren:
+ return Ctx.getParenType(Ctx.getQualifiedType(Underlying));
+
+ case Type::TemplateSpecialization: {
+ const auto *TX = cast<TemplateSpecializationType>(X),
+ *TY = cast<TemplateSpecializationType>(Y);
+ TemplateName CTN = ::getCommonTemplateName(Ctx, TX->getTemplateName(),
+ TY->getTemplateName());
+ if (!CTN.getAsVoidPointer())
+ return QualType();
+ SmallVector<TemplateArgument, 8> Args;
+ if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(),
+ TY->template_arguments()))
+ return QualType();
+ return Ctx.getTemplateSpecializationType(CTN, Args,
+ Ctx.getQualifiedType(Underlying));
+ }
+ case Type::Typedef: {
+ const auto *TX = cast<TypedefType>(X), *TY = cast<TypedefType>(Y);
+ const TypedefNameDecl *CD = ::getCommonDecl(TX->getDecl(), TY->getDecl());
+ if (!CD)
+ return QualType();
+ return Ctx.getTypedefType(CD, Ctx.getQualifiedType(Underlying));
+ }
+ case Type::TypeOf: {
+ // The common sugar between two typeof expressions, where one is
+ // potentially a typeof_unqual and the other is not, we unify to the
+ // qualified type as that retains the most information along with the type.
+ // We only return a typeof_unqual type when both types are unqual types.
+ TypeOfKind Kind = TypeOfKind::Qualified;
+ if (cast<TypeOfType>(X)->getKind() == cast<TypeOfType>(Y)->getKind() &&
+ cast<TypeOfType>(X)->getKind() == TypeOfKind::Unqualified)
+ Kind = TypeOfKind::Unqualified;
+ return Ctx.getTypeOfType(Ctx.getQualifiedType(Underlying), Kind);
+ }
+ case Type::TypeOfExpr:
+ return QualType();
+
+ case Type::UnaryTransform: {
+ const auto *UX = cast<UnaryTransformType>(X),
+ *UY = cast<UnaryTransformType>(Y);
+ UnaryTransformType::UTTKind KX = UX->getUTTKind();
+ if (KX != UY->getUTTKind())
+ return QualType();
+ QualType BX = UX->getBaseType(), BY = UY->getBaseType();
+ if (!Ctx.hasSameType(BX, BY))
+ return QualType();
+ // FIXME: It's inefficient to have to unify the base types.
+ return Ctx.getUnaryTransformType(Ctx.getCommonSugaredType(BX, BY),
+ Ctx.getQualifiedType(Underlying), KX);
+ }
+ case Type::Using: {
+ const auto *UX = cast<UsingType>(X), *UY = cast<UsingType>(Y);
+ const UsingShadowDecl *CD =
+ ::getCommonDecl(UX->getFoundDecl(), UY->getFoundDecl());
+ if (!CD)
+ return QualType();
+ return Ctx.getUsingType(CD, Ctx.getQualifiedType(Underlying));
+ }
+ }
+ llvm_unreachable("Unhandled Type Class");
+}
+
+static auto unwrapSugar(SplitQualType &T, Qualifiers &QTotal) {
+ SmallVector<SplitQualType, 8> R;
+ while (true) {
+ QTotal += T.Quals;
+ QualType NT = T.Ty->getLocallyUnqualifiedSingleStepDesugaredType();
+ if (NT == QualType(T.Ty, 0))
+ break;
+ R.push_back(T);
+ T = NT.split();
+ }
+ return R;
+}
+
+QualType ASTContext::getCommonSugaredType(QualType X, QualType Y,
+ bool Unqualified) {
+ assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y));
+ if (X == Y)
+ return X;
+ if (!Unqualified) {
+ if (X.isCanonical())
+ return X;
+ if (Y.isCanonical())
+ return Y;
+ }
+
+ SplitQualType SX = X.split(), SY = Y.split();
+ Qualifiers QX, QY;
+ // Desugar SX and SY, setting the sugar and qualifiers aside into Xs and Ys,
+ // until we reach their underlying "canonical nodes". Note these are not
+ // necessarily canonical types, as they may still have sugared properties.
+ // QX and QY will store the sum of all qualifiers in Xs and Ys respectively.
+ auto Xs = ::unwrapSugar(SX, QX), Ys = ::unwrapSugar(SY, QY);
+ if (SX.Ty != SY.Ty) {
+ // The canonical nodes differ. Build a common canonical node out of the two,
+ // unifying their sugar. This may recurse back here.
+ SX.Ty =
+ ::getCommonNonSugarTypeNode(*this, SX.Ty, QX, SY.Ty, QY).getTypePtr();
+ } else {
+ // The canonical nodes were identical: We may have desugared too much.
+ // Add any common sugar back in.
+ while (!Xs.empty() && !Ys.empty() && Xs.back().Ty == Ys.back().Ty) {
+ QX -= SX.Quals;
+ QY -= SY.Quals;
+ SX = Xs.pop_back_val();
+ SY = Ys.pop_back_val();
+ }
+ }
+ if (Unqualified)
+ QX = Qualifiers::removeCommonQualifiers(QX, QY);
else
- return (*AddrSpaceMap)[(unsigned)AS];
+ assert(QX == QY);
+
+ // Even though the remaining sugar nodes in Xs and Ys differ, some may be
+ // related. Walk up these nodes, unifying them and adding the result.
+ while (!Xs.empty() && !Ys.empty()) {
+ auto Underlying = SplitQualType(
+ SX.Ty, Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals));
+ SX = Xs.pop_back_val();
+ SY = Ys.pop_back_val();
+ SX.Ty = ::getCommonSugarTypeNode(*this, SX.Ty, SY.Ty, Underlying)
+ .getTypePtrOrNull();
+ // Stop at the first pair which is unrelated.
+ if (!SX.Ty) {
+ SX.Ty = Underlying.Ty;
+ break;
+ }
+ QX -= Underlying.Quals;
+ };
+
+ // Add back the missing accumulated qualifiers, which were stripped off
+ // with the sugar nodes we could not unify.
+ QualType R = getQualifiedType(SX.Ty, QX);
+ assert(Unqualified ? hasSameUnqualifiedType(R, X) : hasSameType(R, X));
+ return R;
}
QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const {
@@ -12304,10 +13308,22 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
}
}
+std::vector<std::string> ASTContext::filterFunctionTargetVersionAttrs(
+ const TargetVersionAttr *TV) const {
+ assert(TV != nullptr);
+ llvm::SmallVector<StringRef, 8> Feats;
+ std::vector<std::string> ResFeats;
+ TV->getFeatures(Feats);
+ for (auto &Feature : Feats)
+ if (Target->validateCpuSupports(Feature.str()))
+ ResFeats.push_back("?" + Feature.str());
+ return ResFeats;
+}
+
ParsedTargetAttr
ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const {
assert(TD != nullptr);
- ParsedTargetAttr ParsedAttr = TD->parse();
+ ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(TD->getFeaturesStr());
llvm::erase_if(ParsedAttr.Features, [&](const std::string &Feat) {
return !Target->isValidFeatureName(StringRef{Feat}.substr(1));
@@ -12341,9 +13357,8 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
Target->getTargetOpts().FeaturesAsWritten.begin(),
Target->getTargetOpts().FeaturesAsWritten.end());
- if (ParsedAttr.Architecture != "" &&
- Target->isValidCPUName(ParsedAttr.Architecture))
- TargetCPU = ParsedAttr.Architecture;
+ if (ParsedAttr.CPU != "" && Target->isValidCPUName(ParsedAttr.CPU))
+ TargetCPU = ParsedAttr.CPU;
// Now populate the feature map, first with the TargetCPU which is either
// the default or a new one from the target attribute string. Then we'll use
@@ -12363,12 +13378,32 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
std::vector<std::string> Features;
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
- if (VersionStr.startswith("arch="))
- TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
- else if (VersionStr != "default")
- Features.push_back((StringRef{"+"} + VersionStr).str());
-
+ if (Target->getTriple().isAArch64()) {
+ // TargetClones for AArch64
+ if (VersionStr != "default") {
+ SmallVector<StringRef, 1> VersionFeatures;
+ VersionStr.split(VersionFeatures, "+");
+ for (auto &VFeature : VersionFeatures) {
+ VFeature = VFeature.trim();
+ Features.push_back((StringRef{"?"} + VFeature).str());
+ }
+ }
+ Features.insert(Features.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.end());
+ } else {
+ if (VersionStr.startswith("arch="))
+ TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
+ else if (VersionStr != "default")
+ Features.push_back((StringRef{"+"} + VersionStr).str());
+ }
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
+ } else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
+ std::vector<std::string> Feats = filterFunctionTargetVersionAttrs(TV);
+ Feats.insert(Feats.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.end());
+ Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Feats);
} else {
FeatureMap = Target->getTargetOpts().FeatureMap;
}
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 28269ec219e4..08877aa12c02 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -118,8 +118,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
if (!TST->isTypeAlias()) {
bool DesugarArgument = false;
SmallVector<TemplateArgument, 4> Args;
- for (unsigned I = 0, N = TST->getNumArgs(); I != N; ++I) {
- const TemplateArgument &Arg = TST->getArg(I);
+ for (const TemplateArgument &Arg : TST->template_arguments()) {
if (Arg.getKind() == TemplateArgument::Type)
Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(),
DesugarArgument));
@@ -228,7 +227,7 @@ break; \
desugarForDiagnostic(Context, Ty->getBaseType(), ShouldAKA);
QT = Context.getObjCObjectType(
BaseType, Ty->getTypeArgsAsWritten(),
- llvm::makeArrayRef(Ty->qual_begin(), Ty->getNumProtocols()),
+ llvm::ArrayRef(Ty->qual_begin(), Ty->getNumProtocols()),
Ty->isKindOfTypeAsWritten());
}
}
@@ -425,7 +424,7 @@ void clang::FormatASTNodeDiagnosticArgument(
Modifier = StringRef();
Argument = StringRef();
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case DiagnosticsEngine::ak_qualtype: {
assert(Modifier.empty() && Argument.empty() &&
@@ -539,7 +538,7 @@ class TemplateDiff {
bool ShowColor;
/// FromTemplateType - When single type printing is selected, this is the
- /// type to be be printed. When tree printing is selected, this type will
+ /// type to be printed. When tree printing is selected, this type will
/// show up first in the tree.
QualType FromTemplateType;
@@ -986,7 +985,7 @@ class TemplateDiff {
if (isEnd()) return;
// Set to first template argument. If not a parameter pack, done.
- TemplateArgument TA = TST->getArg(0);
+ TemplateArgument TA = TST->template_arguments()[0];
if (TA.getKind() != TemplateArgument::Pack) return;
// Start looking into the parameter pack.
@@ -1007,7 +1006,7 @@ class TemplateDiff {
/// isEnd - Returns true if the iterator is one past the end.
bool isEnd() const {
assert(TST && "InternalIterator is invalid with a null TST.");
- return Index >= TST->getNumArgs();
+ return Index >= TST->template_arguments().size();
}
/// &operator++ - Increment the iterator to the next template argument.
@@ -1027,11 +1026,11 @@ class TemplateDiff {
// Loop until a template argument is found, or the end is reached.
while (true) {
// Advance to the next template argument. Break if reached the end.
- if (++Index == TST->getNumArgs())
+ if (++Index == TST->template_arguments().size())
break;
// If the TemplateArgument is not a parameter pack, done.
- TemplateArgument TA = TST->getArg(Index);
+ TemplateArgument TA = TST->template_arguments()[Index];
if (TA.getKind() != TemplateArgument::Pack)
break;
@@ -1051,7 +1050,7 @@ class TemplateDiff {
assert(TST && "InternalIterator is invalid with a null TST.");
assert(!isEnd() && "Index exceeds number of arguments.");
if (CurrentTA == EndTA)
- return TST->getArg(Index);
+ return TST->template_arguments()[Index];
else
return *CurrentTA;
}
@@ -1684,9 +1683,24 @@ class TemplateDiff {
: FromType.getAsString(Policy);
std::string ToTypeStr = ToType.isNull() ? "(no argument)"
: ToType.getAsString(Policy);
- // Switch to canonical typename if it is better.
+ // Print without ElaboratedType sugar if it is better.
// TODO: merge this with other aka printing above.
if (FromTypeStr == ToTypeStr) {
+ const auto *FromElTy = dyn_cast<ElaboratedType>(FromType),
+ *ToElTy = dyn_cast<ElaboratedType>(ToType);
+ if (FromElTy || ToElTy) {
+ std::string FromNamedTypeStr =
+ FromElTy ? FromElTy->getNamedType().getAsString(Policy)
+ : FromTypeStr;
+ std::string ToNamedTypeStr =
+ ToElTy ? ToElTy->getNamedType().getAsString(Policy) : ToTypeStr;
+ if (FromNamedTypeStr != ToNamedTypeStr) {
+ FromTypeStr = FromNamedTypeStr;
+ ToTypeStr = ToNamedTypeStr;
+ goto PrintTypes;
+ }
+ }
+ // Switch to canonical typename if it is better.
std::string FromCanTypeStr =
FromType.getCanonicalType().getAsString(Policy);
std::string ToCanTypeStr = ToType.getCanonicalType().getAsString(Policy);
@@ -1696,6 +1710,7 @@ class TemplateDiff {
}
}
+ PrintTypes:
if (PrintTree) OS << '[';
OS << (FromDefault ? "(default) " : "");
Bold();
@@ -1877,7 +1892,7 @@ class TemplateDiff {
TPO->printAsInit(OS, Policy);
return;
}
- VD->printName(OS);
+ VD->printName(OS, Policy);
return;
}
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index c6df61f79e2e..9900efb5a48d 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -19,9 +19,37 @@
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
+
using namespace clang;
using namespace clang::comments;
+void ASTDumper::dumpInvalidDeclContext(const DeclContext *DC) {
+ NodeDumper.AddChild([=] {
+ if (!DC) {
+ ColorScope Color(OS, ShowColors, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+ // An invalid DeclContext is one for which a dyn_cast() from a DeclContext
+ // pointer to a Decl pointer would fail an assertion or otherwise fall prey
+ // to undefined behavior as a result of an invalid associated DeclKind.
+ // Such invalidity is not supposed to happen of course, but, when it does,
+ // the information provided below is intended to provide some hints about
+ // what might have gone awry.
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "DeclContext";
+ }
+ NodeDumper.dumpPointer(DC);
+ OS << " <";
+ {
+ ColorScope Color(OS, ShowColors, DeclNameColor);
+ OS << "unrecognized Decl kind " << (unsigned)DC->getDeclKind();
+ }
+ OS << ">";
+ });
+}
+
void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
NodeDumper.AddChild([=] {
OS << "StoredDeclsMap ";
@@ -96,7 +124,7 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
case TSK_ExplicitInstantiationDefinition:
if (!DumpExplicitInst)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
if (DumpRefOnly)
@@ -200,6 +228,31 @@ LLVM_DUMP_METHOD void Decl::dumpColor() const {
P.Visit(this);
}
+LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const {
+ dumpAsDecl(nullptr);
+}
+
+LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const {
+ // By design, DeclContext is required to be a base class of some class that
+ // derives from Decl. Thus, it should always be possible to dyn_cast() from
+ // a DeclContext pointer to a Decl pointer and Decl::castFromDeclContext()
+ // asserts that to be the case. Since this function is intended for use in a
+ // debugger, it performs an additional check in order to prevent a failed
+ // cast and assertion. If that check fails, then the (invalid) DeclContext
+ // is dumped with an indication of its invalidity.
+ if (hasValidDeclKind()) {
+ const auto *D = cast<Decl>(this);
+ D->dump();
+ } else {
+ // If an ASTContext is not available, a less capable ASTDumper is
+ // constructed for which color diagnostics are, regrettably, disabled.
+ ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx,
+ Ctx->getDiagnostics().getShowColors())
+ : ASTDumper(llvm::errs(), /*ShowColors*/ false);
+ P.dumpInvalidDeclContext(this);
+ }
+}
+
LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
dumpLookups(llvm::errs());
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 0273e5068371..6f367ef053d2 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -34,7 +34,6 @@
#include "clang/AST/LambdaCapture.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OperationKinds.h"
-#include "clang/AST/ParentMapContext.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -57,8 +56,6 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallVector.h"
@@ -69,6 +66,7 @@
#include <cassert>
#include <cstddef>
#include <memory>
+#include <optional>
#include <type_traits>
#include <utility>
@@ -184,13 +182,13 @@ namespace clang {
// Use this instead of Importer.importInto .
template <typename ImportT>
- LLVM_NODISCARD Error importInto(ImportT &To, const ImportT &From) {
+ [[nodiscard]] Error importInto(ImportT &To, const ImportT &From) {
return Importer.importInto(To, From);
}
// Use this to import pointers of specific type.
template <typename ImportT>
- LLVM_NODISCARD Error importInto(ImportT *&To, ImportT *From) {
+ [[nodiscard]] Error importInto(ImportT *&To, ImportT *From) {
auto ToOrErr = Importer.Import(From);
if (ToOrErr)
To = cast_or_null<ImportT>(*ToOrErr);
@@ -201,8 +199,8 @@ namespace clang {
// cast the return value to `T`.
template <typename T>
auto import(T *From)
- -> std::conditional_t<std::is_base_of<Type, T>::value,
- Expected<const T *>, Expected<T *>> {
+ -> std::conditional_t<std::is_base_of_v<Type, T>, Expected<const T *>,
+ Expected<T *>> {
auto ToOrErr = Importer.Import(From);
if (!ToOrErr)
return ToOrErr.takeError();
@@ -220,11 +218,11 @@ namespace clang {
return Importer.Import(From);
}
- // Import an Optional<T> by importing the contained T, if any.
- template<typename T>
- Expected<Optional<T>> import(Optional<T> From) {
+ // Import an std::optional<T> by importing the contained T, if any.
+ template <typename T>
+ Expected<std::optional<T>> import(std::optional<T> From) {
if (!From)
- return Optional<T>();
+ return std::nullopt;
return import(*From);
}
@@ -245,8 +243,8 @@ namespace clang {
// then to the already imported Decl. Returns a bool value set to true if
// the `FromD` had been imported before.
template <typename ToDeclT, typename FromDeclT, typename... Args>
- LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD,
- Args &&... args) {
+ [[nodiscard]] bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD,
+ Args &&...args) {
// There may be several overloads of ToDeclT::Create. We must make sure
// to call the one which would be chosen by the arguments, thus we use a
// wrapper for the overload set.
@@ -261,8 +259,8 @@ namespace clang {
// GetImportedOrCreateDecl<TypeAliasDecl>(ToTypedef, FromD, ...);
template <typename NewDeclT, typename ToDeclT, typename FromDeclT,
typename... Args>
- LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD,
- Args &&... args) {
+ [[nodiscard]] bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD,
+ Args &&...args) {
CallOverloadedCreateFun<NewDeclT> OC;
return GetImportedOrCreateSpecialDecl(ToD, OC, FromD,
std::forward<Args>(args)...);
@@ -271,9 +269,9 @@ namespace clang {
// used, e.g. CXXRecordDecl::CreateLambda .
template <typename ToDeclT, typename CreateFunT, typename FromDeclT,
typename... Args>
- LLVM_NODISCARD bool
+ [[nodiscard]] bool
GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun,
- FromDeclT *FromD, Args &&... args) {
+ FromDeclT *FromD, Args &&...args) {
if (Importer.getImportDeclErrorIfAny(FromD)) {
ToD = nullptr;
return true; // Already imported but with error.
@@ -471,9 +469,8 @@ namespace clang {
Error ImportDefinition(
ObjCProtocolDecl *From, ObjCProtocolDecl *To,
ImportDefinitionKind Kind = IDK_Default);
- Error ImportTemplateArguments(
- const TemplateArgument *FromArgs, unsigned NumFromArgs,
- SmallVectorImpl<TemplateArgument> &ToArgs);
+ Error ImportTemplateArguments(ArrayRef<TemplateArgument> FromArgs,
+ SmallVectorImpl<TemplateArgument> &ToArgs);
Expected<TemplateArgument>
ImportTemplateArgument(const TemplateArgument &From);
@@ -791,9 +788,8 @@ ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization(
return std::move(Err);
// Import template arguments.
- auto TemplArgs = FTSInfo->TemplateArguments->asArray();
- if (Error Err = ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(),
- std::get<1>(Result)))
+ if (Error Err = ImportTemplateArguments(FTSInfo->TemplateArguments->asArray(),
+ std::get<1>(Result)))
return std::move(Err);
return Result;
@@ -894,12 +890,11 @@ ASTNodeImporter::import(const TemplateArgument &From) {
case TemplateArgument::Pack: {
SmallVector<TemplateArgument, 2> ToPack;
ToPack.reserve(From.pack_size());
- if (Error Err = ImportTemplateArguments(
- From.pack_begin(), From.pack_size(), ToPack))
+ if (Error Err = ImportTemplateArguments(From.pack_elements(), ToPack))
return std::move(Err);
return TemplateArgument(
- llvm::makeArrayRef(ToPack).copy(Importer.getToContext()));
+ llvm::ArrayRef(ToPack).copy(Importer.getToContext()));
}
}
@@ -1006,7 +1001,7 @@ ASTNodeImporter::import(const Designator &D) {
template <>
Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
- VarDecl *Var = nullptr;
+ ValueDecl *Var = nullptr;
if (From.capturesVariable()) {
if (auto VarOrErr = import(From.getCapturedVar()))
Var = *VarOrErr;
@@ -1362,24 +1357,27 @@ ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
Expected<TypedefNameDecl *> ToDeclOrErr = import(T->getDecl());
if (!ToDeclOrErr)
return ToDeclOrErr.takeError();
+ ExpectedType ToUnderlyingTypeOrErr = import(T->desugar());
+ if (!ToUnderlyingTypeOrErr)
+ return ToUnderlyingTypeOrErr.takeError();
- return Importer.getToContext().getTypeDeclType(*ToDeclOrErr);
+ return Importer.getToContext().getTypedefType(*ToDeclOrErr,
+ *ToUnderlyingTypeOrErr);
}
ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) {
ExpectedExpr ToExprOrErr = import(T->getUnderlyingExpr());
if (!ToExprOrErr)
return ToExprOrErr.takeError();
-
- return Importer.getToContext().getTypeOfExprType(*ToExprOrErr);
+ return Importer.getToContext().getTypeOfExprType(*ToExprOrErr, T->getKind());
}
ExpectedType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) {
- ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType());
+ ExpectedType ToUnderlyingTypeOrErr = import(T->getUnmodifiedType());
if (!ToUnderlyingTypeOrErr)
return ToUnderlyingTypeOrErr.takeError();
-
- return Importer.getToContext().getTypeOfType(*ToUnderlyingTypeOrErr);
+ return Importer.getToContext().getTypeOfType(*ToUnderlyingTypeOrErr,
+ T->getKind());
}
ExpectedType ASTNodeImporter::VisitUsingType(const UsingType *T) {
@@ -1432,9 +1430,7 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) {
return ToTypeConstraintConcept.takeError();
SmallVector<TemplateArgument, 2> ToTemplateArgs;
- ArrayRef<TemplateArgument> FromTemplateArgs = T->getTypeConstraintArguments();
- if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(),
- FromTemplateArgs.size(),
+ if (Error Err = ImportTemplateArguments(T->getTypeConstraintArguments(),
ToTemplateArgs))
return std::move(Err);
@@ -1520,8 +1516,7 @@ ExpectedType ASTNodeImporter::VisitTemplateTypeParmType(
ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
const SubstTemplateTypeParmType *T) {
- Expected<const TemplateTypeParmType *> ReplacedOrErr =
- import(T->getReplacedParameter());
+ Expected<Decl *> ReplacedOrErr = import(T->getAssociatedDecl());
if (!ReplacedOrErr)
return ReplacedOrErr.takeError();
@@ -1530,13 +1525,13 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
return ToReplacementTypeOrErr.takeError();
return Importer.getToContext().getSubstTemplateTypeParmType(
- *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType());
+ *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(),
+ T->getPackIndex());
}
ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
const SubstTemplateTypeParmPackType *T) {
- Expected<const TemplateTypeParmType *> ReplacedOrErr =
- import(T->getReplacedParameter());
+ Expected<Decl *> ReplacedOrErr = import(T->getAssociatedDecl());
if (!ReplacedOrErr)
return ReplacedOrErr.takeError();
@@ -1545,7 +1540,7 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
return ToArgumentPack.takeError();
return Importer.getToContext().getSubstTemplateTypeParmPackType(
- *ReplacedOrErr, *ToArgumentPack);
+ *ReplacedOrErr, T->getIndex(), T->getFinal(), *ToArgumentPack);
}
ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
@@ -1555,8 +1550,8 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
return ToTemplateOrErr.takeError();
SmallVector<TemplateArgument, 2> ToTemplateArgs;
- if (Error Err = ImportTemplateArguments(
- T->getArgs(), T->getNumArgs(), ToTemplateArgs))
+ if (Error Err =
+ ImportTemplateArguments(T->template_arguments(), ToTemplateArgs))
return std::move(Err);
QualType ToCanonType;
@@ -1613,9 +1608,8 @@ ExpectedType ASTNodeImporter::VisitDependentTemplateSpecializationType(
IdentifierInfo *ToName = Importer.Import(T->getIdentifier());
SmallVector<TemplateArgument, 2> ToPack;
- ToPack.reserve(T->getNumArgs());
- if (Error Err = ImportTemplateArguments(
- T->getArgs(), T->getNumArgs(), ToPack))
+ ToPack.reserve(T->template_arguments().size());
+ if (Error Err = ImportTemplateArguments(T->template_arguments(), ToPack))
return std::move(Err);
return Importer.getToContext().getDependentTemplateSpecializationType(
@@ -2186,10 +2180,10 @@ Error ASTNodeImporter::ImportDefinition(
}
Error ASTNodeImporter::ImportTemplateArguments(
- const TemplateArgument *FromArgs, unsigned NumFromArgs,
+ ArrayRef<TemplateArgument> FromArgs,
SmallVectorImpl<TemplateArgument> &ToArgs) {
- for (unsigned I = 0; I != NumFromArgs; ++I) {
- if (auto ToOrErr = import(FromArgs[I]))
+ for (const auto &Arg : FromArgs) {
+ if (auto ToOrErr = import(Arg))
ToArgs.push_back(*ToOrErr);
else
return ToOrErr.takeError();
@@ -2417,10 +2411,10 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
// Create the "to" namespace, if needed.
NamespaceDecl *ToNamespace = MergeWithNamespace;
if (!ToNamespace) {
- if (GetImportedOrCreateDecl(
- ToNamespace, D, Importer.getToContext(), DC, D->isInline(),
- *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(),
- /*PrevDecl=*/nullptr))
+ if (GetImportedOrCreateDecl(ToNamespace, D, Importer.getToContext(), DC,
+ D->isInline(), *BeginLocOrErr, Loc,
+ Name.getAsIdentifierInfo(),
+ /*PrevDecl=*/nullptr, D->isNested()))
return ToNamespace;
ToNamespace->setRBraceLoc(*RBraceLocOrErr);
ToNamespace->setLexicalDeclContext(LexicalDC);
@@ -3179,10 +3173,10 @@ Error ASTNodeImporter::ImportTemplateInformation(
// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
- FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(),
- llvm::makeArrayRef(
- FromInfo->getTemplateArgs(), FromInfo->getNumTemplateArgs()),
- ToTAInfo))
+ FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(),
+ llvm::ArrayRef(FromInfo->getTemplateArgs(),
+ FromInfo->getNumTemplateArgs()),
+ ToTAInfo))
return Err;
ToFD->setDependentTemplateSpecialization(Importer.getToContext(),
@@ -3234,70 +3228,182 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
return false;
}
-// Returns true if the statement S has a parent declaration that has a
-// DeclContext that is inside (or equal to) DC. In a specific use case if DC is
-// a FunctionDecl, check if statement S resides in the body of the function.
+// Check if there is a declaration that has 'DC' as parent context and is
+// referenced from statement 'S' or one of its children. The search is done in
+// BFS order through children of 'S'.
static bool isAncestorDeclContextOf(const DeclContext *DC, const Stmt *S) {
- ParentMapContext &ParentC = DC->getParentASTContext().getParentMapContext();
- DynTypedNodeList Parents = ParentC.getParents(*S);
- while (!Parents.empty()) {
- if (const Decl *PD = Parents.begin()->get<Decl>())
- return isAncestorDeclContextOf(DC, PD);
- Parents = ParentC.getParents(*Parents.begin());
+ SmallVector<const Stmt *> ToProcess;
+ ToProcess.push_back(S);
+ while (!ToProcess.empty()) {
+ const Stmt *CurrentS = ToProcess.pop_back_val();
+ ToProcess.append(CurrentS->child_begin(), CurrentS->child_end());
+ if (const auto *DeclRef = dyn_cast<DeclRefExpr>(CurrentS))
+ if (const Decl *D = DeclRef->getDecl())
+ if (isAncestorDeclContextOf(DC, D))
+ return true;
}
return false;
}
-static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
- if (T.isNull())
+namespace {
+/// Check if a type has any reference to a declaration that is inside the body
+/// of a function.
+/// The \c CheckType(QualType) function should be used to determine
+/// this property.
+///
+/// The type visitor visits one type object only (not recursive).
+/// To find all referenced declarations we must discover all type objects until
+/// the canonical type is reached (walk over typedef and similar objects). This
+/// is done by loop over all "sugar" type objects. For every such type we must
+/// check all declarations that are referenced from it. For this check the
+/// visitor is used. In the visit functions all referenced declarations except
+/// the one that follows in the sugar chain (if any) must be checked. For this
+/// check the same visitor is re-used (it has no state-dependent data).
+///
+/// The visit functions have 3 possible return values:
+/// - True, found a declaration inside \c ParentDC.
+/// - False, found declarations only outside \c ParentDC and it is not possible
+/// to find more declarations (the "sugar" chain does not continue).
+/// - Empty optional value, found no declarations or only outside \c ParentDC,
+/// but it is possible to find more declarations in the type "sugar" chain.
+/// The loop over the "sugar" types can be implemented by using type visit
+/// functions only (call \c CheckType with the desugared type). With the current
+/// solution no visit function is needed if the type has only a desugared type
+/// as data.
+class IsTypeDeclaredInsideVisitor
+ : public TypeVisitor<IsTypeDeclaredInsideVisitor, std::optional<bool>> {
+public:
+ IsTypeDeclaredInsideVisitor(const FunctionDecl *ParentDC)
+ : ParentDC(ParentDC) {}
+
+ bool CheckType(QualType T) {
+ // Check the chain of "sugar" types.
+ // The "sugar" types are typedef or similar types that have the same
+ // canonical type.
+ if (std::optional<bool> Res = Visit(T.getTypePtr()))
+ return *Res;
+ QualType DsT =
+ T.getSingleStepDesugaredType(ParentDC->getParentASTContext());
+ while (DsT != T) {
+ if (std::optional<bool> Res = Visit(DsT.getTypePtr()))
+ return *Res;
+ T = DsT;
+ DsT = T.getSingleStepDesugaredType(ParentDC->getParentASTContext());
+ }
return false;
+ }
+
+ std::optional<bool> VisitTagType(const TagType *T) {
+ if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl()))
+ for (const auto &Arg : Spec->getTemplateArgs().asArray())
+ if (checkTemplateArgument(Arg))
+ return true;
+ return isAncestorDeclContextOf(ParentDC, T->getDecl());
+ }
+
+ std::optional<bool> VisitPointerType(const PointerType *T) {
+ return CheckType(T->getPointeeType());
+ }
+
+ std::optional<bool> VisitReferenceType(const ReferenceType *T) {
+ return CheckType(T->getPointeeTypeAsWritten());
+ }
+
+ std::optional<bool> VisitTypedefType(const TypedefType *T) {
+ const TypedefNameDecl *TD = T->getDecl();
+ assert(TD);
+ return isAncestorDeclContextOf(ParentDC, TD);
+ }
+
+ std::optional<bool> VisitUsingType(const UsingType *T) {
+ if (T->getFoundDecl() &&
+ isAncestorDeclContextOf(ParentDC, T->getFoundDecl()))
+ return true;
+
+ return {};
+ }
- auto CheckTemplateArgument = [FD](const TemplateArgument &Arg) {
+ std::optional<bool>
+ VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
+ for (const auto &Arg : T->template_arguments())
+ if (checkTemplateArgument(Arg))
+ return true;
+ // This type is a "sugar" to a record type, it can have a desugared type.
+ return {};
+ }
+
+ std::optional<bool> VisitConstantArrayType(const ConstantArrayType *T) {
+ if (T->getSizeExpr() && isAncestorDeclContextOf(ParentDC, T->getSizeExpr()))
+ return true;
+
+ return CheckType(T->getElementType());
+ }
+
+ std::optional<bool> VisitVariableArrayType(const VariableArrayType *T) {
+ llvm_unreachable(
+ "Variable array should not occur in deduced return type of a function");
+ }
+
+ std::optional<bool> VisitIncompleteArrayType(const IncompleteArrayType *T) {
+ llvm_unreachable("Incomplete array should not occur in deduced return type "
+ "of a function");
+ }
+
+ std::optional<bool> VisitDependentArrayType(const IncompleteArrayType *T) {
+ llvm_unreachable("Dependent array should not occur in deduced return type "
+ "of a function");
+ }
+
+private:
+ const DeclContext *const ParentDC;
+
+ bool checkTemplateArgument(const TemplateArgument &Arg) {
switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ return false;
+ case TemplateArgument::Integral:
+ return CheckType(Arg.getIntegralType());
case TemplateArgument::Type:
- return hasTypeDeclaredInsideFunction(Arg.getAsType(), FD);
+ return CheckType(Arg.getAsType());
case TemplateArgument::Expression:
- return isAncestorDeclContextOf(FD, Arg.getAsExpr());
- default:
- // FIXME: Handle other argument kinds.
+ return isAncestorDeclContextOf(ParentDC, Arg.getAsExpr());
+ case TemplateArgument::Declaration:
+ // FIXME: The declaration in this case is not allowed to be in a function?
+ return isAncestorDeclContextOf(ParentDC, Arg.getAsDecl());
+ case TemplateArgument::NullPtr:
+ // FIXME: The type is not allowed to be in the function?
+ return CheckType(Arg.getNullPtrType());
+ case TemplateArgument::Pack:
+ for (const auto &PackArg : Arg.getPackAsArray())
+ if (checkTemplateArgument(PackArg))
+ return true;
+ return false;
+ case TemplateArgument::Template:
+ // Templates can not be defined locally in functions.
+ // A template passed as argument can be not in ParentDC.
+ return false;
+ case TemplateArgument::TemplateExpansion:
+ // Templates can not be defined locally in functions.
+ // A template passed as argument can be not in ParentDC.
return false;
}
+ llvm_unreachable("Unknown TemplateArgument::ArgKind enum");
};
-
- if (const auto *RecordT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RecordT->getDecl();
- assert(RD);
- if (isAncestorDeclContextOf(FD, RD)) {
- assert(RD->getLexicalDeclContext() == RD->getDeclContext());
- return true;
- }
- if (const auto *RDTempl = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- if (llvm::count_if(RDTempl->getTemplateArgs().asArray(),
- CheckTemplateArgument))
- return true;
- // Note: It is possible that T can be get as both a RecordType and a
- // TemplateSpecializationType.
- }
- if (const auto *TST = T->getAs<TemplateSpecializationType>())
- return llvm::count_if(TST->template_arguments(), CheckTemplateArgument);
-
- return false;
-}
+};
+} // namespace
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
QualType FromTy = D->getType();
const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
assert(FromFPT && "Must be called on FunctionProtoType");
- if (const AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType())
- return hasTypeDeclaredInsideFunction(AutoT->getDeducedType(), D);
- if (const auto *TypedefT = FromFPT->getReturnType()->getAs<TypedefType>()) {
- const TypedefNameDecl *TD = TypedefT->getDecl();
- assert(TD);
- if (isAncestorDeclContextOf(D, TD)) {
- assert(TD->getLexicalDeclContext() == TD->getDeclContext());
- return true;
- }
+
+ QualType RetT = FromFPT->getReturnType();
+ if (isa<AutoType>(RetT.getTypePtr())) {
+ FunctionDecl *Def = D->getDefinition();
+ IsTypeDeclaredInsideVisitor Visitor(Def ? Def : D);
+ return Visitor.CheckType(RetT);
}
+
return false;
}
@@ -3475,6 +3581,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
auto TInfo = importChecked(Err, FromTSI);
auto ToInnerLocStart = importChecked(Err, D->getInnerLocStart());
auto ToEndLoc = importChecked(Err, D->getEndLoc());
+ auto ToDefaultLoc = importChecked(Err, D->getDefaultLoc());
auto ToQualifierLoc = importChecked(Err, D->getQualifierLoc());
auto TrailingRequiresClause =
importChecked(Err, D->getTrailingRequiresClause());
@@ -3483,7 +3590,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import the function parameters.
SmallVector<ParmVarDecl *, 8> Parameters;
- for (auto P : D->parameters()) {
+ for (auto *P : D->parameters()) {
if (Expected<ParmVarDecl *> ToPOrErr = import(P))
Parameters.push_back(*ToPOrErr);
else
@@ -3592,7 +3699,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToFunction->setDefaulted(D->isDefaulted());
ToFunction->setExplicitlyDefaulted(D->isExplicitlyDefaulted());
ToFunction->setDeletedAsWritten(D->isDeletedAsWritten());
+ ToFunction->setFriendConstraintRefersToEnclosingTemplate(
+ D->FriendConstraintRefersToEnclosingTemplate());
ToFunction->setRangeEnd(ToEndLoc);
+ ToFunction->setDefaultLoc(ToDefaultLoc);
// Set the parameters.
for (auto *Param : Parameters) {
@@ -3637,6 +3747,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
}
+ // If it is a template, import all related things.
+ if (Error Err = ImportTemplateInformation(D, ToFunction))
+ return std::move(Err);
+
if (D->doesThisDeclarationHaveABody()) {
Error Err = ImportFunctionDeclBody(D, ToFunction);
@@ -3658,10 +3772,6 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// FIXME: Other bits to merge?
- // If it is a template, import all related things.
- if (Error Err = ImportTemplateInformation(D, ToFunction))
- return std::move(Err);
-
addDeclToContexts(D, ToFunction);
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
@@ -3870,7 +3980,7 @@ static FriendCountAndPosition getFriendCountAndPosition(
const FriendDecl *FD,
llvm::function_ref<T(const FriendDecl *)> GetCanTypeOrDecl) {
unsigned int FriendCount = 0;
- llvm::Optional<unsigned int> FriendPosition;
+ std::optional<unsigned int> FriendPosition;
const auto *RD = cast<CXXRecordDecl>(FD->getLexicalDeclContext());
T TypeOrDecl = GetCanTypeOrDecl(FD);
@@ -4754,13 +4864,14 @@ ExpectedDecl ASTNodeImporter::VisitUsingEnumDecl(UsingEnumDecl *D) {
Error Err = Error::success();
auto ToUsingLoc = importChecked(Err, D->getUsingLoc());
auto ToEnumLoc = importChecked(Err, D->getEnumLoc());
- auto ToEnumDecl = importChecked(Err, D->getEnumDecl());
+ auto ToNameLoc = importChecked(Err, D->getLocation());
+ auto *ToEnumType = importChecked(Err, D->getEnumType());
if (Err)
return std::move(Err);
UsingEnumDecl *ToUsingEnum;
if (GetImportedOrCreateDecl(ToUsingEnum, D, Importer.getToContext(), DC,
- ToUsingLoc, ToEnumLoc, Loc, ToEnumDecl))
+ ToUsingLoc, ToEnumLoc, ToNameLoc, ToEnumType))
return ToUsingEnum;
ToUsingEnum->setLexicalDeclContext(LexicalDC);
@@ -5722,8 +5833,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Import template arguments.
SmallVector<TemplateArgument, 2> TemplateArgs;
- if (Error Err = ImportTemplateArguments(
- D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs))
+ if (Error Err =
+ ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs))
return std::move(Err);
// Try to find an existing specialization with these template arguments and
// template parameter list.
@@ -5804,10 +5915,10 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
CanonInjType = CanonInjType.getCanonicalType();
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
- D2, D, Importer.getToContext(), D->getTagKind(), DC,
- *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate,
- llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
- ToTAInfo, CanonInjType,
+ D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
+ *IdLocOrErr, ToTPList, ClassTemplate,
+ llvm::ArrayRef(TemplateArgs.data(), TemplateArgs.size()), ToTAInfo,
+ CanonInjType,
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
return D2;
@@ -5881,6 +5992,30 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind());
+ if (auto P = D->getInstantiatedFrom()) {
+ if (auto *CTD = P.dyn_cast<ClassTemplateDecl *>()) {
+ if (auto CTDorErr = import(CTD))
+ D2->setInstantiationOf(*CTDorErr);
+ } else {
+ auto *CTPSD = cast<ClassTemplatePartialSpecializationDecl *>(P);
+ auto CTPSDOrErr = import(CTPSD);
+ if (!CTPSDOrErr)
+ return CTPSDOrErr.takeError();
+ const TemplateArgumentList &DArgs = D->getTemplateInstantiationArgs();
+ SmallVector<TemplateArgument, 2> D2ArgsVec(DArgs.size());
+ for (unsigned I = 0; I < DArgs.size(); ++I) {
+ const TemplateArgument &DArg = DArgs[I];
+ if (auto ArgOrErr = import(DArg))
+ D2ArgsVec[I] = *ArgOrErr;
+ else
+ return ArgOrErr.takeError();
+ }
+ D2->setInstantiationOf(
+ *CTPSDOrErr,
+ TemplateArgumentList::CreateCopy(Importer.getToContext(), D2ArgsVec));
+ }
+ }
+
if (D->isCompleteDefinition())
if (Error Err = ImportDefinition(D, D2))
return std::move(Err);
@@ -6020,8 +6155,8 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
// Import template arguments.
SmallVector<TemplateArgument, 2> TemplateArgs;
- if (Error Err = ImportTemplateArguments(
- D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs))
+ if (Error Err =
+ ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs))
return std::move(Err);
// Try to find an existing specialization with these template arguments.
@@ -6044,15 +6179,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
}
}
} else {
- // Import the type.
- QualType T;
- if (Error Err = importInto(T, D->getType()))
- return std::move(Err);
-
- auto TInfoOrErr = import(D->getTypeSourceInfo());
- if (!TInfoOrErr)
- return TInfoOrErr.takeError();
-
TemplateArgumentListInfo ToTAInfo;
if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) {
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
@@ -6077,7 +6203,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
PartVarSpecDecl *ToPartial;
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
- VarTemplate, T, *TInfoOrErr,
+ VarTemplate, QualType(), nullptr,
D->getStorageClass(), TemplateArgs, ArgInfos))
return ToPartial;
@@ -6098,11 +6224,21 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
} else { // Full specialization
if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, VarTemplate,
- T, *TInfoOrErr,
- D->getStorageClass(), TemplateArgs))
+ QualType(), nullptr, D->getStorageClass(),
+ TemplateArgs))
return D2;
}
+ QualType T;
+ if (Error Err = importInto(T, D->getType()))
+ return std::move(Err);
+ D2->setType(T);
+
+ auto TInfoOrErr = import(D->getTypeSourceInfo());
+ if (!TInfoOrErr)
+ return TInfoOrErr.takeError();
+ D2->setTypeSourceInfo(*TInfoOrErr);
+
if (D->getPointOfInstantiation().isValid()) {
if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation()))
D2->setPointOfInstantiation(*POIOrErr);
@@ -6875,14 +7011,14 @@ ASTNodeImporter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
const ASTContext &ToCtx = Importer.getToContext();
if (E->isResultDependent()) {
return GenericSelectionExpr::Create(
- ToCtx, ToGenericLoc, ToControllingExpr,
- llvm::makeArrayRef(ToAssocTypes), llvm::makeArrayRef(ToAssocExprs),
- ToDefaultLoc, ToRParenLoc, E->containsUnexpandedParameterPack());
+ ToCtx, ToGenericLoc, ToControllingExpr, llvm::ArrayRef(ToAssocTypes),
+ llvm::ArrayRef(ToAssocExprs), ToDefaultLoc, ToRParenLoc,
+ E->containsUnexpandedParameterPack());
}
return GenericSelectionExpr::Create(
- ToCtx, ToGenericLoc, ToControllingExpr, llvm::makeArrayRef(ToAssocTypes),
- llvm::makeArrayRef(ToAssocExprs), ToDefaultLoc, ToRParenLoc,
+ ToCtx, ToGenericLoc, ToControllingExpr, llvm::ArrayRef(ToAssocTypes),
+ llvm::ArrayRef(ToAssocExprs), ToDefaultLoc, ToRParenLoc,
E->containsUnexpandedParameterPack(), E->getResultIndex());
}
@@ -7224,7 +7360,7 @@ ExpectedStmt ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
return BinaryOperator::Create(
Importer.getToContext(), ToLHS, ToRHS, E->getOpcode(), ToType,
E->getValueKind(), E->getObjectKind(), ToOperatorLoc,
- E->getFPFeatures(Importer.getFromContext().getLangOpts()));
+ E->getFPFeatures());
}
ExpectedStmt ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
@@ -7335,7 +7471,7 @@ ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
return CompoundAssignOperator::Create(
Importer.getToContext(), ToLHS, ToRHS, E->getOpcode(), ToType,
E->getValueKind(), E->getObjectKind(), ToOperatorLoc,
- E->getFPFeatures(Importer.getFromContext().getLangOpts()),
+ E->getFPFeatures(),
ToComputationLHSType, ToComputationResultType);
}
@@ -7544,15 +7680,23 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
// see VisitParmVarDecl).
ParmVarDecl *ToParam = *ToParamOrErr;
if (!ToParam->getDefaultArg()) {
- Optional<ParmVarDecl *> FromParam = Importer.getImportedFromDecl(ToParam);
+ std::optional<ParmVarDecl *> FromParam =
+ Importer.getImportedFromDecl(ToParam);
assert(FromParam && "ParmVarDecl was not imported?");
if (Error Err = ImportDefaultArgOfParmVarDecl(*FromParam, ToParam))
return std::move(Err);
}
-
+ Expr *RewrittenInit = nullptr;
+ if (E->hasRewrittenInit()) {
+ ExpectedExpr ExprOrErr = import(E->getRewrittenExpr());
+ if (!ExprOrErr)
+ return ExprOrErr.takeError();
+ RewrittenInit = ExprOrErr.get();
+ }
return CXXDefaultArgExpr::Create(Importer.getToContext(), *ToUsedLocOrErr,
- *ToParamOrErr, *UsedContextOrErr);
+ *ToParamOrErr, RewrittenInit,
+ *UsedContextOrErr);
}
ExpectedStmt
@@ -7670,16 +7814,14 @@ ExpectedStmt ASTNodeImporter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
if (Err)
return std::move(Err);
- Optional<unsigned> Length;
+ std::optional<unsigned> Length;
if (!E->isValueDependent())
Length = E->getPackLength();
SmallVector<TemplateArgument, 8> ToPartialArguments;
if (E->isPartiallySubstituted()) {
- if (Error Err = ImportTemplateArguments(
- E->getPartialArguments().data(),
- E->getPartialArguments().size(),
- ToPartialArguments))
+ if (Error Err = ImportTemplateArguments(E->getPartialArguments(),
+ ToPartialArguments))
return std::move(Err);
}
@@ -7806,8 +7948,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
if (!ToLocationOrErr)
return ToLocationOrErr.takeError();
- return new (Importer.getToContext()) CXXBoolLiteralExpr(
- E->getValue(), *ToTypeOrErr, *ToLocationOrErr);
+ return CXXBoolLiteralExpr::Create(Importer.getToContext(), E->getValue(),
+ *ToTypeOrErr, *ToLocationOrErr);
}
ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
@@ -7969,7 +8111,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXUnresolvedConstructExpr(
return CXXUnresolvedConstructExpr::Create(
Importer.getToContext(), ToType, ToTypeSourceInfo, ToLParenLoc,
- llvm::makeArrayRef(ToArgs), ToRParenLoc);
+ llvm::ArrayRef(ToArgs), ToRParenLoc);
}
ExpectedStmt
@@ -8246,8 +8388,16 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
ToField->setInClassInitializer(*ToInClassInitializerOrErr);
}
+ Expr *RewrittenInit = nullptr;
+ if (E->hasRewrittenInit()) {
+ ExpectedExpr ExprOrErr = import(E->getRewrittenExpr());
+ if (!ExprOrErr)
+ return ExprOrErr.takeError();
+ RewrittenInit = ExprOrErr.get();
+ }
+
return CXXDefaultInitExpr::Create(Importer.getToContext(), *ToBeginLocOrErr,
- ToField, *UsedContextOrErr);
+ ToField, *UsedContextOrErr, RewrittenInit);
}
ExpectedStmt ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
@@ -8295,14 +8445,14 @@ ExpectedStmt ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr(
Error Err = Error::success();
auto ToType = importChecked(Err, E->getType());
auto ToExprLoc = importChecked(Err, E->getExprLoc());
- auto ToParameter = importChecked(Err, E->getParameter());
+ auto ToAssociatedDecl = importChecked(Err, E->getAssociatedDecl());
auto ToReplacement = importChecked(Err, E->getReplacement());
if (Err)
return std::move(Err);
return new (Importer.getToContext()) SubstNonTypeTemplateParmExpr(
- ToType, E->getValueKind(), ToExprLoc, ToParameter,
- E->isReferenceParameter(), ToReplacement);
+ ToType, E->getValueKind(), ToExprLoc, ToReplacement, ToAssociatedDecl,
+ E->getIndex(), E->getPackIndex(), E->isReferenceParameter());
}
ExpectedStmt ASTNodeImporter::VisitTypeTraitExpr(TypeTraitExpr *E) {
@@ -8403,13 +8553,13 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTImporter::~ASTImporter() = default;
-Optional<unsigned> ASTImporter::getFieldIndex(Decl *F) {
+std::optional<unsigned> ASTImporter::getFieldIndex(Decl *F) {
assert(F && (isa<FieldDecl>(*F) || isa<IndirectFieldDecl>(*F)) &&
"Try to get field index for non-field.");
auto *Owner = dyn_cast<RecordDecl>(F->getDeclContext());
if (!Owner)
- return None;
+ return std::nullopt;
unsigned Index = 0;
for (const auto *D : Owner->decls()) {
@@ -8422,7 +8572,7 @@ Optional<unsigned> ASTImporter::getFieldIndex(Decl *F) {
llvm_unreachable("Field was not found in its parent context.");
- return None;
+ return std::nullopt;
}
ASTImporter::FoundDeclsTy
@@ -8533,6 +8683,7 @@ Expected<TypeSourceInfo *> ASTImporter::Import(TypeSourceInfo *FromTSI) {
return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr);
}
+namespace {
// To use this object, it should be created before the new attribute is created,
// and destructed after it is created. The construction already performs the
// import of the data.
@@ -8663,6 +8814,7 @@ public:
return ToAttr;
}
};
+} // namespace
Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
AttrImporter AI(*this);
@@ -9279,33 +9431,35 @@ Expected<TemplateName> ASTImporter::Import(TemplateName From) {
case TemplateName::SubstTemplateTemplateParm: {
SubstTemplateTemplateParmStorage *Subst =
From.getAsSubstTemplateTemplateParm();
- ExpectedDecl ParamOrErr = Import(Subst->getParameter());
- if (!ParamOrErr)
- return ParamOrErr.takeError();
-
auto ReplacementOrErr = Import(Subst->getReplacement());
if (!ReplacementOrErr)
return ReplacementOrErr.takeError();
+ auto AssociatedDeclOrErr = Import(Subst->getAssociatedDecl());
+ if (!AssociatedDeclOrErr)
+ return AssociatedDeclOrErr.takeError();
+
return ToContext.getSubstTemplateTemplateParm(
- cast<TemplateTemplateParmDecl>(*ParamOrErr), *ReplacementOrErr);
+ *ReplacementOrErr, *AssociatedDeclOrErr, Subst->getIndex(),
+ Subst->getPackIndex());
}
case TemplateName::SubstTemplateTemplateParmPack: {
- SubstTemplateTemplateParmPackStorage *SubstPack
- = From.getAsSubstTemplateTemplateParmPack();
- ExpectedDecl ParamOrErr = Import(SubstPack->getParameterPack());
- if (!ParamOrErr)
- return ParamOrErr.takeError();
-
+ SubstTemplateTemplateParmPackStorage *SubstPack =
+ From.getAsSubstTemplateTemplateParmPack();
ASTNodeImporter Importer(*this);
auto ArgPackOrErr =
Importer.ImportTemplateArgument(SubstPack->getArgumentPack());
if (!ArgPackOrErr)
return ArgPackOrErr.takeError();
+ auto AssociatedDeclOrErr = Import(SubstPack->getAssociatedDecl());
+ if (!AssociatedDeclOrErr)
+ return AssociatedDeclOrErr.takeError();
+
return ToContext.getSubstTemplateTemplateParmPack(
- cast<TemplateTemplateParmDecl>(*ParamOrErr), *ArgPackOrErr);
+ *ArgPackOrErr, *AssociatedDeclOrErr, SubstPack->getIndex(),
+ SubstPack->getFinal());
}
case TemplateName::UsingTemplate: {
auto UsingOrError = Import(From.getAsUsingShadowDecl());
@@ -9410,7 +9564,7 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
if (ToID.isInvalid() || IsBuiltin) {
// FIXME: We want to re-use the existing MemoryBuffer!
- llvm::Optional<llvm::MemoryBufferRef> FromBuf =
+ std::optional<llvm::MemoryBufferRef> FromBuf =
Cache->getBufferOrNone(FromContext.getDiagnostics(),
FromSM.getFileManager(), SourceLocation{});
if (!FromBuf)
@@ -9879,13 +10033,13 @@ Decl *ASTImporter::MapImported(Decl *From, Decl *To) {
return To;
}
-llvm::Optional<ASTImportError>
+std::optional<ASTImportError>
ASTImporter::getImportDeclErrorIfAny(Decl *FromD) const {
auto Pos = ImportDeclErrors.find(FromD);
if (Pos != ImportDeclErrors.end())
return Pos->second;
else
- return Optional<ASTImportError>();
+ return std::nullopt;
}
void ASTImporter::setImportDeclError(Decl *From, ASTImportError Error) {
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index d80fc3ce7292..ba7dfc35edf2 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -84,13 +84,12 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
+#include <optional>
#include <utility>
using namespace clang;
@@ -103,6 +102,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateArgument &Arg1,
const TemplateArgument &Arg2);
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgumentLoc &Arg1,
+ const TemplateArgumentLoc &Arg2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
NestedNameSpecifier *NNS1,
NestedNameSpecifier *NNS2);
static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
@@ -238,8 +240,8 @@ class StmtComparer {
const GenericSelectionExpr *E2) {
for (auto Pair : zip_longest(E1->getAssocTypeSourceInfos(),
E2->getAssocTypeSourceInfos())) {
- Optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
- Optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
+ std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
+ std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
// Skip this case if there are a different number of associated types.
if (!Child1 || !Child2)
return false;
@@ -289,8 +291,14 @@ class StmtComparer {
bool IsStmtEquivalent(const SubstNonTypeTemplateParmExpr *E1,
const SubstNonTypeTemplateParmExpr *E2) {
- return IsStructurallyEquivalent(Context, E1->getParameter(),
- E2->getParameter());
+ if (!IsStructurallyEquivalent(Context, E1->getAssociatedDecl(),
+ E2->getAssociatedDecl()))
+ return false;
+ if (E1->getIndex() != E2->getIndex())
+ return false;
+ if (E1->getPackIndex() != E2->getPackIndex())
+ return false;
+ return true;
}
bool IsStmtEquivalent(const SubstNonTypeTemplateParmPackExpr *E1,
@@ -304,8 +312,8 @@ class StmtComparer {
return false;
for (auto Pair : zip_longest(E1->getArgs(), E2->getArgs())) {
- Optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
- Optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
+ std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
+ std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
// Different number of args.
if (!Child1 || !Child2)
return false;
@@ -334,6 +342,30 @@ class StmtComparer {
return true;
}
+ bool IsStmtEquivalent(const OverloadExpr *E1, const OverloadExpr *E2) {
+ if (!IsStructurallyEquivalent(Context, E1->getName(), E2->getName()))
+ return false;
+
+ if (static_cast<bool>(E1->getQualifier()) !=
+ static_cast<bool>(E2->getQualifier()))
+ return false;
+ if (E1->getQualifier() &&
+ !IsStructurallyEquivalent(Context, E1->getQualifier(),
+ E2->getQualifier()))
+ return false;
+
+ if (E1->getNumTemplateArgs() != E2->getNumTemplateArgs())
+ return false;
+ const TemplateArgumentLoc *Args1 = E1->getTemplateArgs();
+ const TemplateArgumentLoc *Args2 = E2->getTemplateArgs();
+ for (unsigned int ArgI = 0, ArgN = E1->getNumTemplateArgs(); ArgI < ArgN;
+ ++ArgI)
+ if (!IsStructurallyEquivalent(Context, Args1[ArgI], Args2[ArgI]))
+ return false;
+
+ return true;
+ }
+
/// End point of the traversal chain.
bool TraverseStmt(const Stmt *S1, const Stmt *S2) { return true; }
@@ -394,8 +426,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
// Iterate over the children of both statements and also compare them.
for (auto Pair : zip_longest(S1->children(), S2->children())) {
- Optional<const Stmt *> Child1 = std::get<0>(Pair);
- Optional<const Stmt *> Child2 = std::get<1>(Pair);
+ std::optional<const Stmt *> Child1 = std::get<0>(Pair);
+ std::optional<const Stmt *> Child2 = std::get<1>(Pair);
// One of the statements has a different amount of children than the other,
// so the statements can't be equivalent.
if (!Child1 || !Child2)
@@ -510,8 +542,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
*P2 = N2.getAsSubstTemplateTemplateParmPack();
return IsStructurallyEquivalent(Context, P1->getArgumentPack(),
P2->getArgumentPack()) &&
- IsStructurallyEquivalent(Context, P1->getParameterPack(),
- P2->getParameterPack());
+ IsStructurallyEquivalent(Context, P1->getAssociatedDecl(),
+ P2->getAssociatedDecl()) &&
+ P1->getIndex() == P2->getIndex();
}
case TemplateName::Template:
@@ -526,6 +559,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ ArrayRef<TemplateArgument> Args1,
+ ArrayRef<TemplateArgument> Args2);
+
/// Determine whether two template arguments are equivalent.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateArgument &Arg1,
@@ -568,18 +605,32 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Arg2.getAsExpr());
case TemplateArgument::Pack:
- if (Arg1.pack_size() != Arg2.pack_size())
- return false;
+ return IsStructurallyEquivalent(Context, Arg1.pack_elements(),
+ Arg2.pack_elements());
+ }
- for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I)
- if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I],
- Arg2.pack_begin()[I]))
- return false;
+ llvm_unreachable("Invalid template argument kind");
+}
- return true;
+/// Determine structural equivalence of two template argument lists.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ ArrayRef<TemplateArgument> Args1,
+ ArrayRef<TemplateArgument> Args2) {
+ if (Args1.size() != Args2.size())
+ return false;
+ for (unsigned I = 0, N = Args1.size(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Args1[I], Args2[I]))
+ return false;
}
+ return true;
+}
- llvm_unreachable("Invalid template argument kind");
+/// Determine whether two template argument locations are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgumentLoc &Arg1,
+ const TemplateArgumentLoc &Arg2) {
+ return IsStructurallyEquivalent(Context, Arg1.getArgument(),
+ Arg2.getArgument());
}
/// Determine structural equivalence for the common part of array
@@ -900,7 +951,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
// Fall through to check the bits common with FunctionNoProtoType.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case Type::FunctionNoProto: {
@@ -957,11 +1008,17 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(),
cast<UsingType>(T2)->getFoundDecl()))
return false;
+ if (!IsStructurallyEquivalent(Context,
+ cast<UsingType>(T1)->getUnderlyingType(),
+ cast<UsingType>(T2)->getUnderlyingType()))
+ return false;
break;
case Type::Typedef:
if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
- cast<TypedefType>(T2)->getDecl()))
+ cast<TypedefType>(T2)->getDecl()) ||
+ !IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->desugar(),
+ cast<TypedefType>(T2)->desugar()))
return false;
break;
@@ -974,8 +1031,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::TypeOf:
if (!IsStructurallyEquivalent(Context,
- cast<TypeOfType>(T1)->getUnderlyingType(),
- cast<TypeOfType>(T2)->getUnderlyingType()))
+ cast<TypeOfType>(T1)->getUnmodifiedType(),
+ cast<TypeOfType>(T2)->getUnmodifiedType()))
return false;
break;
@@ -1005,16 +1062,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Auto1->getTypeConstraintConcept() !=
Auto2->getTypeConstraintConcept())
return false;
- ArrayRef<TemplateArgument> Auto1Args =
- Auto1->getTypeConstraintArguments();
- ArrayRef<TemplateArgument> Auto2Args =
- Auto2->getTypeConstraintArguments();
- if (Auto1Args.size() != Auto2Args.size())
+ if (!IsStructurallyEquivalent(Context,
+ Auto1->getTypeConstraintArguments(),
+ Auto2->getTypeConstraintArguments()))
return false;
- for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
- return false;
- }
}
break;
}
@@ -1055,22 +1106,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::SubstTemplateTypeParm: {
const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1);
const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
- return false;
if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
Subst2->getReplacementType()))
return false;
+ if (!IsStructurallyEquivalent(Context, Subst1->getAssociatedDecl(),
+ Subst2->getAssociatedDecl()))
+ return false;
+ if (Subst1->getIndex() != Subst2->getIndex())
+ return false;
+ if (Subst1->getPackIndex() != Subst2->getPackIndex())
+ return false;
break;
}
case Type::SubstTemplateTypeParmPack: {
const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
+ if (!IsStructurallyEquivalent(Context, Subst1->getAssociatedDecl(),
+ Subst2->getAssociatedDecl()))
+ return false;
+ if (Subst1->getIndex() != Subst2->getIndex())
return false;
if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
Subst2->getArgumentPack()))
@@ -1084,13 +1139,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
Spec2->getTemplateName()))
return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),
+ Spec2->template_arguments()))
return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
- Spec2->getArg(I)))
- return false;
- }
break;
}
@@ -1141,13 +1192,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
Spec2->getIdentifier()))
return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),
+ Spec2->template_arguments()))
return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
- Spec2->getArg(I)))
- return false;
- }
break;
}
@@ -1434,9 +1481,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!D1->getDeclName() && !D2->getDeclName()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (Optional<unsigned> Index1 =
+ if (std::optional<unsigned> Index1 =
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {
- if (Optional<unsigned> Index2 =
+ if (std::optional<unsigned> Index2 =
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
D2)) {
if (*Index1 != *Index2)
@@ -2108,14 +2155,14 @@ DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
return ToCtx.getDiagnostics().Report(Loc, DiagID);
}
-Optional<unsigned>
+std::optional<unsigned>
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
ASTContext &Context = Anon->getASTContext();
QualType AnonTy = Context.getRecordType(Anon);
const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
if (!Owner)
- return None;
+ return std::nullopt;
unsigned Index = 0;
for (const auto *D : Owner->noload_decls()) {
diff --git a/clang/lib/AST/AttrDocTable.cpp b/clang/lib/AST/AttrDocTable.cpp
index 3bfedac8b8f1..df7e3d63a6c3 100644
--- a/clang/lib/AST/AttrDocTable.cpp
+++ b/clang/lib/AST/AttrDocTable.cpp
@@ -21,7 +21,7 @@ static const llvm::StringRef AttrDoc[] = {
};
llvm::StringRef clang::Attr::getDocumentation(clang::attr::Kind K) {
- if(K < llvm::array_lengthof(AttrDoc))
+ if (K < std::size(AttrDoc))
return AttrDoc[K];
return "";
}
diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp
index deb28bee5ed8..0adcca7731d9 100644
--- a/clang/lib/AST/AttrImpl.cpp
+++ b/clang/lib/AST/AttrImpl.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
+#include <optional>
using namespace clang;
void LoopHintAttr::printPrettyPragma(raw_ostream &OS,
@@ -137,7 +138,7 @@ void OMPDeclareTargetDeclAttr::printPrettyPragma(
// Use fake syntax because it is for testing and debugging purpose only.
if (getDevType() != DT_Any)
OS << " device_type(" << ConvertDevTypeTyToStr(getDevType()) << ")";
- if (getMapType() != MT_To)
+ if (getMapType() != MT_To && getMapType() != MT_Enter)
OS << ' ' << ConvertMapTypeTyToStr(getMapType());
if (Expr *E = getIndirectExpr()) {
OS << " indirect(";
@@ -148,10 +149,10 @@ void OMPDeclareTargetDeclAttr::printPrettyPragma(
}
}
-llvm::Optional<OMPDeclareTargetDeclAttr *>
+std::optional<OMPDeclareTargetDeclAttr *>
OMPDeclareTargetDeclAttr::getActiveAttr(const ValueDecl *VD) {
if (!VD->hasAttrs())
- return llvm::None;
+ return std::nullopt;
unsigned Level = 0;
OMPDeclareTargetDeclAttr *FoundAttr = nullptr;
for (auto *Attr : VD->specific_attrs<OMPDeclareTargetDeclAttr>()) {
@@ -162,31 +163,31 @@ OMPDeclareTargetDeclAttr::getActiveAttr(const ValueDecl *VD) {
}
if (FoundAttr)
return FoundAttr;
- return llvm::None;
+ return std::nullopt;
}
-llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
+std::optional<OMPDeclareTargetDeclAttr::MapTypeTy>
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(const ValueDecl *VD) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.value()->getMapType();
- return llvm::None;
+ return (*ActiveAttr)->getMapType();
+ return std::nullopt;
}
-llvm::Optional<OMPDeclareTargetDeclAttr::DevTypeTy>
+std::optional<OMPDeclareTargetDeclAttr::DevTypeTy>
OMPDeclareTargetDeclAttr::getDeviceType(const ValueDecl *VD) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.value()->getDevType();
- return llvm::None;
+ return (*ActiveAttr)->getDevType();
+ return std::nullopt;
}
-llvm::Optional<SourceLocation>
+std::optional<SourceLocation>
OMPDeclareTargetDeclAttr::getLocation(const ValueDecl *VD) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.value()->getRange().getBegin();
- return llvm::None;
+ return (*ActiveAttr)->getRange().getBegin();
+ return std::nullopt;
}
namespace clang {
@@ -222,18 +223,18 @@ void OMPDeclareVariantAttr::printPrettyPragma(
OS << ")";
}
- auto PrintInteropTypes = [&OS](InteropType *Begin, InteropType *End) {
- for (InteropType *I = Begin; I != End; ++I) {
+ auto PrintInteropInfo = [&OS](OMPInteropInfo *Begin, OMPInteropInfo *End) {
+ for (OMPInteropInfo *I = Begin; I != End; ++I) {
if (I != Begin)
OS << ", ";
OS << "interop(";
- OS << ConvertInteropTypeToStr(*I);
+ OS << getInteropTypeString(I);
OS << ")";
}
};
if (appendArgs_size()) {
OS << " append_args(";
- PrintInteropTypes(appendArgs_begin(), appendArgs_end());
+ PrintInteropInfo(appendArgs_begin(), appendArgs_end());
OS << ")";
}
}
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index 96a6f344be7c..1abbe8139ae9 100644
--- a/clang/lib/AST/CXXInheritance.cpp
+++ b/clang/lib/AST/CXXInheritance.cpp
@@ -22,7 +22,6 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp
index 43820fc566e4..2bb6bb5cbcb6 100644
--- a/clang/lib/AST/Comment.cpp
+++ b/clang/lib/AST/Comment.cpp
@@ -29,7 +29,7 @@ namespace comments {
#undef ABSTRACT_COMMENT
// DeclInfo is also allocated with a BumpPtrAllocator.
-static_assert(std::is_trivially_destructible<DeclInfo>::value,
+static_assert(std::is_trivially_destructible_v<DeclInfo>,
"DeclInfo should be trivially destructible!");
const char *Comment::getCommentKindName() const {
@@ -206,7 +206,7 @@ void DeclInfo::fill() {
IsInstanceMethod = false;
IsClassMethod = false;
IsVariadic = false;
- ParamVars = None;
+ ParamVars = std::nullopt;
TemplateParameters = nullptr;
if (!CommentDecl) {
@@ -301,7 +301,7 @@ void DeclInfo::fill() {
TemplateKind = TemplateSpecialization;
TemplateParameters = VTD->getTemplateParameters();
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Decl::Field:
case Decl::EnumConstant:
case Decl::ObjCIvar:
diff --git a/clang/lib/AST/CommentCommandTraits.cpp b/clang/lib/AST/CommentCommandTraits.cpp
index bdc0dd47fb7d..a37a0e18432c 100644
--- a/clang/lib/AST/CommentCommandTraits.cpp
+++ b/clang/lib/AST/CommentCommandTraits.cpp
@@ -16,8 +16,8 @@ namespace comments {
#include "clang/AST/CommentCommandInfo.inc"
CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
- const CommentOptions &CommentOptions) :
- NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
+ const CommentOptions &CommentOptions)
+ : NextID(std::size(Commands)), Allocator(Allocator) {
registerCommentOptions(CommentOptions);
}
@@ -115,7 +115,7 @@ const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
const CommandInfo *CommandTraits::getBuiltinCommandInfo(
unsigned CommandID) {
- if (CommandID < llvm::array_lengthof(Commands))
+ if (CommandID < std::size(Commands))
return &Commands[CommandID];
return nullptr;
}
@@ -131,7 +131,7 @@ const CommandInfo *CommandTraits::getRegisteredCommandInfo(
const CommandInfo *CommandTraits::getRegisteredCommandInfo(
unsigned CommandID) const {
- return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)];
+ return RegisteredCommands[CommandID - std::size(Commands)];
}
} // end namespace comments
diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp
index 61ce8979f13f..f0250fc9fd55 100644
--- a/clang/lib/AST/CommentLexer.cpp
+++ b/clang/lib/AST/CommentLexer.cpp
@@ -701,7 +701,7 @@ void Lexer::lexHTMLStartTag(Token &T) {
C = *BufferPtr;
if (!isHTMLIdentifierStartingCharacter(C) &&
- C != '=' && C != '\"' && C != '\'' && C != '>') {
+ C != '=' && C != '\"' && C != '\'' && C != '>' && C != '/') {
State = LS_Normal;
return;
}
diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp
index 7bac1fb99b88..8adfd85d0160 100644
--- a/clang/lib/AST/CommentParser.cpp
+++ b/clang/lib/AST/CommentParser.cpp
@@ -245,7 +245,7 @@ public:
Pos.CurToken++;
}
- P.putBack(llvm::makeArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));
+ P.putBack(llvm::ArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));
Pos.CurToken = Toks.size();
if (HavePartialTok)
@@ -301,7 +301,7 @@ Parser::parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs) {
ParsedArgs++;
}
- return llvm::makeArrayRef(Args, ParsedArgs);
+ return llvm::ArrayRef(Args, ParsedArgs);
}
BlockCommandComment *Parser::parseBlockCommand() {
@@ -334,7 +334,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
if (isTokBlockCommand()) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
- ParagraphComment *Paragraph = S.actOnParagraphComment(None);
+ ParagraphComment *Paragraph = S.actOnParagraphComment(std::nullopt);
if (PC) {
S.actOnParamCommandFinish(PC, Paragraph);
return PC;
@@ -376,7 +376,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
ParagraphComment *Paragraph;
if (EmptyParagraph)
- Paragraph = S.actOnParagraphComment(None);
+ Paragraph = S.actOnParagraphComment(std::nullopt);
else {
BlockContentComment *Block = parseParagraphOrBlockCommand();
// Since we have checked for a block command, we should have parsed a
@@ -467,16 +467,14 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
}
case tok::html_greater:
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
Tok.getLocation(),
/* IsSelfClosing = */ false);
consumeToken();
return HST;
case tok::html_slash_greater:
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
Tok.getLocation(),
/* IsSelfClosing = */ true);
consumeToken();
@@ -494,16 +492,14 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
Tok.is(tok::html_slash_greater))
continue;
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
SourceLocation(),
/* IsSelfClosing = */ false);
return HST;
default:
// Not a token from an HTML start tag. Thus HTML tag prematurely ended.
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
SourceLocation(),
/* IsSelfClosing = */ false);
bool StartLineInvalid;
@@ -642,7 +638,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
break;
}
- return S.actOnParagraphComment(S.copyArray(llvm::makeArrayRef(Content)));
+ return S.actOnParagraphComment(S.copyArray(llvm::ArrayRef(Content)));
}
VerbatimBlockComment *Parser::parseVerbatimBlock() {
@@ -679,14 +675,13 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() {
if (Tok.is(tok::verbatim_block_end)) {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID());
- S.actOnVerbatimBlockFinish(VB, Tok.getLocation(),
- Info->Name,
- S.copyArray(llvm::makeArrayRef(Lines)));
+ S.actOnVerbatimBlockFinish(VB, Tok.getLocation(), Info->Name,
+ S.copyArray(llvm::ArrayRef(Lines)));
consumeToken();
} else {
// Unterminated \\verbatim block
S.actOnVerbatimBlockFinish(VB, SourceLocation(), "",
- S.copyArray(llvm::makeArrayRef(Lines)));
+ S.copyArray(llvm::ArrayRef(Lines)));
}
return VB;
@@ -762,7 +757,7 @@ FullComment *Parser::parseFullComment() {
while (Tok.is(tok::newline))
consumeToken();
}
- return S.actOnFullComment(S.copyArray(llvm::makeArrayRef(Blocks)));
+ return S.actOnFullComment(S.copyArray(llvm::ArrayRef(Blocks)));
}
} // end namespace comments
diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp
index 9b0f03445888..a4250c0b7cbb 100644
--- a/clang/lib/AST/CommentSema.cpp
+++ b/clang/lib/AST/CommentSema.cpp
@@ -267,7 +267,7 @@ void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
}
auto *A = new (Allocator)
Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
- Command->setArgs(llvm::makeArrayRef(A, 1));
+ Command->setArgs(llvm::ArrayRef(A, 1));
}
void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
@@ -303,7 +303,7 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
auto *A = new (Allocator)
Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
- Command->setArgs(llvm::makeArrayRef(A, 1));
+ Command->setArgs(llvm::ArrayRef(A, 1));
if (!isTemplateOrSpecialization()) {
// We already warned that this \\tparam is not attached to a template decl.
@@ -314,7 +314,7 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
ThisDeclInfo->TemplateParameters;
SmallVector<unsigned, 2> Position;
if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
- Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
+ Command->setPosition(copyArray(llvm::ArrayRef(Position)));
TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
if (PrevCommand) {
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
diff --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp
index a42960ad3c7f..58411201c3b0 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -17,10 +17,11 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
-Optional<ComparisonCategoryType>
+std::optional<ComparisonCategoryType>
clang::getComparisonCategoryForBuiltinCmp(QualType T) {
using CCT = ComparisonCategoryType;
@@ -37,7 +38,7 @@ clang::getComparisonCategoryForBuiltinCmp(QualType T) {
return CCT::StrongOrdering;
// TODO: Extend support for operator<=> to ObjC types.
- return llvm::None;
+ return std::nullopt;
}
bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 1f573346b441..eb9afbdb1c87 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -573,7 +573,7 @@ ExprDependence clang::computeDependence(RecoveryExpr *E) {
// - type-dependent if we don't know the type (fallback to an opaque
// dependent type), or the type is known and dependent, or it has
// type-dependent subexpressions.
- auto D = toExprDependenceForImpliedType(E->getType()->getDependence()) |
+ auto D = toExprDependenceAsWritten(E->getType()->getDependence()) |
ExprDependence::ErrorDependent;
// FIXME: remove the type-dependent bit from subexpressions, if the
// RecoveryExpr has a non-dependent type.
@@ -594,7 +594,7 @@ ExprDependence clang::computeDependence(PredefinedExpr *E) {
ExprDependence clang::computeDependence(CallExpr *E,
llvm::ArrayRef<Expr *> PreArgs) {
auto D = E->getCallee()->getDependence();
- for (auto *A : llvm::makeArrayRef(E->getArgs(), E->getNumArgs())) {
+ for (auto *A : llvm::ArrayRef(E->getArgs(), E->getNumArgs())) {
if (A)
D |= A->getDependence();
}
@@ -642,7 +642,7 @@ ExprDependence clang::computeDependence(InitListExpr *E) {
ExprDependence clang::computeDependence(ShuffleVectorExpr *E) {
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
- for (auto *C : llvm::makeArrayRef(E->getSubExprs(), E->getNumSubExprs()))
+ for (auto *C : llvm::ArrayRef(E->getSubExprs(), E->getNumSubExprs()))
D |= C->getDependence();
return D;
}
@@ -686,7 +686,7 @@ ExprDependence clang::computeDependence(PseudoObjectExpr *O) {
ExprDependence clang::computeDependence(AtomicExpr *A) {
auto D = ExprDependence::None;
- for (auto *E : llvm::makeArrayRef(A->getSubExprs(), A->getNumSubExprs()))
+ for (auto *E : llvm::ArrayRef(A->getSubExprs(), A->getNumSubExprs()))
D |= E->getDependence();
return D;
}
@@ -831,6 +831,13 @@ ExprDependence clang::computeDependence(CXXFoldExpr *E) {
return D;
}
+ExprDependence clang::computeDependence(CXXParenListInitExpr *E) {
+ auto D = ExprDependence::None;
+ for (const auto *A : E->getInitExprs())
+ D |= A->getDependence();
+ return D;
+}
+
ExprDependence clang::computeDependence(TypeTraitExpr *E) {
auto D = ExprDependence::None;
for (const auto *A : E->getArgs())
@@ -853,7 +860,10 @@ ExprDependence clang::computeDependence(ConceptSpecializationExpr *E,
ExprDependence D =
ValueDependent ? ExprDependence::Value : ExprDependence::None;
- return D | toExprDependence(TA);
+ auto Res = D | toExprDependence(TA);
+ if(!ValueDependent && E->getSatisfaction().ContainsErrors)
+ Res |= ExprDependence::Error;
+ return Res;
}
ExprDependence clang::computeDependence(ObjCArrayLiteral *E) {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index aaba4345587b..e60cc28f6e0f 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -54,8 +54,6 @@
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -69,6 +67,7 @@
#include <cstddef>
#include <cstring>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <type_traits>
@@ -170,8 +169,8 @@ withExplicitVisibilityAlready(LVComputationKind Kind) {
return Kind;
}
-static Optional<Visibility> getExplicitVisibility(const NamedDecl *D,
- LVComputationKind kind) {
+static std::optional<Visibility> getExplicitVisibility(const NamedDecl *D,
+ LVComputationKind kind) {
assert(!kind.IgnoreExplicitVisibility &&
"asking for explicit visibility when we shouldn't be");
return D->getExplicitVisibility(kind.getExplicitVisibilityKind());
@@ -187,8 +186,8 @@ static bool usesTypeVisibility(const NamedDecl *D) {
/// Does the given declaration have member specialization information,
/// and if so, is it an explicit specialization?
-template <class T> static typename
-std::enable_if<!std::is_base_of<RedeclarableTemplateDecl, T>::value, bool>::type
+template <class T>
+static std::enable_if_t<!std::is_base_of_v<RedeclarableTemplateDecl, T>, bool>
isExplicitMemberSpecialization(const T *D) {
if (const MemberSpecializationInfo *member =
D->getMemberSpecializationInfo()) {
@@ -220,8 +219,8 @@ static Visibility getVisibilityFromAttr(const T *attr) {
}
/// Return the explicit visibility of the given declaration.
-static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
- NamedDecl::ExplicitVisibilityKind kind) {
+static std::optional<Visibility>
+getVisibilityOf(const NamedDecl *D, NamedDecl::ExplicitVisibilityKind kind) {
// If we're ultimately computing the visibility of a type, look for
// a 'type_visibility' attribute before looking for 'visibility'.
if (kind == NamedDecl::VisibilityForType) {
@@ -235,7 +234,7 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
return getVisibilityFromAttr(A);
}
- return None;
+ return std::nullopt;
}
LinkageInfo LinkageComputer::getLVForType(const Type &T,
@@ -729,7 +728,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
LinkageInfo LV = getExternalLinkageFor(D);
if (!hasExplicitVisibilityAlready(computation)) {
- if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) {
+ if (std::optional<Visibility> Vis = getExplicitVisibility(D, computation)) {
LV.mergeVisibility(*Vis, true);
} else {
// If we're declared in a namespace with a visibility attribute,
@@ -739,7 +738,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
DC = DC->getParent()) {
const auto *ND = dyn_cast<NamespaceDecl>(DC);
if (!ND) continue;
- if (Optional<Visibility> Vis = getExplicitVisibility(ND, computation)) {
+ if (std::optional<Visibility> Vis =
+ getExplicitVisibility(ND, computation)) {
LV.mergeVisibility(*Vis, true);
break;
}
@@ -834,6 +834,15 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Function->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
+ // OpenMP target declare device functions are not callable from the host so
+ // they should not be exported from the device image. This applies to all
+ // functions as the host-callable kernel functions are emitted at codegen.
+ if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice &&
+ ((Context.getTargetInfo().getTriple().isAMDGPU() ||
+ Context.getTargetInfo().getTriple().isNVPTX()) ||
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(Function)))
+ LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false);
+
// Note that Sema::MergeCompatibleFunctionDecls already takes care of
// merging storage classes and visibility attributes, so we don't have to
// look at previous decls in here.
@@ -956,7 +965,7 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
// If we have an explicit visibility attribute, merge that in.
if (!hasExplicitVisibilityAlready(computation)) {
- if (Optional<Visibility> Vis = getExplicitVisibility(D, computation))
+ if (std::optional<Visibility> Vis = getExplicitVisibility(D, computation))
LV.mergeVisibility(*Vis, true);
// If we're paying attention to global visibility, apply
// -finline-visibility-hidden if this is an inline method.
@@ -1012,6 +1021,16 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
explicitSpecSuppressor = MD;
}
+ // OpenMP target declare device functions are not callable from the host so
+ // they should not be exported from the device image. This applies to all
+ // functions as the host-callable kernel functions are emitted at codegen.
+ ASTContext &Context = D->getASTContext();
+ if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice &&
+ ((Context.getTargetInfo().getTriple().isAMDGPU() ||
+ Context.getTargetInfo().getTriple().isNVPTX()) ||
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(MD)))
+ LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false);
+
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
if (const auto *spec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
mergeTemplateLV(LV, spec, computation);
@@ -1158,14 +1177,14 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const {
return LinkageComputer{}.getDeclLinkageAndVisibility(this);
}
-static Optional<Visibility>
+static std::optional<Visibility>
getExplicitVisibilityAux(const NamedDecl *ND,
NamedDecl::ExplicitVisibilityKind kind,
bool IsMostRecent) {
assert(!IsMostRecent || ND == ND->getMostRecentDecl());
// Check the declaration itself first.
- if (Optional<Visibility> V = getVisibilityOf(ND, kind))
+ if (std::optional<Visibility> V = getVisibilityOf(ND, kind))
return V;
// If this is a member class of a specialization of a class template
@@ -1185,11 +1204,11 @@ getExplicitVisibilityAux(const NamedDecl *ND,
const auto *TD = spec->getSpecializedTemplate()->getTemplatedDecl();
while (TD != nullptr) {
auto Vis = getVisibilityOf(TD, kind);
- if (Vis != None)
+ if (Vis != std::nullopt)
return Vis;
TD = TD->getPreviousDecl();
}
- return None;
+ return std::nullopt;
}
// Use the most recent declaration.
@@ -1210,7 +1229,7 @@ getExplicitVisibilityAux(const NamedDecl *ND,
return getVisibilityOf(VTSD->getSpecializedTemplate()->getTemplatedDecl(),
kind);
- return None;
+ return std::nullopt;
}
// Also handle function template specializations.
if (const auto *fn = dyn_cast<FunctionDecl>(ND)) {
@@ -1227,17 +1246,17 @@ getExplicitVisibilityAux(const NamedDecl *ND,
if (InstantiatedFrom)
return getVisibilityOf(InstantiatedFrom, kind);
- return None;
+ return std::nullopt;
}
// The visibility of a template is stored in the templated decl.
if (const auto *TD = dyn_cast<TemplateDecl>(ND))
return getVisibilityOf(TD->getTemplatedDecl(), kind);
- return None;
+ return std::nullopt;
}
-Optional<Visibility>
+std::optional<Visibility>
NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
return getExplicitVisibilityAux(this, kind, false);
}
@@ -1252,8 +1271,13 @@ LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC,
else if (isa<ParmVarDecl>(ContextDecl))
Owner =
dyn_cast<NamedDecl>(ContextDecl->getDeclContext()->getRedeclContext());
- else
+ else if (isa<ImplicitConceptSpecializationDecl>(ContextDecl)) {
+ // Replace with the concept's owning decl, which is either a namespace or a
+ // TU, so this needs a dyn_cast.
+ Owner = dyn_cast<NamedDecl>(ContextDecl->getDeclContext());
+ } else {
Owner = cast<NamedDecl>(ContextDecl);
+ }
if (!Owner)
return LinkageInfo::none();
@@ -1289,7 +1313,7 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D,
LinkageInfo LV;
if (!hasExplicitVisibilityAlready(computation)) {
- if (Optional<Visibility> Vis =
+ if (std::optional<Visibility> Vis =
getExplicitVisibility(Function, computation))
LV.mergeVisibility(*Vis, true);
}
@@ -1310,7 +1334,8 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D,
if (Var->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
else if (!hasExplicitVisibilityAlready(computation)) {
- if (Optional<Visibility> Vis = getExplicitVisibility(Var, computation))
+ if (std::optional<Visibility> Vis =
+ getExplicitVisibility(Var, computation))
LV.mergeVisibility(*Vis, true);
}
@@ -1505,7 +1530,7 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D,
if (computation.IgnoreAllVisibility && D->hasCachedLinkage())
return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
- if (llvm::Optional<LinkageInfo> LI = lookup(D, computation))
+ if (std::optional<LinkageInfo> LI = lookup(D, computation))
return *LI;
LinkageInfo LV = computeLVForDecl(D, computation);
@@ -1527,7 +1552,7 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D,
// that all other computed linkages match, check that the one we just
// computed also does.
NamedDecl *Old = nullptr;
- for (auto I : D->redecls()) {
+ for (auto *I : D->redecls()) {
auto *T = cast<NamedDecl>(I);
if (T == D)
continue;
@@ -1601,8 +1626,12 @@ Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const {
llvm_unreachable("unknown module kind");
}
-void NamedDecl::printName(raw_ostream &os) const {
- os << Name;
+void NamedDecl::printName(raw_ostream &OS, const PrintingPolicy&) const {
+ OS << Name;
+}
+
+void NamedDecl::printName(raw_ostream &OS) const {
+ printName(OS, getASTContext().getPrintingPolicy());
}
std::string NamedDecl::getQualifiedNameAsString() const {
@@ -1620,7 +1649,7 @@ 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);
+ printName(OS, P);
return;
}
printNestedNameSpecifier(OS, P);
@@ -1631,7 +1660,7 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
// fall back to "(anonymous)".
SmallString<64> NameBuffer;
llvm::raw_svector_ostream NameOS(NameBuffer);
- printName(NameOS);
+ printName(NameOS, P);
if (NameBuffer.empty())
OS << "(anonymous)";
else
@@ -1754,7 +1783,7 @@ void NamedDecl::getNameForDiagnostic(raw_ostream &OS,
if (Qualified)
printQualifiedName(OS, Policy);
else
- printName(OS);
+ printName(OS, Policy);
}
template<typename T> static bool isRedeclarableImpl(Redeclarable<T> *) {
@@ -1825,7 +1854,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
// Check whether this is actually newer than OldD. We want to keep the
// newer declaration. This loop will usually only iterate once, because
// OldD is usually the previous declaration.
- for (auto D : redecls()) {
+ for (auto *D : redecls()) {
if (D == OldD)
break;
@@ -2273,7 +2302,7 @@ VarDecl *VarDecl::getActingDefinition() {
VarDecl *VarDecl::getDefinition(ASTContext &C) {
VarDecl *First = getFirstDecl();
- for (auto I : First->redecls()) {
+ for (auto *I : First->redecls()) {
if (I->isThisDeclarationADefinition(C) == Definition)
return I;
}
@@ -2284,7 +2313,7 @@ VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
DefinitionKind Kind = DeclarationOnly;
const VarDecl *First = getFirstDecl();
- for (auto I : First->redecls()) {
+ for (auto *I : First->redecls()) {
Kind = std::max(Kind, I->isThisDeclarationADefinition(C));
if (Kind == Definition)
break;
@@ -2294,7 +2323,7 @@ VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
}
const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const {
- for (auto I : redecls()) {
+ for (auto *I : redecls()) {
if (auto Expr = I->getInit()) {
D = I;
return Expr;
@@ -2330,7 +2359,7 @@ Stmt **VarDecl::getInitAddress() {
VarDecl *VarDecl::getInitializingDeclaration() {
VarDecl *Def = nullptr;
- for (auto I : redecls()) {
+ for (auto *I : redecls()) {
if (I->hasInit())
return I;
@@ -2580,7 +2609,7 @@ bool VarDecl::isNonEscapingByref() const {
bool VarDecl::hasDependentAlignment() const {
QualType T = getType();
- return T->isDependentType() || T->isUndeducedAutoType() ||
+ return T->isDependentType() || T->isUndeducedType() ||
llvm::any_of(specific_attrs<AlignedAttr>(), [](const AlignedAttr *AA) {
return AA->isAlignmentDependent();
});
@@ -2870,8 +2899,7 @@ Expr *ParmVarDecl::getDefaultArg() {
Expr *Arg = getInit();
if (auto *E = dyn_cast_or_null<FullExpr>(Arg))
- if (!isa<ConstantExpr>(E))
- return E->getSubExpr();
+ return E->getSubExpr();
return Arg;
}
@@ -2970,6 +2998,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.IsMultiVersion = false;
FunctionDeclBits.IsCopyDeductionCandidate = false;
FunctionDeclBits.HasODRHash = false;
+ FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate = false;
if (TrailingRequiresClause)
setTrailingRequiresClause(TrailingRequiresClause);
}
@@ -3015,7 +3044,7 @@ FunctionDecl::getDefaultedFunctionInfo() const {
}
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
- for (auto I : redecls()) {
+ for (auto *I : redecls()) {
if (I->doesThisDeclarationHaveABody()) {
Definition = I;
return true;
@@ -3162,11 +3191,13 @@ bool FunctionDecl::isMSVCRTEntryPoint() const {
}
bool FunctionDecl::isReservedGlobalPlacementOperator() const {
- assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName);
- assert(getDeclName().getCXXOverloadedOperator() == OO_New ||
- getDeclName().getCXXOverloadedOperator() == OO_Delete ||
- getDeclName().getCXXOverloadedOperator() == OO_Array_New ||
- getDeclName().getCXXOverloadedOperator() == OO_Array_Delete);
+ if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+ return false;
+ if (getDeclName().getCXXOverloadedOperator() != OO_New &&
+ getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_New &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return false;
if (!getDeclContext()->getRedeclContext()->isTranslationUnit())
return false;
@@ -3185,7 +3216,7 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
}
bool FunctionDecl::isReplaceableGlobalAllocationFunction(
- Optional<unsigned> *AlignmentParam, bool *IsNothrow) const {
+ std::optional<unsigned> *AlignmentParam, bool *IsNothrow) const {
if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
return false;
if (getDeclName().getCXXOverloadedOperator() != OO_New &&
@@ -3329,6 +3360,8 @@ bool FunctionDecl::isNoReturn() const {
MultiVersionKind FunctionDecl::getMultiVersionKind() const {
if (hasAttr<TargetAttr>())
return MultiVersionKind::Target;
+ if (hasAttr<TargetVersionAttr>())
+ return MultiVersionKind::TargetVersion;
if (hasAttr<CPUDispatchAttr>())
return MultiVersionKind::CPUDispatch;
if (hasAttr<CPUSpecificAttr>())
@@ -3347,7 +3380,8 @@ bool FunctionDecl::isCPUSpecificMultiVersion() const {
}
bool FunctionDecl::isTargetMultiVersion() const {
- return isMultiVersion() && hasAttr<TargetAttr>();
+ return isMultiVersion() &&
+ (hasAttr<TargetAttr>() || hasAttr<TargetVersionAttr>());
}
bool FunctionDecl::isTargetClonesMultiVersion() const {
@@ -3486,8 +3520,8 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
bool FunctionDecl::hasOneParamOrDefaultArgs() const {
return getNumParams() == 1 ||
(getNumParams() > 1 &&
- std::all_of(param_begin() + 1, param_end(),
- [](ParmVarDecl *P) { return P->hasDefaultArg(); }));
+ llvm::all_of(llvm::drop_begin(parameters()),
+ [](ParmVarDecl *P) { return P->hasDefaultArg(); }));
}
/// The combination of the extern and inline keywords under MSVC forces
@@ -3686,7 +3720,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// If any declaration is 'inline' but not 'extern', then this definition
// is externally visible.
- for (auto Redecl : redecls()) {
+ for (auto *Redecl : redecls()) {
if (Redecl->isInlineSpecified() &&
Redecl->getStorageClass() != SC_Extern)
return true;
@@ -3703,7 +3737,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
// then the definition in that translation unit is an inline definition.
- for (auto Redecl : redecls()) {
+ for (auto *Redecl : redecls()) {
if (RedeclForcesDefC99(Redecl))
return true;
}
@@ -4408,7 +4442,7 @@ void TagDecl::startDefinition() {
if (auto *D = dyn_cast<CXXRecordDecl>(this)) {
struct CXXRecordDecl::DefinitionData *Data =
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
- for (auto I : redecls())
+ for (auto *I : redecls())
cast<CXXRecordDecl>(I)->DefinitionData = Data;
}
}
@@ -4441,7 +4475,7 @@ TagDecl *TagDecl::getDefinition() const {
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(this))
return CXXRD->getDefinition();
- for (auto R : redecls())
+ for (auto *R : redecls())
if (R->isCompleteDefinition())
return R;
@@ -4468,6 +4502,23 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
}
}
+void TagDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
+ DeclarationName Name = getDeclName();
+ // If the name is supposed to have an identifier but does not have one, then
+ // the tag is anonymous and we should print it differently.
+ if (Name.isIdentifier() && !Name.getAsIdentifierInfo()) {
+ // If the caller wanted to print a qualified name, they've already printed
+ // the scope. And if the caller doesn't want that, the scope information
+ // is already printed as part of the type.
+ PrintingPolicy Copy(Policy);
+ Copy.SuppressScope = true;
+ getASTContext().getTagDeclType(this).print(OS, Copy);
+ return;
+ }
+ // Otherwise, do the normal printing.
+ Name.print(OS, Policy);
+}
+
void TagDecl::setTemplateParameterListsInfo(
ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists) {
assert(!TPLists.empty());
@@ -4621,6 +4672,21 @@ SourceRange EnumDecl::getSourceRange() const {
return Res;
}
+void EnumDecl::getValueRange(llvm::APInt &Max, llvm::APInt &Min) const {
+ unsigned Bitwidth = getASTContext().getIntWidth(getIntegerType());
+ unsigned NumNegativeBits = getNumNegativeBits();
+ unsigned NumPositiveBits = getNumPositiveBits();
+
+ if (NumNegativeBits) {
+ unsigned NumBits = std::max(NumNegativeBits, NumPositiveBits + 1);
+ Max = llvm::APInt(Bitwidth, 1) << (NumBits - 1);
+ Min = -Max;
+ } else {
+ Max = llvm::APInt(Bitwidth, 1) << NumPositiveBits;
+ Min = llvm::APInt::getZero(Bitwidth);
+ }
+}
+
//===----------------------------------------------------------------------===//
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
@@ -4645,6 +4711,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C,
setParamDestroyedInCallee(false);
setArgPassingRestrictions(APK_CanPassInRegs);
setIsRandomized(false);
+ setODRHash(0);
}
RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
@@ -4819,6 +4886,19 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const {
return nullptr;
}
+unsigned RecordDecl::getODRHash() {
+ if (hasODRHash())
+ return RecordDeclBits.ODRHash;
+
+ // Only calculate hash on first call of getODRHash per record.
+ ODRHash Hash;
+ Hash.AddRecordDecl(this);
+ // For RecordDecl the ODRHash is stored in the remaining 26
+ // bit of RecordDeclBits, adjust the hash to accomodate.
+ setODRHash(Hash.CalculateHash() >> 6);
+ return RecordDeclBits.ODRHash;
+}
+
//===----------------------------------------------------------------------===//
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
@@ -4968,6 +5048,12 @@ bool ValueDecl::isWeak() const {
MostRecent->hasAttr<WeakRefAttr>() || isWeakImported();
}
+bool ValueDecl::isInitCapture() const {
+ if (auto *Var = llvm::dyn_cast<VarDecl>(this))
+ return Var->isInitCapture();
+ return false;
+}
+
void ImplicitParamDecl::anchor() {}
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
@@ -5073,8 +5159,9 @@ IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- return new (C, ID) IndirectFieldDecl(C, nullptr, SourceLocation(),
- DeclarationName(), QualType(), None);
+ return new (C, ID)
+ IndirectFieldDecl(C, nullptr, SourceLocation(), DeclarationName(),
+ QualType(), std::nullopt);
}
SourceRange EnumConstantDecl::getSourceRange() const {
@@ -5179,6 +5266,29 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
SourceLocation());
}
+void TopLevelStmtDecl::anchor() {}
+
+TopLevelStmtDecl *TopLevelStmtDecl::Create(ASTContext &C, Stmt *Statement) {
+ assert(Statement);
+ assert(C.getLangOpts().IncrementalExtensions &&
+ "Must be used only in incremental mode");
+
+ SourceLocation BeginLoc = Statement->getBeginLoc();
+ DeclContext *DC = C.getTranslationUnitDecl();
+
+ return new (C, DC) TopLevelStmtDecl(DC, BeginLoc, Statement);
+}
+
+TopLevelStmtDecl *TopLevelStmtDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID)
+ TopLevelStmtDecl(/*DC=*/nullptr, SourceLocation(), /*S=*/nullptr);
+}
+
+SourceRange TopLevelStmtDecl::getSourceRange() const {
+ return SourceRange(getLocation(), Statement->getEndLoc());
+}
+
void EmptyDecl::anchor() {}
EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
@@ -5189,6 +5299,40 @@ EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) EmptyDecl(nullptr, SourceLocation());
}
+HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *ID,
+ SourceLocation IDLoc, SourceLocation LBrace)
+ : NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
+ DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
+ IsCBuffer(CBuffer) {}
+
+HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
+ DeclContext *LexicalParent, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *ID,
+ SourceLocation IDLoc,
+ SourceLocation LBrace) {
+ // For hlsl like this
+ // cbuffer A {
+ // cbuffer B {
+ // }
+ // }
+ // compiler should treat it as
+ // cbuffer A {
+ // }
+ // cbuffer B {
+ // }
+ // FIXME: support nested buffers if required for back-compat.
+ DeclContext *DC = LexicalParent;
+ HLSLBufferDecl *Result =
+ new (C, DC) HLSLBufferDecl(DC, CBuffer, KwLoc, ID, IDLoc, LBrace);
+ return Result;
+}
+
+HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr,
+ SourceLocation(), SourceLocation());
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
@@ -5248,11 +5392,11 @@ ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, unsigned ID,
ArrayRef<SourceLocation> ImportDecl::getIdentifierLocs() const {
if (!isImportComplete())
- return None;
+ return std::nullopt;
const auto *StoredLocs = getTrailingObjects<SourceLocation>();
- return llvm::makeArrayRef(StoredLocs,
- getNumModuleIdentifiers(getImportedModule()));
+ return llvm::ArrayRef(StoredLocs,
+ getNumModuleIdentifiers(getImportedModule()));
}
SourceRange ImportDecl::getSourceRange() const {
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index d12330de1500..c94fc602155b 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -152,6 +152,15 @@ void Decl::setInvalidDecl(bool Invalid) {
}
}
+bool DeclContext::hasValidDeclKind() const {
+ switch (getDeclKind()) {
+#define DECL(DERIVED, BASE) case Decl::DERIVED: return true;
+#define ABSTRACT_DECL(DECL)
+#include "clang/AST/DeclNodes.inc"
+ }
+ return false;
+}
+
const char *DeclContext::getDeclKindName() const {
switch (getDeclKind()) {
#define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED;
@@ -252,12 +261,12 @@ const TemplateParameterList *Decl::getDescribedTemplateParams() const {
bool Decl::isTemplated() const {
// A declaration is templated if it is a template or a template pattern, or
- // is within (lexcially for a friend, semantically otherwise) a dependent
- // context.
- // FIXME: Should local extern declarations be treated like friends?
+ // is within (lexcially for a friend or local function declaration,
+ // semantically otherwise) a dependent context.
if (auto *AsDC = dyn_cast<DeclContext>(this))
return AsDC->isDependentContext();
- auto *DC = getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext();
+ auto *DC = getFriendObjectKind() || isLocalExternDecl()
+ ? getLexicalDeclContext() : getDeclContext();
return DC->isDependentContext() || isTemplateDecl() ||
getDescribedTemplateParams();
}
@@ -286,8 +295,7 @@ unsigned Decl::getTemplateDepth() const {
const DeclContext *Decl::getParentFunctionOrMethod(bool LexicalParent) const {
for (const DeclContext *DC = LexicalParent ? getLexicalDeclContext()
: getDeclContext();
- DC && !DC->isTranslationUnit() && !DC->isNamespace();
- DC = DC->getParent())
+ DC && !DC->isFileContext(); DC = DC->getParent())
if (DC->isFunctionOrMethod())
return DC;
@@ -397,6 +405,11 @@ bool Decl::isInStdNamespace() const {
return DC && DC->isStdNamespace();
}
+bool Decl::isFileContextDecl() const {
+ const auto *DC = dyn_cast<DeclContext>(this);
+ return DC && DC->isFileContext();
+}
+
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
if (auto *TUD = dyn_cast<TranslationUnitDecl>(this))
return TUD;
@@ -750,6 +763,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCMethod:
case ObjCProperty:
case MSProperty:
+ case HLSLBuffer:
return IDNS_Ordinary;
case Label:
return IDNS_Label;
@@ -829,6 +843,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case LinkageSpec:
case Export:
case FileScopeAsm:
+ case TopLevelStmt:
case StaticAssert:
case ObjCPropertyImpl:
case PragmaComment:
@@ -860,6 +875,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Empty:
case LifetimeExtendedTemporary:
case RequiresExprBody:
+ case ImplicitConceptSpecialization:
// Never looked up by name.
return 0;
}
@@ -1032,6 +1048,11 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
return Ty->getAs<FunctionType>();
}
+DeclContext *Decl::getNonTransparentDeclContext() {
+ assert(getDeclContext());
+ return getDeclContext()->getNonTransparentContext();
+}
+
/// Starting at a given context (a Decl or DeclContext), look for a
/// code context that is not a closure (a lambda, block, etc.).
template <class T> static Decl *getNonClosureContext(T *D) {
@@ -1188,7 +1209,7 @@ bool DeclContext::isTransparentContext() const {
if (getDeclKind() == Decl::Enum)
return !cast<EnumDecl>(this)->isScoped();
- return getDeclKind() == Decl::LinkageSpec || getDeclKind() == Decl::Export;
+ return isa<LinkageSpecDecl, ExportDecl, HLSLBufferDecl>(this);
}
static bool isLinkageSpecContext(const DeclContext *DC,
@@ -1253,6 +1274,15 @@ DeclContext *DeclContext::getPrimaryContext() {
// There is only one DeclContext for these entities.
return this;
+ case Decl::HLSLBuffer:
+ // Each buffer, even with the same name, is a distinct construct.
+ // Multiple buffers with the same name are allowed for backward
+ // compatibility.
+ // As long as buffers have unique resource bindings the names don't matter.
+ // The names get exposed via the CPU-side reflection API which
+ // supports querying bindings, so we cannot remove them.
+ return this;
+
case Decl::TranslationUnit:
return static_cast<TranslationUnitDecl *>(this)->getFirstDecl();
case Decl::Namespace:
@@ -1766,7 +1796,8 @@ void DeclContext::localUncachedLookup(DeclarationName Name,
if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) {
lookup_result LookupResults = lookup(Name);
Results.insert(Results.end(), LookupResults.begin(), LookupResults.end());
- return;
+ if (!Results.empty())
+ return;
}
// If we have a lookup table, check there first. Maybe we'll get lucky.
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index c307cbe02ecf..3cf355714107 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -36,7 +36,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
-#include "llvm/ADT/None.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
@@ -768,12 +768,16 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Note that we have a user-declared constructor.
data().UserDeclaredConstructor = true;
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- // Since the POD bit is meant to be C++03 POD-ness, clear it even if
- // the type is technically an aggregate in C++0x since it wouldn't be
- // in 03.
- data().PlainOldData = false;
+ const TargetInfo &TI = getASTContext().getTargetInfo();
+ if ((!Constructor->isDeleted() && !Constructor->isDefaulted()) ||
+ !TI.areDefaultedSMFStillPOD(getLangOpts())) {
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if
+ // the type is technically an aggregate in C++0x since it wouldn't be
+ // in 03.
+ data().PlainOldData = false;
+ }
}
if (Constructor->isDefaultConstructor()) {
@@ -881,22 +885,30 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!Method->isImplicit()) {
data().UserDeclaredSpecialMembers |= SMKind;
- // C++03 [class]p4:
- // A POD-struct is an aggregate class that has [...] no user-defined
- // copy assignment operator and no user-defined destructor.
- //
- // Since the POD bit is meant to be C++03 POD-ness, and in C++03,
- // aggregates could not have any constructors, clear it even for an
- // explicitly defaulted or deleted constructor.
- // type is technically an aggregate in C++0x since it wouldn't be in 03.
- //
- // Also, a user-declared move assignment operator makes a class non-POD.
- // This is an extension in C++03.
- data().PlainOldData = false;
+ const TargetInfo &TI = getASTContext().getTargetInfo();
+ if ((!Method->isDeleted() && !Method->isDefaulted() &&
+ SMKind != SMF_MoveAssignment) ||
+ !TI.areDefaultedSMFStillPOD(getLangOpts())) {
+ // C++03 [class]p4:
+ // A POD-struct is an aggregate class that has [...] no user-defined
+ // copy assignment operator and no user-defined destructor.
+ //
+ // Since the POD bit is meant to be C++03 POD-ness, and in C++03,
+ // aggregates could not have any constructors, clear it even for an
+ // explicitly defaulted or deleted constructor.
+ // type is technically an aggregate in C++0x since it wouldn't be in
+ // 03.
+ //
+ // Also, a user-declared move assignment operator makes a class
+ // non-POD. This is an extension in C++03.
+ data().PlainOldData = false;
+ }
}
- // We delay updating destructor relevant properties until
- // addedSelectedDestructor.
- // FIXME: Defer this for the other special member functions as well.
+ // When instantiating a class, we delay updating the destructor and
+ // triviality properties of the class until selecting a destructor and
+ // computing the eligibility of its special member functions. This is
+ // because there might be function constraints that we need to evaluate
+ // and compare later in the instantiation.
if (!Method->isIneligibleOrNotSelected()) {
addedEligibleSpecialMemberFunction(Method, SMKind);
}
@@ -1365,7 +1377,11 @@ void CXXRecordDecl::addedSelectedDestructor(CXXDestructorDecl *DD) {
}
void CXXRecordDecl::addedEligibleSpecialMemberFunction(const CXXMethodDecl *MD,
- unsigned SMKind) {
+ unsigned SMKind) {
+ // FIXME: We shouldn't change DeclaredNonTrivialSpecialMembers if `MD` is
+ // a function template, but this needs CWG attention before we break ABI.
+ // See https://github.com/llvm/llvm-project/issues/59206
+
if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
if (DD->isUserProvided())
data().HasIrrelevantDestructor = false;
@@ -1437,10 +1453,21 @@ void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
// Update which trivial / non-trivial special members we have.
// addedMember will have skipped this step for this member.
- if (D->isTrivial())
- data().HasTrivialSpecialMembers |= SMKind;
- else
- data().DeclaredNonTrivialSpecialMembers |= SMKind;
+ if (!D->isIneligibleOrNotSelected()) {
+ if (D->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
+ }
+}
+
+void CXXRecordDecl::LambdaDefinitionData::AddCaptureList(ASTContext &Ctx,
+ Capture *CaptureList) {
+ Captures.push_back(CaptureList);
+ if (Captures.size() == 2) {
+ // The TinyPtrVector member now needs destruction.
+ Ctx.addDestruction(&Captures);
+ }
}
void CXXRecordDecl::setCaptures(ASTContext &Context,
@@ -1450,9 +1477,9 @@ void CXXRecordDecl::setCaptures(ASTContext &Context,
// Copy captures.
Data.NumCaptures = Captures.size();
Data.NumExplicitCaptures = 0;
- Data.Captures = (LambdaCapture *)Context.Allocate(sizeof(LambdaCapture) *
- Captures.size());
- LambdaCapture *ToCapture = Data.Captures;
+ auto *ToCapture = (LambdaCapture *)Context.Allocate(sizeof(LambdaCapture) *
+ Captures.size());
+ Data.AddCaptureList(Context, ToCapture);
for (unsigned I = 0, N = Captures.size(); I != N; ++I) {
if (Captures[I].isExplicit())
++Data.NumExplicitCaptures;
@@ -1570,21 +1597,23 @@ CXXMethodDecl *CXXRecordDecl::getLambdaStaticInvoker(CallingConv CC) const {
}
void CXXRecordDecl::getCaptureFields(
- llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
- FieldDecl *&ThisCapture) const {
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> &Captures,
+ FieldDecl *&ThisCapture) const {
Captures.clear();
ThisCapture = nullptr;
LambdaDefinitionData &Lambda = getLambdaData();
- RecordDecl::field_iterator Field = field_begin();
- for (const LambdaCapture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
- C != CEnd; ++C, ++Field) {
- if (C->capturesThis())
- ThisCapture = *Field;
- else if (C->capturesVariable())
- Captures[C->getCapturedVar()] = *Field;
+ for (const LambdaCapture *List : Lambda.Captures) {
+ RecordDecl::field_iterator Field = field_begin();
+ for (const LambdaCapture *C = List, *CEnd = C + Lambda.NumCaptures;
+ C != CEnd; ++C, ++Field) {
+ if (C->capturesThis())
+ ThisCapture = *Field;
+ else if (C->capturesVariable())
+ Captures[C->getCapturedVar()] = *Field;
+ }
+ assert(Field == field_end());
}
- assert(Field == field_end());
}
TemplateParameterList *
@@ -1608,7 +1637,7 @@ CXXRecordDecl::getLambdaExplicitTemplateParameters() const {
const auto ExplicitEnd = llvm::partition_point(
*List, [](const NamedDecl *D) { return !D->isImplicit(); });
- return llvm::makeArrayRef(List->begin(), ExplicitEnd);
+ return llvm::ArrayRef(List->begin(), ExplicitEnd);
}
Decl *CXXRecordDecl::getLambdaContextDecl() const {
@@ -2566,7 +2595,7 @@ SourceLocation CXXCtorInitializer::getSourceLocation() const {
return getMemberLocation();
if (const auto *TSInfo = Initializee.get<TypeSourceInfo *>())
- return TSInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ return TSInfo->getTypeLoc().getBeginLoc();
return {};
}
@@ -2865,41 +2894,47 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, NamespaceDecl *PrevDecl)
+ IdentifierInfo *Id, NamespaceDecl *PrevDecl,
+ bool Nested)
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
- redeclarable_base(C), LocStart(StartLoc),
- AnonOrFirstNamespaceAndInline(nullptr, Inline) {
+ redeclarable_base(C), LocStart(StartLoc) {
+ unsigned Flags = 0;
+ if (Inline)
+ Flags |= F_Inline;
+ if (Nested)
+ Flags |= F_Nested;
+ AnonOrFirstNamespaceAndFlags = {nullptr, Flags};
setPreviousDecl(PrevDecl);
if (PrevDecl)
- AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
+ AnonOrFirstNamespaceAndFlags.setPointer(PrevDecl->getOriginalNamespace());
}
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
bool Inline, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
- NamespaceDecl *PrevDecl) {
- return new (C, DC) NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id,
- PrevDecl);
+ NamespaceDecl *PrevDecl, bool Nested) {
+ return new (C, DC)
+ NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl, Nested);
}
NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(),
- SourceLocation(), nullptr, nullptr);
+ SourceLocation(), nullptr, nullptr, false);
}
NamespaceDecl *NamespaceDecl::getOriginalNamespace() {
if (isFirstDecl())
return this;
- return AnonOrFirstNamespaceAndInline.getPointer();
+ return AnonOrFirstNamespaceAndFlags.getPointer();
}
const NamespaceDecl *NamespaceDecl::getOriginalNamespace() const {
if (isFirstDecl())
return this;
- return AnonOrFirstNamespaceAndInline.getPointer();
+ return AnonOrFirstNamespaceAndFlags.getPointer();
}
bool NamespaceDecl::isOriginalNamespace() const { return isFirstDecl(); }
@@ -3087,18 +3122,23 @@ SourceRange UsingDecl::getSourceRange() const {
void UsingEnumDecl::anchor() {}
UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation UL, SourceLocation EL,
- SourceLocation NL, EnumDecl *Enum) {
- return new (C, DC) UsingEnumDecl(DC, Enum->getDeclName(), UL, EL, NL, Enum);
+ SourceLocation UL,
+ SourceLocation EL,
+ SourceLocation NL,
+ TypeSourceInfo *EnumType) {
+ assert(isa<EnumDecl>(EnumType->getType()->getAsTagDecl()));
+ return new (C, DC)
+ UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType);
}
UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
- SourceLocation(), SourceLocation(), nullptr);
+ return new (C, ID)
+ UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
+ SourceLocation(), SourceLocation(), nullptr);
}
SourceRange UsingEnumDecl::getSourceRange() const {
- return SourceRange(EnumLocation, getLocation());
+ return SourceRange(UsingLocation, EnumType->getTypeLoc().getEndLoc());
}
void UsingPackDecl::anchor() {}
@@ -3113,7 +3153,8 @@ UsingPackDecl *UsingPackDecl::Create(ASTContext &C, DeclContext *DC,
UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumExpansions) {
size_t Extra = additionalSizeToAlloc<NamedDecl *>(NumExpansions);
- auto *Result = new (C, ID, Extra) UsingPackDecl(nullptr, nullptr, None);
+ auto *Result =
+ new (C, ID, Extra) UsingPackDecl(nullptr, nullptr, std::nullopt);
Result->NumExpansions = NumExpansions;
auto *Trail = Result->getTrailingObjects<NamedDecl *>();
for (unsigned I = 0; I != NumExpansions; ++I)
@@ -3208,6 +3249,16 @@ StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C,
nullptr, SourceLocation(), false);
}
+VarDecl *ValueDecl::getPotentiallyDecomposedVarDecl() {
+ assert((isa<VarDecl, BindingDecl>(this)) &&
+ "expected a VarDecl or a BindingDecl");
+ if (auto *Var = llvm::dyn_cast<VarDecl>(this))
+ return Var;
+ if (auto *BD = llvm::dyn_cast<BindingDecl>(this))
+ return llvm::dyn_cast<VarDecl>(BD->getDecomposedDecl());
+ return nullptr;
+}
+
void BindingDecl::anchor() {}
BindingDecl *BindingDecl::Create(ASTContext &C, DeclContext *DC,
@@ -3251,7 +3302,7 @@ DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C,
size_t Extra = additionalSizeToAlloc<BindingDecl *>(NumBindings);
auto *Result = new (C, ID, Extra)
DecompositionDecl(C, nullptr, SourceLocation(), SourceLocation(),
- QualType(), nullptr, StorageClass(), None);
+ QualType(), nullptr, StorageClass(), std::nullopt);
// Set up and clean out the bindings array.
Result->NumBindings = NumBindings;
auto *Trail = Result->getTrailingObjects<BindingDecl *>();
@@ -3260,16 +3311,17 @@ DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C,
return Result;
}
-void DecompositionDecl::printName(llvm::raw_ostream &os) const {
- os << '[';
+void DecompositionDecl::printName(llvm::raw_ostream &OS,
+ const PrintingPolicy &Policy) const {
+ OS << '[';
bool Comma = false;
for (const auto *B : bindings()) {
if (Comma)
- os << ", ";
- B->printName(os);
+ OS << ", ";
+ B->printName(OS, Policy);
Comma = true;
}
- os << ']';
+ OS << ']';
}
void MSPropertyDecl::anchor() {}
@@ -3305,7 +3357,8 @@ MSGuidDecl *MSGuidDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) MSGuidDecl(nullptr, QualType(), Parts());
}
-void MSGuidDecl::printName(llvm::raw_ostream &OS) const {
+void MSGuidDecl::printName(llvm::raw_ostream &OS,
+ const PrintingPolicy &) const {
OS << llvm::format("GUID{%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 "-",
PartVal.Part1, PartVal.Part2, PartVal.Part3);
unsigned I = 0;
@@ -3414,7 +3467,8 @@ UnnamedGlobalConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
UnnamedGlobalConstantDecl(C, nullptr, QualType(), APValue());
}
-void UnnamedGlobalConstantDecl::printName(llvm::raw_ostream &OS) const {
+void UnnamedGlobalConstantDecl::printName(llvm::raw_ostream &OS,
+ const PrintingPolicy &) const {
OS << "unnamed-global-constant";
}
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index 15c545b59c81..e934a81d086e 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/ODRHash.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
@@ -23,7 +24,6 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
@@ -403,21 +403,18 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return nullptr;
}
-void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
- PropertyDeclOrder &PO) const {
+void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const {
for (auto *Prop : properties()) {
PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
- PO.push_back(Prop);
}
for (const auto *Ext : known_extensions()) {
const ObjCCategoryDecl *ClassExt = Ext;
for (auto *Prop : ClassExt->properties()) {
PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
- PO.push_back(Prop);
}
}
for (const auto *PI : all_referenced_protocols())
- PI->collectPropertiesToImplement(PM, PO);
+ PI->collectPropertiesToImplement(PM);
// Note, the properties declared only in class extensions are still copied
// into the main @interface's property list, and therefore we don't
// explicitly, have to search class extension properties.
@@ -627,6 +624,17 @@ void ObjCInterfaceDecl::startDefinition() {
}
}
+void ObjCInterfaceDecl::startDuplicateDefinitionForComparison() {
+ Data.setPointer(nullptr);
+ allocateDefinitionData();
+ // Don't propagate data to other redeclarations.
+}
+
+void ObjCInterfaceDecl::mergeDuplicateDefinitionWithCommon(
+ const ObjCInterfaceDecl *Definition) {
+ Data = Definition->Data;
+}
+
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
// FIXME: Should make sure no callers ever do this.
@@ -781,6 +789,33 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
return Method;
}
+unsigned ObjCInterfaceDecl::getODRHash() {
+ assert(hasDefinition() && "ODRHash only for records with definitions");
+
+ // Previously calculated hash is stored in DefinitionData.
+ if (hasODRHash())
+ return data().ODRHash;
+
+ // Only calculate hash on first call of getODRHash per record.
+ ODRHash Hasher;
+ Hasher.AddObjCInterfaceDecl(getDefinition());
+ data().ODRHash = Hasher.CalculateHash();
+ setHasODRHash(true);
+
+ return data().ODRHash;
+}
+
+bool ObjCInterfaceDecl::hasODRHash() const {
+ if (!hasDefinition())
+ return false;
+ return data().HasODRHash;
+}
+
+void ObjCInterfaceDecl::setHasODRHash(bool HasHash) {
+ assert(hasDefinition() && "Cannot set ODRHash without definition");
+ data().HasODRHash = HasHash;
+}
+
//===----------------------------------------------------------------------===//
// ObjCMethodDecl
//===----------------------------------------------------------------------===//
@@ -864,7 +899,7 @@ bool ObjCMethodDecl::isDesignatedInitializerForTheInterface(
}
bool ObjCMethodDecl::hasParamDestroyedInCallee() const {
- for (auto param : parameters()) {
+ for (auto *param : parameters()) {
if (param->isDestroyedInCallee())
return true;
}
@@ -912,12 +947,12 @@ void ObjCMethodDecl::setMethodParams(ASTContext &C,
assert((!SelLocs.empty() || isImplicit()) &&
"No selector locs for non-implicit method");
if (isImplicit())
- return setParamsAndSelLocs(C, Params, llvm::None);
+ return setParamsAndSelLocs(C, Params, std::nullopt);
setSelLocsKind(hasStandardSelectorLocs(getSelector(), SelLocs, Params,
DeclEndLoc));
if (getSelLocsKind() != SelLoc_NonStandard)
- return setParamsAndSelLocs(C, Params, llvm::None);
+ return setParamsAndSelLocs(C, Params, std::nullopt);
setParamsAndSelLocs(C, Params, SelLocs);
}
@@ -1496,7 +1531,7 @@ ObjCTypeParamList *ObjCTypeParamList::create(
void ObjCTypeParamList::gatherDefaultTypeArgs(
SmallVectorImpl<QualType> &typeArgs) const {
typeArgs.reserve(size());
- for (auto typeParam : *this)
+ for (auto *typeParam : *this)
typeArgs.push_back(typeParam->getUnderlyingType());
}
@@ -1988,6 +2023,7 @@ void ObjCProtocolDecl::allocateDefinitionData() {
assert(!Data.getPointer() && "Protocol already has a definition!");
Data.setPointer(new (getASTContext()) DefinitionData);
Data.getPointer()->Definition = this;
+ Data.getPointer()->HasODRHash = false;
}
void ObjCProtocolDecl::startDefinition() {
@@ -1998,19 +2034,28 @@ void ObjCProtocolDecl::startDefinition() {
RD->Data = this->Data;
}
-void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
- PropertyDeclOrder &PO) const {
+void ObjCProtocolDecl::startDuplicateDefinitionForComparison() {
+ Data.setPointer(nullptr);
+ allocateDefinitionData();
+ // Don't propagate data to other redeclarations.
+}
+
+void ObjCProtocolDecl::mergeDuplicateDefinitionWithCommon(
+ const ObjCProtocolDecl *Definition) {
+ Data = Definition->Data;
+}
+
+void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const {
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
for (auto *Prop : PDecl->properties()) {
// Insert into PM if not there already.
PM.insert(std::make_pair(
std::make_pair(Prop->getIdentifier(), Prop->isClassProperty()),
Prop));
- PO.push_back(Prop);
}
// Scan through protocol's protocols.
for (const auto *PI : PDecl->protocols())
- PI->collectPropertiesToImplement(PM, PO);
+ PI->collectPropertiesToImplement(PM);
}
}
@@ -2042,6 +2087,33 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
return getName();
}
+unsigned ObjCProtocolDecl::getODRHash() {
+ assert(hasDefinition() && "ODRHash only for records with definitions");
+
+ // Previously calculated hash is stored in DefinitionData.
+ if (hasODRHash())
+ return data().ODRHash;
+
+ // Only calculate hash on first call of getODRHash per record.
+ ODRHash Hasher;
+ Hasher.AddObjCProtocolDecl(getDefinition());
+ data().ODRHash = Hasher.CalculateHash();
+ setHasODRHash(true);
+
+ return data().ODRHash;
+}
+
+bool ObjCProtocolDecl::hasODRHash() const {
+ if (!hasDefinition())
+ return false;
+ return data().HasODRHash;
+}
+
+void ObjCProtocolDecl::setHasODRHash(bool HasHash) {
+ assert(hasDefinition() && "Cannot set ODRHash without definition");
+ data().HasODRHash = HasHash;
+}
+
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/DeclOpenMP.cpp b/clang/lib/AST/DeclOpenMP.cpp
index 867ef31656f7..e29fc564fd34 100644
--- a/clang/lib/AST/DeclOpenMP.cpp
+++ b/clang/lib/AST/DeclOpenMP.cpp
@@ -30,7 +30,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
SourceLocation L,
ArrayRef<Expr *> VL) {
auto *D = OMPDeclarativeDirective::createDirective<OMPThreadPrivateDecl>(
- C, DC, llvm::None, VL.size(), L);
+ C, DC, std::nullopt, VL.size(), L);
D->setVars(VL);
return D;
}
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index b041e2a67e95..f3bad9f45b74 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -72,6 +72,7 @@ namespace {
void VisitLabelDecl(LabelDecl *D);
void VisitParmVarDecl(ParmVarDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitTopLevelStmtDecl(TopLevelStmtDecl *D);
void VisitImportDecl(ImportDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
@@ -108,6 +109,7 @@ namespace {
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *NTTP);
+ void VisitHLSLBufferDecl(HLSLBufferDecl *D);
void printTemplateParameters(const TemplateParameterList *Params,
bool OmitTemplateKW = false);
@@ -462,12 +464,9 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
Terminator = nullptr;
else
Terminator = ";";
- } else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
- isa<ObjCImplementationDecl>(*D) ||
- isa<ObjCInterfaceDecl>(*D) ||
- isa<ObjCProtocolDecl>(*D) ||
- isa<ObjCCategoryImplDecl>(*D) ||
- isa<ObjCCategoryDecl>(*D))
+ } else if (isa<NamespaceDecl, LinkageSpecDecl, ObjCImplementationDecl,
+ ObjCInterfaceDecl, ObjCProtocolDecl, ObjCCategoryImplDecl,
+ ObjCCategoryDecl, HLSLBufferDecl>(*D))
Terminator = nullptr;
else if (isa<EnumConstantDecl>(*D)) {
DeclContext::decl_iterator Next = D;
@@ -934,6 +933,11 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Out << ")";
}
+void DeclPrinter::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) {
+ assert(D->getStmt());
+ D->getStmt()->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
+}
+
void DeclPrinter::VisitImportDecl(ImportDecl *D) {
Out << "@import " << D->getImportedModule()->getFullModuleName()
<< ";\n";
@@ -1658,6 +1662,21 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
}
}
+void DeclPrinter::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
+ if (D->isCBuffer())
+ Out << "cbuffer ";
+ else
+ Out << "tbuffer ";
+
+ Out << *D;
+
+ prettyPrintAttributes(D);
+
+ Out << " {\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+}
+
void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
Out << "#pragma omp allocate";
if (!D->varlist_empty()) {
@@ -1698,7 +1717,7 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
Out << OpName;
} else {
assert(D->getDeclName().isIdentifier());
- D->printName(Out);
+ D->printName(Out, Policy);
}
Out << " : ";
D->getType().print(Out, Policy);
@@ -1728,7 +1747,7 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
void DeclPrinter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
if (!D->isInvalidDecl()) {
Out << "#pragma omp declare mapper (";
- D->printName(Out);
+ D->printName(Out, Policy);
Out << " : ";
D->getType().print(Out, Policy);
Out << " ";
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index e7e5f355809b..531be708b6fd 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -26,7 +26,6 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -36,6 +35,7 @@
#include <cassert>
#include <cstdint>
#include <memory>
+#include <optional>
#include <utility>
using namespace clang;
@@ -131,7 +131,7 @@ unsigned TemplateParameterList::getMinRequiredArguments() const {
unsigned NumRequiredArgs = 0;
for (const NamedDecl *P : asArray()) {
if (P->isTemplateParameterPack()) {
- if (Optional<unsigned> Expansions = getExpandedPackSize(P)) {
+ if (std::optional<unsigned> Expansions = getExpandedPackSize(P)) {
NumRequiredArgs += *Expansions;
continue;
}
@@ -250,6 +250,16 @@ bool TemplateDecl::hasAssociatedConstraints() const {
return false;
}
+bool TemplateDecl::isTypeAlias() const {
+ switch (getKind()) {
+ case TemplateDecl::TypeAliasTemplate:
+ case TemplateDecl::BuiltinTemplate:
+ return true;
+ default:
+ return false;
+ };
+}
+
//===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -343,6 +353,22 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
SETraits::getDecl(Entry));
}
+ArrayRef<TemplateArgument> RedeclarableTemplateDecl::getInjectedTemplateArgs() {
+ TemplateParameterList *Params = getTemplateParameters();
+ auto *CommonPtr = getCommonPtr();
+ if (!CommonPtr->InjectedArgs) {
+ auto &Context = getASTContext();
+ SmallVector<TemplateArgument, 16> TemplateArgs;
+ Context.getInjectedTemplateArgs(Params, TemplateArgs);
+ CommonPtr->InjectedArgs =
+ new (Context) TemplateArgument[TemplateArgs.size()];
+ std::copy(TemplateArgs.begin(), TemplateArgs.end(),
+ CommonPtr->InjectedArgs);
+ }
+
+ return llvm::ArrayRef(CommonPtr->InjectedArgs, Params->size());
+}
+
//===----------------------------------------------------------------------===//
// FunctionTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -393,22 +419,6 @@ void FunctionTemplateDecl::addSpecialization(
InsertPos);
}
-ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() {
- TemplateParameterList *Params = getTemplateParameters();
- Common *CommonPtr = getCommonPtr();
- if (!CommonPtr->InjectedArgs) {
- auto &Context = getASTContext();
- SmallVector<TemplateArgument, 16> TemplateArgs;
- Context.getInjectedTemplateArgs(Params, TemplateArgs);
- CommonPtr->InjectedArgs =
- new (Context) TemplateArgument[TemplateArgs.size()];
- std::copy(TemplateArgs.begin(), TemplateArgs.end(),
- CommonPtr->InjectedArgs);
- }
-
- return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size());
-}
-
void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
using Base = RedeclarableTemplateDecl;
@@ -519,6 +529,9 @@ static void ProfileTemplateParameterList(ASTContext &C,
ID.AddInteger(0);
ID.AddBoolean(NTTP->isParameterPack());
NTTP->getType().getCanonicalType().Profile(ID);
+ ID.AddBoolean(NTTP->hasPlaceholderTypeConstraint());
+ if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
+ E->Profile(ID, C, /*Canonical=*/true);
continue;
}
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) {
@@ -624,13 +637,11 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
// TemplateTypeParm Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
-TemplateTypeParmDecl *
-TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation KeyLoc, SourceLocation NameLoc,
- unsigned D, unsigned P, IdentifierInfo *Id,
- bool Typename, bool ParameterPack,
- bool HasTypeConstraint,
- Optional<unsigned> NumExpanded) {
+TemplateTypeParmDecl *TemplateTypeParmDecl::Create(
+ const ASTContext &C, DeclContext *DC, SourceLocation KeyLoc,
+ SourceLocation NameLoc, unsigned D, unsigned P, IdentifierInfo *Id,
+ bool Typename, bool ParameterPack, bool HasTypeConstraint,
+ std::optional<unsigned> NumExpanded) {
auto *TTPDecl =
new (C, DC,
additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0))
@@ -643,9 +654,9 @@ TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
TemplateTypeParmDecl *
TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
- return new (C, ID) TemplateTypeParmDecl(nullptr, SourceLocation(),
- SourceLocation(), nullptr, false,
- false, None);
+ return new (C, ID)
+ TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(), nullptr,
+ false, false, std::nullopt);
}
TemplateTypeParmDecl *
@@ -653,8 +664,8 @@ TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID,
bool HasTypeConstraint) {
return new (C, ID,
additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0))
- TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(),
- nullptr, false, HasTypeConstraint, None);
+ TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(), nullptr,
+ false, HasTypeConstraint, std::nullopt);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
@@ -768,12 +779,12 @@ NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumExpandedTypes,
bool HasTypeConstraint) {
auto *NTTP =
- new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
- Expr *>(
- NumExpandedTypes, HasTypeConstraint ? 1 : 0))
+ new (C, ID,
+ additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, Expr *>(
+ NumExpandedTypes, HasTypeConstraint ? 1 : 0))
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
- 0, 0, nullptr, QualType(), nullptr, None,
- None);
+ 0, 0, nullptr, QualType(), nullptr,
+ std::nullopt, std::nullopt);
NTTP->NumExpandedTypes = NumExpandedTypes;
return NTTP;
}
@@ -841,7 +852,7 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
auto *TTP =
new (C, ID, additionalSizeToAlloc<TemplateParameterList *>(NumExpansions))
TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr,
- nullptr, None);
+ nullptr, std::nullopt);
TTP->NumExpandedParams = NumExpansions;
return TTP;
}
@@ -930,6 +941,14 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
SpecializedTemplate, Args, PrevDecl);
Result->setMayHaveOutOfDateDef(false);
+ // If the template decl is incomplete, copy the external lexical storage from
+ // the base template. This allows instantiations of incomplete types to
+ // complete using the external AST if the template's declaration came from an
+ // external AST.
+ if (!SpecializedTemplate->getTemplatedDecl()->isCompleteDefinition())
+ Result->setHasExternalLexicalStorage(
+ SpecializedTemplate->getTemplatedDecl()->hasExternalLexicalStorage());
+
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
@@ -1032,6 +1051,44 @@ ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C,
}
//===----------------------------------------------------------------------===//
+// ImplicitConceptSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl(
+ DeclContext *DC, SourceLocation SL,
+ ArrayRef<TemplateArgument> ConvertedArgs)
+ : Decl(ImplicitConceptSpecialization, DC, SL),
+ NumTemplateArgs(ConvertedArgs.size()) {
+ setTemplateArguments(ConvertedArgs);
+}
+
+ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl(
+ EmptyShell Empty, unsigned NumTemplateArgs)
+ : Decl(ImplicitConceptSpecialization, Empty),
+ NumTemplateArgs(NumTemplateArgs) {}
+
+ImplicitConceptSpecializationDecl *ImplicitConceptSpecializationDecl::Create(
+ const ASTContext &C, DeclContext *DC, SourceLocation SL,
+ ArrayRef<TemplateArgument> ConvertedArgs) {
+ return new (C, DC,
+ additionalSizeToAlloc<TemplateArgument>(ConvertedArgs.size()))
+ ImplicitConceptSpecializationDecl(DC, SL, ConvertedArgs);
+}
+
+ImplicitConceptSpecializationDecl *
+ImplicitConceptSpecializationDecl::CreateDeserialized(
+ const ASTContext &C, unsigned ID, unsigned NumTemplateArgs) {
+ return new (C, ID, additionalSizeToAlloc<TemplateArgument>(NumTemplateArgs))
+ ImplicitConceptSpecializationDecl(EmptyShell{}, NumTemplateArgs);
+}
+
+void ImplicitConceptSpecializationDecl::setTemplateArguments(
+ ArrayRef<TemplateArgument> Converted) {
+ assert(Converted.size() == NumTemplateArgs);
+ std::uninitialized_copy(Converted.begin(), Converted.end(),
+ getTrailingObjects<TemplateArgument>());
+}
+
+//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
void ClassTemplatePartialSpecializationDecl::anchor() {}
@@ -1457,8 +1514,8 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) {
// template <std::size_t Index, typename ...T>
NamedDecl *Params[] = {Index, Ts};
return TemplateParameterList::Create(C, SourceLocation(), SourceLocation(),
- llvm::makeArrayRef(Params),
- SourceLocation(), nullptr);
+ llvm::ArrayRef(Params), SourceLocation(),
+ nullptr);
}
static TemplateParameterList *createBuiltinTemplateParameterList(
@@ -1511,9 +1568,10 @@ TemplateParamObjectDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return TPOD;
}
-void TemplateParamObjectDecl::printName(llvm::raw_ostream &OS) const {
+void TemplateParamObjectDecl::printName(llvm::raw_ostream &OS,
+ const PrintingPolicy &Policy) const {
OS << "<template param ";
- printAsExpr(OS);
+ printAsExpr(OS, Policy);
OS << ">";
}
@@ -1535,3 +1593,56 @@ void TemplateParamObjectDecl::printAsInit(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const {
getValue().printPretty(OS, Policy, getType(), &getASTContext());
}
+
+TemplateParameterList *clang::getReplacedTemplateParameterList(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Kind::ClassTemplate:
+ return cast<ClassTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::ClassTemplateSpecialization: {
+ const auto *CTSD = cast<ClassTemplateSpecializationDecl>(D);
+ auto P = CTSD->getSpecializedTemplateOrPartial();
+ if (const auto *CTPSD =
+ P.dyn_cast<ClassTemplatePartialSpecializationDecl *>())
+ return CTPSD->getTemplateParameters();
+ return cast<ClassTemplateDecl *>(P)->getTemplateParameters();
+ }
+ case Decl::Kind::ClassTemplatePartialSpecialization:
+ return cast<ClassTemplatePartialSpecializationDecl>(D)
+ ->getTemplateParameters();
+ case Decl::Kind::TypeAliasTemplate:
+ return cast<TypeAliasTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::BuiltinTemplate:
+ return cast<BuiltinTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::CXXDeductionGuide:
+ case Decl::Kind::CXXConversion:
+ case Decl::Kind::CXXConstructor:
+ case Decl::Kind::CXXDestructor:
+ case Decl::Kind::CXXMethod:
+ case Decl::Kind::Function:
+ return cast<FunctionDecl>(D)
+ ->getTemplateSpecializationInfo()
+ ->getTemplate()
+ ->getTemplateParameters();
+ case Decl::Kind::FunctionTemplate:
+ return cast<FunctionTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::VarTemplate:
+ return cast<VarTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::VarTemplateSpecialization: {
+ const auto *VTSD = cast<VarTemplateSpecializationDecl>(D);
+ auto P = VTSD->getSpecializedTemplateOrPartial();
+ if (const auto *VTPSD =
+ P.dyn_cast<VarTemplatePartialSpecializationDecl *>())
+ return VTPSD->getTemplateParameters();
+ return cast<VarTemplateDecl *>(P)->getTemplateParameters();
+ }
+ case Decl::Kind::VarTemplatePartialSpecialization:
+ return cast<VarTemplatePartialSpecializationDecl>(D)
+ ->getTemplateParameters();
+ case Decl::Kind::TemplateTemplateParm:
+ return cast<TemplateTemplateParmDecl>(D)->getTemplateParameters();
+ case Decl::Kind::Concept:
+ return cast<ConceptDecl>(D)->getTemplateParameters();
+ default:
+ llvm_unreachable("Unhandled templated declaration kind");
+ }
+}
diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp
index b2232ddfced3..c1219041a466 100644
--- a/clang/lib/AST/DeclarationName.cpp
+++ b/clang/lib/AST/DeclarationName.cpp
@@ -72,15 +72,9 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
}
unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs();
for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) {
- switch (LHSSelector.getNameForSlot(I).compare(
- RHSSelector.getNameForSlot(I))) {
- case -1:
- return -1;
- case 1:
- return 1;
- default:
- break;
- }
+ if (int Compare = LHSSelector.getNameForSlot(I).compare(
+ RHSSelector.getNameForSlot(I)))
+ return Compare;
}
return compareInt(LN, RN);
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index ca477e6500c5..67862a8692ac 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -37,6 +37,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstring>
+#include <optional>
using namespace clang;
const Expr *Expr::getBestDynamicClassTypeExpr() const {
@@ -203,6 +204,88 @@ bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
return false;
}
+bool Expr::isFlexibleArrayMemberLike(
+ ASTContext &Context,
+ LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
+ bool IgnoreTemplateOrMacroSubstitution) const {
+
+ // For compatibility with existing code, we treat arrays of length 0 or
+ // 1 as flexible array members.
+ const auto *CAT = Context.getAsConstantArrayType(getType());
+ if (CAT) {
+ llvm::APInt Size = CAT->getSize();
+
+ using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+
+ if (StrictFlexArraysLevel == FAMKind::IncompleteOnly)
+ return false;
+
+ // GCC extension, only allowed to represent a FAM.
+ if (Size == 0)
+ return true;
+
+ if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
+ return false;
+
+ if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2))
+ return false;
+ } else if (!Context.getAsIncompleteArrayType(getType()))
+ return false;
+
+ const Expr *E = IgnoreParens();
+
+ const NamedDecl *ND = nullptr;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
+ ND = DRE->getDecl();
+ else if (const auto *ME = dyn_cast<MemberExpr>(E))
+ ND = ME->getMemberDecl();
+ else if (const auto *IRE = dyn_cast<ObjCIvarRefExpr>(E))
+ return IRE->getDecl()->getNextIvar() == nullptr;
+
+ if (!ND)
+ return false;
+
+ // A flexible array member must be the last member in the class.
+ // FIXME: If the base type of the member expr is not FD->getParent(),
+ // this should not be treated as a flexible array member access.
+ if (const auto *FD = dyn_cast<FieldDecl>(ND)) {
+ // GCC treats an array memeber of a union as an FAM if the size is one or
+ // zero.
+ if (CAT) {
+ llvm::APInt Size = CAT->getSize();
+ if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne()))
+ return true;
+ }
+
+ // Don't consider sizes resulting from macro expansions or template argument
+ // substitution to form C89 tail-padded arrays.
+ if (IgnoreTemplateOrMacroSubstitution) {
+ TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
+ while (TInfo) {
+ TypeLoc TL = TInfo->getTypeLoc();
+ // Look through typedefs.
+ if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
+ const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
+ TInfo = TDL->getTypeSourceInfo();
+ continue;
+ }
+ if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+ }
+ break;
+ }
+ }
+
+ RecordDecl::field_iterator FI(
+ DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
+ return ++FI == FD->getParent()->field_end();
+ }
+
+ return false;
+}
+
const ValueDecl *
Expr::getAsBuiltinConstantDeclRef(const ASTContext &Context) const {
Expr::EvalResult Eval;
@@ -277,7 +360,7 @@ ConstantExpr::getStorageKind(const APValue &Value) {
case APValue::Int:
if (!Value.getInt().needsCleanup())
return ConstantExpr::RSK_Int64;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return ConstantExpr::RSK_APValue;
}
@@ -562,10 +645,10 @@ std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context) const {
std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context,
QualType Ty) {
auto MangleCallback = [](ASTContext &Ctx,
- const NamedDecl *ND) -> llvm::Optional<unsigned> {
+ const NamedDecl *ND) -> std::optional<unsigned> {
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND))
return RD->getDeviceLambdaManglingNumber();
- return llvm::None;
+ return std::nullopt;
};
std::unique_ptr<MangleContext> Ctx{ItaniumMangleContext::create(
@@ -2633,7 +2716,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
}
// Fallthrough for generic call handling.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case CallExprClass:
case CXXMemberCallExprClass:
@@ -3562,6 +3645,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ShuffleVectorExprClass:
case ConvertVectorExprClass:
case AsTypeExprClass:
+ case CXXParenListInitExprClass:
// These have a side-effect if any subexpression does.
break;
@@ -3609,7 +3693,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
DCE->getCastKind() == CK_Dynamic)
return true;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ImplicitCastExprClass:
case CStyleCastExprClass:
case CXXStaticCastExprClass:
@@ -3857,7 +3941,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
if (getType().isNull())
return NPCK_NotNull;
- // C++11 nullptr_t is always a null pointer constant.
+ // C++11/C2x nullptr_t is always a null pointer constant.
if (getType()->isNullPtrType())
return NPCK_CXX11_nullptr;
@@ -4451,7 +4535,8 @@ DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C,
OK_Ordinary) {
BaseAndUpdaterExprs[0] = baseExpr;
- InitListExpr *ILE = new (C) InitListExpr(C, lBraceLoc, None, rBraceLoc);
+ InitListExpr *ILE =
+ new (C) InitListExpr(C, lBraceLoc, std::nullopt, rBraceLoc);
ILE->setType(baseExpr->getType());
BaseAndUpdaterExprs[1] = ILE;
@@ -4831,7 +4916,7 @@ RecoveryExpr::RecoveryExpr(ASTContext &Ctx, QualType T, SourceLocation BeginLoc,
OK_Ordinary),
BeginLoc(BeginLoc), EndLoc(EndLoc), NumExprs(SubExprs.size()) {
assert(!T.isNull());
- assert(llvm::all_of(SubExprs, [](Expr* E) { return E != nullptr; }));
+ assert(!llvm::is_contained(SubExprs, nullptr));
llvm::copy(SubExprs, getTrailingObjects<Expr *>());
setDependence(computeDependence(this));
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 891105692980..2a9e33595013 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -38,6 +38,7 @@
#include <cstddef>
#include <cstring>
#include <memory>
+#include <optional>
using namespace clang;
@@ -182,7 +183,7 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
bool UsualArrayDeleteWantsSize,
ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
- Optional<Expr *> ArraySize,
+ std::optional<Expr *> ArraySize,
InitializationStyle InitializationStyle,
Expr *Initializer, QualType Ty,
TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
@@ -244,7 +245,7 @@ CXXNewExpr::Create(const ASTContext &Ctx, bool IsGlobalNew,
FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete,
bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize,
ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
- Optional<Expr *> ArraySize,
+ std::optional<Expr *> ArraySize,
InitializationStyle InitializationStyle, Expr *Initializer,
QualType Ty, TypeSourceInfo *AllocatedTypeInfo,
SourceRange Range, SourceRange DirectInitRange) {
@@ -314,7 +315,7 @@ QualType CXXDeleteExpr::getDestroyedType() const {
// CXXPseudoDestructorExpr
PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
: Type(Info) {
- Location = Info->getTypeLoc().getLocalSourceRange().getBegin();
+ Location = Info->getTypeLoc().getBeginLoc();
}
CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(
@@ -341,7 +342,7 @@ QualType CXXPseudoDestructorExpr::getDestroyedType() const {
SourceLocation CXXPseudoDestructorExpr::getEndLoc() const {
SourceLocation End = DestroyedType.getLocation();
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
- End = TInfo->getTypeLoc().getLocalSourceRange().getEnd();
+ End = TInfo->getTypeLoc().getSourceRange().getEnd();
return End;
}
@@ -949,9 +950,43 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
return cast<FunctionDecl>(getCalleeDecl())->getLiteralIdentifier();
}
+CXXDefaultArgExpr *CXXDefaultArgExpr::CreateEmpty(const ASTContext &C,
+ bool HasRewrittenInit) {
+ size_t Size = totalSizeToAlloc<Expr *>(HasRewrittenInit);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+ return new (Mem) CXXDefaultArgExpr(EmptyShell(), HasRewrittenInit);
+}
+
+CXXDefaultArgExpr *CXXDefaultArgExpr::Create(const ASTContext &C,
+ SourceLocation Loc,
+ ParmVarDecl *Param,
+ Expr *RewrittenExpr,
+ DeclContext *UsedContext) {
+ size_t Size = totalSizeToAlloc<Expr *>(RewrittenExpr != nullptr);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+ return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
+ RewrittenExpr, UsedContext);
+}
+
+Expr *CXXDefaultArgExpr::getExpr() {
+ return CXXDefaultArgExprBits.HasRewrittenInit ? getAdjustedRewrittenExpr()
+ : getParam()->getDefaultArg();
+}
+
+Expr *CXXDefaultArgExpr::getAdjustedRewrittenExpr() {
+ assert(hasRewrittenInit() &&
+ "expected this CXXDefaultArgExpr to have a rewritten init.");
+ Expr *Init = getRewrittenExpr();
+ if (auto *E = dyn_cast_if_present<FullExpr>(Init))
+ if (!isa<ConstantExpr>(E))
+ return E->getSubExpr();
+ return Init;
+}
+
CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx,
SourceLocation Loc, FieldDecl *Field,
- QualType Ty, DeclContext *UsedContext)
+ QualType Ty, DeclContext *UsedContext,
+ Expr *RewrittenInitExpr)
: Expr(CXXDefaultInitExprClass, Ty.getNonLValueExprType(Ctx),
Ty->isLValueReferenceType() ? VK_LValue
: Ty->isRValueReferenceType() ? VK_XValue
@@ -959,11 +994,43 @@ CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx,
/*FIXME*/ OK_Ordinary),
Field(Field), UsedContext(UsedContext) {
CXXDefaultInitExprBits.Loc = Loc;
+ CXXDefaultInitExprBits.HasRewrittenInit = RewrittenInitExpr != nullptr;
+
+ if (CXXDefaultInitExprBits.HasRewrittenInit)
+ *getTrailingObjects<Expr *>() = RewrittenInitExpr;
+
assert(Field->hasInClassInitializer());
setDependence(computeDependence(this));
}
+CXXDefaultInitExpr *CXXDefaultInitExpr::CreateEmpty(const ASTContext &C,
+ bool HasRewrittenInit) {
+ size_t Size = totalSizeToAlloc<Expr *>(HasRewrittenInit);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultInitExpr));
+ return new (Mem) CXXDefaultInitExpr(EmptyShell(), HasRewrittenInit);
+}
+
+CXXDefaultInitExpr *CXXDefaultInitExpr::Create(const ASTContext &Ctx,
+ SourceLocation Loc,
+ FieldDecl *Field,
+ DeclContext *UsedContext,
+ Expr *RewrittenInitExpr) {
+
+ size_t Size = totalSizeToAlloc<Expr *>(RewrittenInitExpr != nullptr);
+ auto *Mem = Ctx.Allocate(Size, alignof(CXXDefaultInitExpr));
+ return new (Mem) CXXDefaultInitExpr(Ctx, Loc, Field, Field->getType(),
+ UsedContext, RewrittenInitExpr);
+}
+
+Expr *CXXDefaultInitExpr::getExpr() {
+ assert(Field->getInClassInitializer() && "initializer hasn't been parsed");
+ if (hasRewrittenInit())
+ return getRewrittenExpr();
+
+ return Field->getInClassInitializer();
+}
+
CXXTemporary *CXXTemporary::Create(const ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
@@ -1087,7 +1154,7 @@ CXXConstructExpr::CXXConstructExpr(StmtClass SC, EmptyShell Empty,
: Expr(SC, Empty), NumArgs(NumArgs) {}
LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
- LambdaCaptureKind Kind, VarDecl *Var,
+ LambdaCaptureKind Kind, ValueDecl *Var,
SourceLocation EllipsisLoc)
: DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) {
unsigned Bits = 0;
@@ -1097,7 +1164,7 @@ LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
switch (Kind) {
case LCK_StarThis:
Bits |= Capture_ByCopy;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LCK_This:
assert(!Var && "'this' capture cannot have a variable!");
Bits |= Capture_This;
@@ -1105,7 +1172,7 @@ LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
case LCK_ByCopy:
Bits |= Capture_ByCopy;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LCK_ByRef:
assert(Var && "capture must have a variable!");
break;
@@ -1211,16 +1278,16 @@ const CompoundStmt *LambdaExpr::getCompoundStmtBody() const {
}
bool LambdaExpr::isInitCapture(const LambdaCapture *C) const {
- return (C->capturesVariable() && C->getCapturedVar()->isInitCapture() &&
- (getCallOperator() == C->getCapturedVar()->getDeclContext()));
+ return C->capturesVariable() && C->getCapturedVar()->isInitCapture() &&
+ getCallOperator() == C->getCapturedVar()->getDeclContext();
}
LambdaExpr::capture_iterator LambdaExpr::capture_begin() const {
- return getLambdaClass()->getLambdaData().Captures;
+ return getLambdaClass()->captures_begin();
}
LambdaExpr::capture_iterator LambdaExpr::capture_end() const {
- return capture_begin() + capture_size();
+ return getLambdaClass()->captures_end();
}
LambdaExpr::capture_range LambdaExpr::captures() const {
@@ -1232,9 +1299,8 @@ LambdaExpr::capture_iterator LambdaExpr::explicit_capture_begin() const {
}
LambdaExpr::capture_iterator LambdaExpr::explicit_capture_end() const {
- struct CXXRecordDecl::LambdaDefinitionData &Data
- = getLambdaClass()->getLambdaData();
- return Data.Captures + Data.NumExplicitCaptures;
+ return capture_begin() +
+ getLambdaClass()->getLambdaData().NumExplicitCaptures;
}
LambdaExpr::capture_range LambdaExpr::explicit_captures() const {
@@ -1555,12 +1621,12 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() {
return Record;
}
-SizeOfPackExpr *
-SizeOfPackExpr::Create(ASTContext &Context, SourceLocation OperatorLoc,
- NamedDecl *Pack, SourceLocation PackLoc,
- SourceLocation RParenLoc,
- Optional<unsigned> Length,
- ArrayRef<TemplateArgument> PartialArgs) {
+SizeOfPackExpr *SizeOfPackExpr::Create(ASTContext &Context,
+ SourceLocation OperatorLoc,
+ NamedDecl *Pack, SourceLocation PackLoc,
+ SourceLocation RParenLoc,
+ std::optional<unsigned> Length,
+ ArrayRef<TemplateArgument> PartialArgs) {
void *Storage =
Context.Allocate(totalSizeToAlloc<TemplateArgument>(PartialArgs.size()));
return new (Storage) SizeOfPackExpr(Context.getSizeType(), OperatorLoc, Pack,
@@ -1574,6 +1640,11 @@ SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context,
return new (Storage) SizeOfPackExpr(EmptyShell(), NumPartialArgs);
}
+NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
+ return cast<NonTypeTemplateParmDecl>(
+ getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]);
+}
+
QualType SubstNonTypeTemplateParmExpr::getParameterType(
const ASTContext &Context) const {
// Note that, for a class type NTTP, we will have an lvalue of type 'const
@@ -1584,17 +1655,24 @@ QualType SubstNonTypeTemplateParmExpr::getParameterType(
}
SubstNonTypeTemplateParmPackExpr::SubstNonTypeTemplateParmPackExpr(
- QualType T, ExprValueKind ValueKind, NonTypeTemplateParmDecl *Param,
- SourceLocation NameLoc, const TemplateArgument &ArgPack)
+ QualType T, ExprValueKind ValueKind, SourceLocation NameLoc,
+ const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index)
: Expr(SubstNonTypeTemplateParmPackExprClass, T, ValueKind, OK_Ordinary),
- Param(Param), Arguments(ArgPack.pack_begin()),
- NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) {
+ AssociatedDecl(AssociatedDecl), Arguments(ArgPack.pack_begin()),
+ NumArguments(ArgPack.pack_size()), Index(Index), NameLoc(NameLoc) {
+ assert(AssociatedDecl != nullptr);
setDependence(ExprDependence::TypeValueInstantiation |
ExprDependence::UnexpandedPack);
}
+NonTypeTemplateParmDecl *
+SubstNonTypeTemplateParmPackExpr::getParameterPack() const {
+ return cast<NonTypeTemplateParmDecl>(
+ getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]);
+}
+
TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
- return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments));
+ return TemplateArgument(llvm::ArrayRef(Arguments, NumArguments));
}
FunctionParmPackExpr::FunctionParmPackExpr(QualType T, VarDecl *ParamPack,
@@ -1746,3 +1824,21 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx,
alignof(CUDAKernelCallExpr));
return new (Mem) CUDAKernelCallExpr(NumArgs, HasFPFeatures, Empty);
}
+
+CXXParenListInitExpr *
+CXXParenListInitExpr::Create(ASTContext &C, ArrayRef<Expr *> Args, QualType T,
+ unsigned NumUserSpecifiedExprs,
+ SourceLocation InitLoc, SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Args.size()));
+ return new (Mem) CXXParenListInitExpr(Args, T, NumUserSpecifiedExprs, InitLoc,
+ LParenLoc, RParenLoc);
+}
+
+CXXParenListInitExpr *CXXParenListInitExpr::CreateEmpty(ASTContext &C,
+ unsigned NumExprs,
+ EmptyShell Empty) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumExprs),
+ alignof(CXXParenListInitExpr));
+ return new (Mem) CXXParenListInitExpr(Empty, NumExprs);
+}
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index 6c122cac2c60..12193b7812f9 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -160,7 +160,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXPseudoDestructorExprClass:
case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::CXXNewExprClass:
- case Expr::CXXThisExprClass:
case Expr::CXXNullPtrLiteralExprClass:
case Expr::ImaginaryLiteralClass:
case Expr::GNUNullExprClass:
@@ -205,6 +204,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::RequiresExprClass:
return Cl::CL_PRValue;
+ // Make HLSL this reference-like
+ case Expr::CXXThisExprClass:
+ return Lang.HLSL ? Cl::CL_LValue : Cl::CL_PRValue;
+
case Expr::ConstantExprClass:
return ClassifyInternal(Ctx, cast<ConstantExpr>(E)->getSubExpr());
@@ -442,6 +445,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::SYCLUniqueStableNameExprClass:
return Cl::CL_PRValue;
break;
+
+ case Expr::CXXParenListInitExprClass:
+ if (isa<ArrayType>(E->getType()))
+ return Cl::CL_ArrayTemporary;
+ return Cl::CL_ClassTemporary;
}
llvm_unreachable("unhandled expression kind in classification");
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
index c17453fb45fb..fc8f1eb2abf1 100644
--- a/clang/lib/AST/ExprConcepts.cpp
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -35,16 +35,15 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
NamedConcept, ArgsAsWritten),
- NumTemplateArgs(ConvertedArgs.size()),
+ SpecDecl(SpecDecl),
Satisfaction(Satisfaction
? ASTConstraintSatisfaction::Create(C, *Satisfaction)
: nullptr) {
- setTemplateArguments(ConvertedArgs);
setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
// Currently guaranteed by the fact concepts can only be at namespace-scope.
@@ -56,50 +55,34 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
"should not be value-dependent");
}
-ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
- unsigned NumTemplateArgs)
- : Expr(ConceptSpecializationExprClass, Empty),
- NumTemplateArgs(NumTemplateArgs) {}
+ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
+ : Expr(ConceptSpecializationExprClass, Empty) {}
-void ConceptSpecializationExpr::setTemplateArguments(
- ArrayRef<TemplateArgument> Converted) {
- assert(Converted.size() == NumTemplateArgs);
- std::uninitialized_copy(Converted.begin(), Converted.end(),
- getTrailingObjects<TemplateArgument>());
-}
-
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(const ASTContext &C,
- NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc,
- DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl,
- ConceptDecl *NamedConcept,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- ConvertedArgs.size()));
- return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
- ConceptNameInfo, FoundDecl,
- NamedConcept, ArgsAsWritten,
- ConvertedArgs, Satisfaction);
+ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
+ const ASTContext &C, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ const ConstraintSatisfaction *Satisfaction) {
+ return new (C) ConceptSpecializationExpr(
+ C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
+ ArgsAsWritten, SpecDecl, Satisfaction);
}
ConceptSpecializationExpr::ConceptSpecializationExpr(
const ASTContext &C, ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction, bool Dependent,
bool ContainsUnexpandedParameterPack)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
DeclarationNameInfo(), NamedConcept, NamedConcept,
nullptr),
- NumTemplateArgs(ConvertedArgs.size()),
+ SpecDecl(SpecDecl),
Satisfaction(Satisfaction
? ASTConstraintSatisfaction::Create(C, *Satisfaction)
: nullptr) {
- setTemplateArguments(ConvertedArgs);
ExprDependence D = ExprDependence::None;
if (!Satisfaction)
D |= ExprDependence::Value;
@@ -110,26 +93,14 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
setDependence(D);
}
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(const ASTContext &C,
- ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction,
- bool Dependent,
- bool ContainsUnexpandedParameterPack) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- ConvertedArgs.size()));
- return new (Buffer) ConceptSpecializationExpr(
- C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
- ContainsUnexpandedParameterPack);
-}
-
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
- unsigned NumTemplateArgs) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- NumTemplateArgs));
- return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
+ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
+ const ASTContext &C, ConceptDecl *NamedConcept,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ const ConstraintSatisfaction *Satisfaction, bool Dependent,
+ bool ContainsUnexpandedParameterPack) {
+ return new (C)
+ ConceptSpecializationExpr(C, NamedConcept, SpecDecl, Satisfaction,
+ Dependent, ContainsUnexpandedParameterPack);
}
const TypeConstraint *
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 9d92c848ccb8..912a210fd254 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -52,13 +52,14 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFixedPoint.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <functional>
+#include <optional>
#define DEBUG_TYPE "exprconstant"
@@ -68,7 +69,6 @@ using llvm::APInt;
using llvm::APSInt;
using llvm::APFloat;
using llvm::FixedPointSemantics;
-using llvm::Optional;
namespace {
struct LValue;
@@ -578,7 +578,7 @@ namespace {
/// LambdaCaptureFields - Mapping from captured variables/this to
/// corresponding data members in the closure class.
- llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
FieldDecl *LambdaThisCaptureField;
CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
@@ -592,11 +592,6 @@ namespace {
auto LB = Temporaries.lower_bound(KV);
if (LB != Temporaries.end() && LB->first == KV)
return &LB->second;
- // Pair (Key,Version) wasn't found in the map. Check that no elements
- // in the map have 'Key' as their key.
- assert((LB == Temporaries.end() || LB->first.first != Key) &&
- (LB == Temporaries.begin() || std::prev(LB)->first.first != Key) &&
- "Element with key 'Key' found in map");
return nullptr;
}
@@ -660,6 +655,19 @@ namespace {
CallStackFrame &Frame;
const LValue *OldThis;
};
+
+ // A shorthand time trace scope struct, prints source range, for example
+ // {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
+ class ExprTimeTraceScope {
+ public:
+ ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name)
+ : TimeScope(Name, [E, &Ctx] {
+ return E->getSourceRange().printToString(Ctx.getSourceManager());
+ }) {}
+
+ private:
+ llvm::TimeTraceScope TimeScope;
+ };
}
static bool HandleDestruction(EvalInfo &Info, const Expr *E,
@@ -917,10 +925,6 @@ namespace {
/// fold (not just why it's not strictly a constant expression)?
bool HasFoldFailureDiagnostic;
- /// Whether or not we're in a context where the front end requires a
- /// 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).
@@ -976,8 +980,7 @@ namespace {
BottomFrame(*this, SourceLocation(), nullptr, nullptr, CallRef()),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false), InConstantContext(false),
- EvalMode(Mode) {}
+ HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
~EvalInfo() {
discardCleanups();
@@ -1036,8 +1039,8 @@ namespace {
APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
- Optional<DynAlloc*> lookupDynamicAlloc(DynamicAllocLValue DA) {
- Optional<DynAlloc*> Result;
+ std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
+ std::optional<DynAlloc *> Result;
auto It = HeapAllocs.find(DA);
if (It != HeapAllocs.end())
Result = &It->second;
@@ -1132,7 +1135,7 @@ namespace {
if (!HasFoldFailureDiagnostic)
break;
// We've already failed to fold something. Keep that diagnostic.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case EM_ConstantExpression:
case EM_ConstantExpressionUnevaluated:
setActiveDiagnostic(false);
@@ -1219,7 +1222,7 @@ namespace {
/// (Foo(), 1) // use noteSideEffect
/// (Foo() || true) // use noteSideEffect
/// Foo() + 1 // use noteFailure
- LLVM_NODISCARD bool noteFailure() {
+ [[nodiscard]] bool noteFailure() {
// Failure when evaluating some expression often means there is some
// subexpression whose evaluation was skipped. Therefore, (because we
// don't track whether we skipped an expression when unwinding after an
@@ -1954,8 +1957,8 @@ static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
return true;
}
-/// Should this call expression be treated as a constant?
-static bool IsConstantCall(const CallExpr *E) {
+/// Should this call expression be treated as a no-op?
+static bool IsNoOpCall(const CallExpr *E) {
unsigned Builtin = E->getBuiltinCallee();
return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
@@ -2006,7 +2009,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
case Expr::ObjCBoxedExprClass:
return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer();
case Expr::CallExprClass:
- return IsConstantCall(cast<CallExpr>(E));
+ return IsNoOpCall(cast<CallExpr>(E));
// For GCC compatibility, &&label has static storage duration.
case Expr::AddrLabelExprClass:
return true;
@@ -2095,7 +2098,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
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))
+ if (std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA))
Info.Note((*Alloc)->AllocExpr->getExprLoc(),
diag::note_constexpr_dynamic_alloc_here);
}
@@ -2174,12 +2177,10 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// assumed to be global here.
if (!IsGlobalLValue(Base)) {
if (Info.getLangOpts().CPlusPlus11) {
- const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
Info.FFDiag(Loc, diag::note_constexpr_non_global, 1)
- << IsReferenceType << !Designator.Entries.empty()
- << !!VD << VD;
-
- auto *VarD = dyn_cast_or_null<VarDecl>(VD);
+ << IsReferenceType << !Designator.Entries.empty() << !!BaseVD
+ << BaseVD;
+ auto *VarD = dyn_cast_or_null<VarDecl>(BaseVD);
if (VarD && VarD->isConstexpr()) {
// Non-static local constexpr variables have unintuitive semantics:
// constexpr int a = 1;
@@ -2470,6 +2471,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
// A null base expression indicates a null pointer. These are always
// evaluatable, and they are false unless the offset is zero.
if (!Value.getLValueBase()) {
+ // TODO: Should a non-null pointer with an offset of zero evaluate to true?
Result = !Value.getLValueOffset().isZero();
return true;
}
@@ -2482,6 +2484,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
}
static bool HandleConversionToBool(const APValue &Val, bool &Result) {
+ // TODO: This function should produce notes if it fails.
switch (Val.getKind()) {
case APValue::None:
case APValue::Indeterminate:
@@ -2506,6 +2509,9 @@ static bool HandleConversionToBool(const APValue &Val, bool &Result) {
case APValue::LValue:
return EvalPointerValueAsBool(Val, Result);
case APValue::MemberPointer:
+ if (Val.getMemberPointerDecl() && Val.getMemberPointerDecl()->isWeak()) {
+ return false;
+ }
Result = Val.getMemberPointerDecl();
return true;
case APValue::Vector:
@@ -2636,14 +2642,9 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
QualType SrcType, const APSInt &Value,
QualType DestType, APFloat &Result) {
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
- APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(),
- APFloat::rmNearestTiesToEven);
- if (!Info.InConstantContext && St != llvm::APFloatBase::opOK &&
- FPO.isFPConstrained()) {
- Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
- return false;
- }
- return true;
+ llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
+ APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(), RM);
+ return checkFloatingPointResult(Info, E, St);
}
static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
@@ -2743,6 +2744,7 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
BinaryOperatorKind Opcode, APSInt RHS,
APSInt &Result) {
+ bool HandleOverflowResult = true;
switch (Opcode) {
default:
Info.FFDiag(E);
@@ -2765,14 +2767,14 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
Info.FFDiag(E, diag::note_expr_divide_by_zero);
return false;
}
- Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
// Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports
// this operation and gives the two's complement result.
if (RHS.isNegative() && RHS.isAllOnes() && LHS.isSigned() &&
LHS.isMinSignedValue())
- return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1),
- E->getType());
- return true;
+ HandleOverflowResult = HandleOverflow(
+ Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
+ Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ return HandleOverflowResult;
case BO_Shl: {
if (Info.getLangOpts().OpenCL)
// OpenCL 6.3j: shift values are effectively % word size of LHS.
@@ -3647,9 +3649,9 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if ((ObjType.isConstQualified() || ObjType.isVolatileQualified()) &&
ObjType->isRecordType() &&
Info.isEvaluatingCtorDtor(
- Obj.Base, llvm::makeArrayRef(Sub.Entries.begin(),
- Sub.Entries.begin() + I)) !=
- ConstructionPhase::None) {
+ Obj.Base,
+ llvm::ArrayRef(Sub.Entries.begin(), Sub.Entries.begin() + I)) !=
+ ConstructionPhase::None) {
ObjType = Info.Ctx.getCanonicalType(ObjType);
ObjType.removeLocalConst();
ObjType.removeLocalVolatile();
@@ -4129,7 +4131,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
return CompleteObject();
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
- Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA);
+ std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
if (!Alloc) {
Info.FFDiag(E, diag::note_constexpr_access_deleted_object) << AK;
return CompleteObject();
@@ -4844,6 +4846,8 @@ enum EvalStmtResult {
}
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
+ if (VD->isInvalidDecl())
+ return false;
// We don't need to evaluate the initializer for a static local.
if (!VD->hasLocalStorage())
return true;
@@ -5040,8 +5044,10 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
static bool CheckLocalVariableDeclaration(EvalInfo &Info, const VarDecl *VD) {
// An expression E is a core constant expression unless the evaluation of E
// would evaluate one of the following: [C++2b] - a control flow that passes
- // through a declaration of a variable with static or thread storage duration.
- if (VD->isLocalVarDecl() && VD->isStaticLocal()) {
+ // through a declaration of a variable with static or thread storage duration
+ // unless that variable is usable in constant expressions.
+ if (VD->isLocalVarDecl() && VD->isStaticLocal() &&
+ !VD->isUsableInConstantExpressions(Info.Ctx)) {
Info.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
<< (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
return false;
@@ -5663,13 +5669,15 @@ static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator,
}
/// Determine the dynamic type of an object.
-static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
- LValue &This, AccessKinds AK) {
+static std::optional<DynamicType> ComputeDynamicType(EvalInfo &Info,
+ const Expr *E,
+ LValue &This,
+ AccessKinds AK) {
// If we don't have an lvalue denoting an object of class type, there is no
// meaningful dynamic type. (We consider objects of non-class type to have no
// dynamic type.)
if (!checkDynamicType(Info, E, This, AK, true))
- return None;
+ return std::nullopt;
// Refuse to compute a dynamic type in the presence of virtual bases. This
// shouldn't happen other than in constant-folding situations, since literal
@@ -5681,7 +5689,7 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
This.Designator.MostDerivedType->getAsCXXRecordDecl();
if (!Class || Class->getNumVBases()) {
Info.FFDiag(E);
- return None;
+ return std::nullopt;
}
// FIXME: For very deep class hierarchies, it might be beneficial to use a
@@ -5714,14 +5722,14 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
// 'This', so that object has not yet begun its period of construction and
// any polymorphic operation on it results in undefined behavior.
Info.FFDiag(E);
- return None;
+ return std::nullopt;
}
/// Perform virtual dispatch.
static const CXXMethodDecl *HandleVirtualDispatch(
EvalInfo &Info, const Expr *E, LValue &This, const CXXMethodDecl *Found,
llvm::SmallVectorImpl<QualType> &CovariantAdjustmentPath) {
- Optional<DynamicType> DynType = ComputeDynamicType(
+ std::optional<DynamicType> DynType = ComputeDynamicType(
Info, E, This,
isa<CXXDestructorDecl>(Found) ? AK_Destroy : AK_MemberCall);
if (!DynType)
@@ -5839,7 +5847,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
// For all the other cases, we need the pointer to point to an object within
// its lifetime / period of construction / destruction, and we need to know
// its dynamic type.
- Optional<DynamicType> DynType =
+ std::optional<DynamicType> DynType =
ComputeDynamicType(Info, E, Ptr, AK_DynamicCast);
if (!DynType)
return false;
@@ -6728,10 +6736,10 @@ static const FunctionDecl *getVirtualOperatorDelete(QualType T) {
/// 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) {
+/// a diagnostic and returns std::nullopt.
+static std::optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
+ const LValue &Pointer,
+ DynAlloc::Kind DeallocKind) {
auto PointerAsString = [&] {
return Pointer.toString(Info.Ctx, Info.Ctx.VoidPtrTy);
};
@@ -6742,13 +6750,13 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
<< PointerAsString();
if (Pointer.Base)
NoteLValueLocation(Info, Pointer.Base);
- return None;
+ return std::nullopt;
}
- Optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
+ std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
if (!Alloc) {
Info.FFDiag(E, diag::note_constexpr_double_delete);
- return None;
+ return std::nullopt;
}
QualType AllocType = Pointer.Base.getDynamicAllocType();
@@ -6756,7 +6764,7 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
Info.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
<< DeallocKind << (*Alloc)->getKind() << AllocType;
NoteLValueLocation(Info, Pointer.Base);
- return None;
+ return std::nullopt;
}
bool Subobject = false;
@@ -6770,7 +6778,7 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
if (Subobject) {
Info.FFDiag(E, diag::note_constexpr_delete_subobject)
<< PointerAsString() << Pointer.Designator.isOnePastTheEnd();
- return None;
+ return std::nullopt;
}
return Alloc;
@@ -6822,7 +6830,7 @@ class BitCastBuffer {
// FIXME: Its possible under the C++ standard for 'char' to not be 8 bits, but
// we don't support a host or target where that is the case. Still, we should
// use a more generic type in case we ever do.
- SmallVector<Optional<unsigned char>, 32> Bytes;
+ SmallVector<std::optional<unsigned char>, 32> Bytes;
static_assert(std::numeric_limits<unsigned char>::digits >= 8,
"Need at least 8 bit unsigned char");
@@ -6834,9 +6842,8 @@ public:
: Bytes(Width.getQuantity()),
TargetIsLittleEndian(TargetIsLittleEndian) {}
- LLVM_NODISCARD
- bool readObject(CharUnits Offset, CharUnits Width,
- SmallVectorImpl<unsigned char> &Output) const {
+ [[nodiscard]] bool readObject(CharUnits Offset, CharUnits Width,
+ SmallVectorImpl<unsigned char> &Output) const {
for (CharUnits I = Offset, E = Offset + Width; I != E; ++I) {
// If a byte of an integer is uninitialized, then the whole integer is
// uninitialized.
@@ -7013,12 +7020,12 @@ class APValueToBufferConverter {
}
public:
- static Optional<BitCastBuffer> convert(EvalInfo &Info, const APValue &Src,
- const CastExpr *BCE) {
+ static std::optional<BitCastBuffer>
+ convert(EvalInfo &Info, const APValue &Src, const CastExpr *BCE) {
CharUnits DstSize = Info.Ctx.getTypeSizeInChars(BCE->getType());
APValueToBufferConverter Converter(Info, DstSize, BCE);
if (!Converter.visit(Src, BCE->getSubExpr()->getType()))
- return None;
+ return std::nullopt;
return Converter.Buffer;
}
};
@@ -7036,22 +7043,22 @@ class BufferToAPValueConverter {
// Emit an unsupported bit_cast type error. Sema refuses to build a bit_cast
// with an invalid type, so anything left is a deficiency on our part (FIXME).
// Ideally this will be unreachable.
- llvm::NoneType unsupportedType(QualType Ty) {
+ std::nullopt_t unsupportedType(QualType Ty) {
Info.FFDiag(BCE->getBeginLoc(),
diag::note_constexpr_bit_cast_unsupported_type)
<< Ty;
- return None;
+ return std::nullopt;
}
- llvm::NoneType unrepresentableValue(QualType Ty, const APSInt &Val) {
+ std::nullopt_t unrepresentableValue(QualType Ty, const APSInt &Val) {
Info.FFDiag(BCE->getBeginLoc(),
diag::note_constexpr_bit_cast_unrepresentable_value)
<< Ty << toString(Val, /*Radix=*/10);
- return None;
+ return std::nullopt;
}
- Optional<APValue> visit(const BuiltinType *T, CharUnits Offset,
- const EnumType *EnumSugar = nullptr) {
+ std::optional<APValue> visit(const BuiltinType *T, CharUnits Offset,
+ const EnumType *EnumSugar = nullptr) {
if (T->isNullPtrType()) {
uint64_t NullValue = Info.Ctx.getTargetNullPointerValue(QualType(T, 0));
return APValue((Expr *)nullptr,
@@ -7087,7 +7094,7 @@ class BufferToAPValueConverter {
Info.FFDiag(BCE->getExprLoc(),
diag::note_constexpr_bit_cast_indet_dest)
<< DisplayType << Info.Ctx.getLangOpts().CharIsSigned;
- return None;
+ return std::nullopt;
}
return APValue::IndeterminateValue();
@@ -7119,7 +7126,7 @@ class BufferToAPValueConverter {
return unsupportedType(QualType(T, 0));
}
- Optional<APValue> visit(const RecordType *RTy, CharUnits Offset) {
+ std::optional<APValue> visit(const RecordType *RTy, CharUnits Offset) {
const RecordDecl *RD = RTy->getAsRecordDecl();
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -7139,10 +7146,10 @@ class BufferToAPValueConverter {
Info.Ctx.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
continue;
- Optional<APValue> SubObj = visitType(
+ std::optional<APValue> SubObj = visitType(
BS.getType(), Layout.getBaseClassOffset(BaseDecl) + Offset);
if (!SubObj)
- return None;
+ return std::nullopt;
ResultVal.getStructBase(I) = *SubObj;
}
}
@@ -7155,7 +7162,7 @@ class BufferToAPValueConverter {
if (FD->isBitField()) {
Info.FFDiag(BCE->getBeginLoc(),
diag::note_constexpr_bit_cast_unsupported_bitfield);
- return None;
+ return std::nullopt;
}
uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx);
@@ -7165,9 +7172,9 @@ class BufferToAPValueConverter {
CharUnits::fromQuantity(FieldOffsetBits / Info.Ctx.getCharWidth()) +
Offset;
QualType FieldTy = FD->getType();
- Optional<APValue> SubObj = visitType(FieldTy, FieldOffset);
+ std::optional<APValue> SubObj = visitType(FieldTy, FieldOffset);
if (!SubObj)
- return None;
+ return std::nullopt;
ResultVal.getStructField(FieldIdx) = *SubObj;
++FieldIdx;
}
@@ -7175,7 +7182,7 @@ class BufferToAPValueConverter {
return ResultVal;
}
- Optional<APValue> visit(const EnumType *Ty, CharUnits Offset) {
+ std::optional<APValue> visit(const EnumType *Ty, CharUnits Offset) {
QualType RepresentationType = Ty->getDecl()->getIntegerType();
assert(!RepresentationType.isNull() &&
"enum forward decl should be caught by Sema");
@@ -7186,27 +7193,27 @@ class BufferToAPValueConverter {
return visit(AsBuiltin, Offset, /*EnumTy=*/Ty);
}
- Optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) {
+ std::optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) {
size_t Size = Ty->getSize().getLimitedValue();
CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType());
APValue ArrayValue(APValue::UninitArray(), Size, Size);
for (size_t I = 0; I != Size; ++I) {
- Optional<APValue> ElementValue =
+ std::optional<APValue> ElementValue =
visitType(Ty->getElementType(), Offset + I * ElementWidth);
if (!ElementValue)
- return None;
+ return std::nullopt;
ArrayValue.getArrayInitializedElt(I) = std::move(*ElementValue);
}
return ArrayValue;
}
- Optional<APValue> visit(const Type *Ty, CharUnits Offset) {
+ std::optional<APValue> visit(const Type *Ty, CharUnits Offset) {
return unsupportedType(QualType(Ty, 0));
}
- Optional<APValue> visitType(QualType Ty, CharUnits Offset) {
+ std::optional<APValue> visitType(QualType Ty, CharUnits Offset) {
QualType Can = Ty.getCanonicalType();
switch (Can->getTypeClass()) {
@@ -7231,8 +7238,8 @@ class BufferToAPValueConverter {
public:
// Pull out a full value of type DstType.
- static Optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer,
- const CastExpr *BCE) {
+ static std::optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer,
+ const CastExpr *BCE) {
BufferToAPValueConverter Converter(Info, Buffer, BCE);
return Converter.visitType(BCE->getType(), CharUnits::fromQuantity(0));
}
@@ -7321,13 +7328,13 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
return false;
// Read out SourceValue into a char buffer.
- Optional<BitCastBuffer> Buffer =
+ std::optional<BitCastBuffer> Buffer =
APValueToBufferConverter::convert(Info, SourceRValue, BCE);
if (!Buffer)
return false;
// Write out the buffer into a new APValue.
- Optional<APValue> MaybeDestValue =
+ std::optional<APValue> MaybeDestValue =
BufferToAPValueConverter::convert(Info, *Buffer, BCE);
if (!MaybeDestValue)
return false;
@@ -7406,6 +7413,12 @@ protected:
bool ZeroInitialization(const Expr *E) { return Error(E); }
+ bool IsConstantEvaluatedBuiltinCall(const CallExpr *E) {
+ unsigned BuiltinOp = E->getBuiltinCallee();
+ return BuiltinOp != 0 &&
+ Info.Ctx.BuiltinInfo.isConstantEvaluated(BuiltinOp);
+ }
+
public:
ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
@@ -7613,7 +7626,7 @@ public:
const FunctionDecl *FD = nullptr;
LValue *This = nullptr, ThisVal;
- auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
CallRef Call;
@@ -7945,8 +7958,8 @@ 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.
- llvm::SaveAndRestore<bool> NotCheckingForUB(
- Info.CheckingForUndefinedBehavior, false);
+ llvm::SaveAndRestore NotCheckingForUB(Info.CheckingForUndefinedBehavior,
+ false);
const CompoundStmt *CS = E->getSubStmt();
if (CS->body_empty())
@@ -8179,7 +8192,8 @@ public:
return LValueExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_LValueBitCast:
- this->CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ this->CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
if (!Visit(E->getSubExpr()))
return false;
Result.Designator.setInvalid();
@@ -8208,7 +8222,7 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK) {
assert(!E->isValueDependent());
assert(E->isGLValue() || E->getType()->isFunctionType() ||
- E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E));
+ E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E->IgnoreParens()));
return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E);
}
@@ -8317,7 +8331,12 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
}
bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
switch (E->getBuiltinCallee()) {
+ default:
+ return false;
case Builtin::BIas_const:
case Builtin::BIforward:
case Builtin::BImove:
@@ -8424,7 +8443,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
if (!Visit(E->getExprOperand()))
return false;
- Optional<DynamicType> DynType =
+ std::optional<DynamicType> DynType =
ComputeDynamicType(Info, E, Result, AK_TypeId);
if (!DynType)
return false;
@@ -8890,9 +8909,10 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
Result.Designator.setInvalid();
if (SubExpr->getType()->isVoidPointerType())
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 3 << SubExpr->getType();
+ << 3 << SubExpr->getType();
else
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
}
}
if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr)
@@ -8929,7 +8949,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
return ZeroInitialization(E);
case CK_IntegralToPointer: {
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
APValue Value;
if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
@@ -9090,13 +9111,9 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
}
bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
- if (IsConstantCall(E))
- return Success(E);
-
- if (unsigned BuiltinOp = E->getBuiltinCallee())
- return VisitBuiltinCallExpr(E, BuiltinOp);
-
- return visitNonBuiltinCallExpr(E);
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return visitNonBuiltinCallExpr(E);
+ return VisitBuiltinCallExpr(E, E->getBuiltinCallee());
}
// Determine if T is a character type for which we guarantee that
@@ -9107,6 +9124,9 @@ static bool isOneByteCharacterType(QualType T) {
bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
+ if (IsNoOpCall(E))
+ return Success(E);
+
switch (BuiltinOp) {
case Builtin::BIaddressof:
case Builtin::BI__addressof:
@@ -9213,11 +9233,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BIwmemchr:
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
- << /*isConstexpr*/0 << /*isConstructor*/0
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
+ << /*isConstexpr*/ 0 << /*isConstructor*/ 0
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_strchr:
case Builtin::BI__builtin_wcschr:
case Builtin::BI__builtin_memchr:
@@ -9259,7 +9279,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// FIXME: We can compare the bytes in the correct order.
if (IsRawByte && !isOneByteCharacterType(CharTy)) {
Info.FFDiag(E, diag::note_constexpr_memchr_unsupported)
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'")
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str()
<< CharTy;
return false;
}
@@ -9278,7 +9298,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
Desired))
return ZeroInitialization(E);
StopAtNull = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BImemchr:
case Builtin::BI__builtin_memchr:
case Builtin::BI__builtin_char_memchr:
@@ -9291,7 +9311,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BIwcschr:
case Builtin::BI__builtin_wcschr:
StopAtNull = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BIwmemchr:
case Builtin::BI__builtin_wmemchr:
// wcschr and wmemchr are given a wchar_t to look for. Just use it.
@@ -9321,11 +9341,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BIwmemmove:
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
- << /*isConstexpr*/0 << /*isConstructor*/0
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
+ << /*isConstexpr*/ 0 << /*isConstructor*/ 0
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_memcpy:
case Builtin::BI__builtin_memmove:
case Builtin::BI__builtin_wmemcpy:
@@ -9461,10 +9481,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
default:
- break;
+ return false;
}
-
- return visitNonBuiltinCallExpr(E);
}
static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
@@ -9527,7 +9545,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
bool ValueInit = false;
QualType AllocType = E->getAllocatedType();
- if (Optional<const Expr *> ArraySize = E->getArraySize()) {
+ if (std::optional<const Expr *> ArraySize = E->getArraySize()) {
const Expr *Stripped = *ArraySize;
for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
Stripped = ICE->getSubExpr())
@@ -9809,6 +9827,9 @@ namespace {
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
bool VisitBinCmp(const BinaryOperator *E);
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args);
};
}
@@ -9927,8 +9948,13 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
if (E->isTransparent())
return Visit(E->getInit(0));
+ return VisitCXXParenListOrInitListExpr(E, E->inits());
+}
- const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
+bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
+ const Expr *ExprToVisit, ArrayRef<Expr *> Args) {
+ const RecordDecl *RD =
+ ExprToVisit->getType()->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
@@ -9939,7 +9965,16 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
CXXRD && CXXRD->getNumBases());
if (RD->isUnion()) {
- const FieldDecl *Field = E->getInitializedFieldInUnion();
+ const FieldDecl *Field;
+ if (auto *ILE = dyn_cast<InitListExpr>(ExprToVisit)) {
+ Field = ILE->getInitializedFieldInUnion();
+ } else if (auto *PLIE = dyn_cast<CXXParenListInitExpr>(ExprToVisit)) {
+ Field = PLIE->getInitializedFieldInUnion();
+ } else {
+ llvm_unreachable(
+ "Expression is neither an init list nor a C++ paren list");
+ }
+
Result = APValue(Field);
if (!Field)
return true;
@@ -9950,7 +9985,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// Is this difference ever observable for initializer lists which
// we don't build?
ImplicitValueInitExpr VIE(Field->getType());
- const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE;
+ const Expr *InitExpr = Args.empty() ? &VIE : Args[0];
LValue Subobject = This;
if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout))
@@ -9979,8 +10014,8 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// Initialize base classes.
if (CXXRD && CXXRD->getNumBases()) {
for (const auto &Base : CXXRD->bases()) {
- assert(ElementNo < E->getNumInits() && "missing init for base class");
- const Expr *Init = E->getInit(ElementNo);
+ assert(ElementNo < Args.size() && "missing init for base class");
+ const Expr *Init = Args[ElementNo];
LValue Subobject = This;
if (!HandleLValueBase(Info, Init, Subobject, CXXRD, &Base))
@@ -10007,18 +10042,18 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
LValue Subobject = This;
- bool HaveInit = ElementNo < E->getNumInits();
+ bool HaveInit = ElementNo < Args.size();
// FIXME: Diagnostics here should point to the end of the initializer
// list, not the start.
- if (!HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E,
+ if (!HandleLValueMember(Info, HaveInit ? Args[ElementNo] : ExprToVisit,
Subobject, Field, &Layout))
return false;
// Perform an implicit value-initialization for members beyond the end of
// the initializer list.
ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType());
- const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE;
+ const Expr *Init = HaveInit ? Args[ElementNo++] : &VIE;
if (Field->getType()->isIncompleteArrayType()) {
if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) {
@@ -10093,7 +10128,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (ZeroInit && !ZeroInitialization(E, T))
return false;
- auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E, This, Args,
cast<CXXConstructorDecl>(Definition), Info,
Result);
@@ -10504,10 +10539,10 @@ bool VectorExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return Success(LHSValue, E);
}
-static llvm::Optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
- QualType ResultTy,
- UnaryOperatorKind Op,
- APValue Elt) {
+static std::optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
+ QualType ResultTy,
+ UnaryOperatorKind Op,
+ APValue Elt) {
switch (Op) {
case UO_Plus:
// Nothing to do here.
@@ -10550,7 +10585,7 @@ static llvm::Optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
}
default:
// FIXME: Implement the rest of the unary operators.
- return llvm::None;
+ return std::nullopt;
}
}
@@ -10581,7 +10616,7 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
SmallVector<APValue, 4> ResultElements;
for (unsigned EltNum = 0; EltNum < VD->getNumElements(); ++EltNum) {
- llvm::Optional<APValue> Elt = handleVectorUnaryOperator(
+ std::optional<APValue> Elt = handleVectorUnaryOperator(
Info.Ctx, ResultEltTy, Op, SubExprValue.getVectorElt(EltNum));
if (!Elt)
return false;
@@ -10652,6 +10687,11 @@ namespace {
expandStringLiteral(Info, E, Result, AllocType);
return true;
}
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args,
+ const Expr *ArrayFiller,
+ QualType AllocType = QualType());
};
} // end anonymous namespace
@@ -10695,6 +10735,11 @@ static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
if (MaybeElementDependentArrayFiller(ILE->getInit(I)))
return true;
}
+
+ if (ILE->hasArrayFiller() &&
+ MaybeElementDependentArrayFiller(ILE->getArrayFiller()))
+ return true;
+
return false;
}
return true;
@@ -10722,6 +10767,16 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
assert(!E->isTransparent() &&
"transparent array list initialization is not string literal init?");
+ return VisitCXXParenListOrInitListExpr(E, E->inits(), E->getArrayFiller(),
+ AllocType);
+}
+
+bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
+ const Expr *ExprToVisit, ArrayRef<Expr *> Args, const Expr *ArrayFiller,
+ QualType AllocType) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(
+ AllocType.isNull() ? ExprToVisit->getType() : AllocType);
+
bool Success = true;
assert((!Result.isArray() || Result.getArrayInitializedElts() == 0) &&
@@ -10730,13 +10785,12 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
if (Result.isArray() && Result.hasArrayFiller())
Filler = Result.getArrayFiller();
- unsigned NumEltsToInit = E->getNumInits();
+ unsigned NumEltsToInit = Args.size();
unsigned NumElts = CAT->getSize().getZExtValue();
- const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : nullptr;
// If the initializer might depend on the array index, run it for each
// array element.
- if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(FillerExpr))
+ if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(ArrayFiller))
NumEltsToInit = NumElts;
LLVM_DEBUG(llvm::dbgs() << "The number of elements to initialize: "
@@ -10754,10 +10808,9 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
}
LValue Subobject = This;
- Subobject.addArray(Info, E, CAT);
+ Subobject.addArray(Info, ExprToVisit, CAT);
for (unsigned Index = 0; Index != NumEltsToInit; ++Index) {
- const Expr *Init =
- Index < E->getNumInits() ? E->getInit(Index) : FillerExpr;
+ const Expr *Init = Index < Args.size() ? Args[Index] : ArrayFiller;
if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
Info, Subobject, Init) ||
!HandleLValueArrayAdjustment(Info, Init, Subobject,
@@ -10773,9 +10826,10 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
// If we get here, we have a trivial filler, which we can just evaluate
// once and splat over the rest of the array elements.
- assert(FillerExpr && "no array filler for incomplete init list");
+ assert(ArrayFiller && "no array filler for incomplete init list");
return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject,
- FillerExpr) && Success;
+ ArrayFiller) &&
+ Success;
}
bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
@@ -10833,6 +10887,9 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (FinalSize == 0)
return true;
+ bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+ Info, E->getExprLoc(), E->getConstructor(),
+ E->requiresZeroInitialization());
LValue ArrayElt = Subobject;
ArrayElt.addArray(Info, E, CAT);
// We do the whole initialization in two passes, first for just one element,
@@ -10856,19 +10913,26 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
for (unsigned I = OldElts; I < N; ++I)
Value->getArrayInitializedElt(I) = Filler;
- // Initialize the elements.
- for (unsigned I = OldElts; I < N; ++I) {
- if (!VisitCXXConstructExpr(E, ArrayElt,
- &Value->getArrayInitializedElt(I),
- CAT->getElementType()) ||
- !HandleLValueArrayAdjustment(Info, E, ArrayElt,
- CAT->getElementType(), 1))
- return false;
- // When checking for const initilization any diagnostic is considered
- // an error.
- if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
- !Info.keepEvaluatingAfterFailure())
- return false;
+ if (HasTrivialConstructor && N == FinalSize) {
+ // If we have a trivial constructor, only evaluate it once and copy
+ // the result into all the array elements.
+ APValue &FirstResult = Value->getArrayInitializedElt(0);
+ for (unsigned I = OldElts; I < FinalSize; ++I)
+ Value->getArrayInitializedElt(I) = FirstResult;
+ } else {
+ for (unsigned I = OldElts; I < N; ++I) {
+ if (!VisitCXXConstructExpr(E, ArrayElt,
+ &Value->getArrayInitializedElt(I),
+ CAT->getElementType()) ||
+ !HandleLValueArrayAdjustment(Info, E, ArrayElt,
+ CAT->getElementType(), 1))
+ return false;
+ // When checking for const initilization any diagnostic is considered
+ // an error.
+ if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
+ !Info.keepEvaluatingAfterFailure())
+ return false;
+ }
}
}
@@ -10882,6 +10946,15 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
.VisitCXXConstructExpr(E, Type);
}
+bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
+ const CXXParenListInitExpr *E) {
+ assert(dyn_cast<ConstantArrayType>(E->getType()) &&
+ "Expression result is not a constant array type");
+
+ return VisitCXXParenListOrInitListExpr(E, E->getInitExprs(),
+ E->getArrayFiller());
+}
+
//===----------------------------------------------------------------------===//
// Integer Evaluation
//
@@ -11596,15 +11669,31 @@ static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const LValue &LVal) {
// conservative with the last element in structs (if it's an array), so our
// current behavior is more compatible than an explicit list approach would
// be.
- int StrictFlexArraysLevel = Ctx.getLangOpts().StrictFlexArrays;
+ auto isFlexibleArrayMember = [&] {
+ using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+ FAMKind StrictFlexArraysLevel =
+ Ctx.getLangOpts().getStrictFlexArraysLevel();
+
+ if (Designator.isMostDerivedAnUnsizedArray())
+ return true;
+
+ if (StrictFlexArraysLevel == FAMKind::Default)
+ return true;
+
+ if (Designator.getMostDerivedArraySize() == 0 &&
+ StrictFlexArraysLevel != FAMKind::IncompleteOnly)
+ return true;
+
+ if (Designator.getMostDerivedArraySize() == 1 &&
+ StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
+ return true;
+
+ return false;
+ };
+
return LVal.InvalidBase &&
Designator.Entries.size() == Designator.MostDerivedPathLength &&
- Designator.MostDerivedIsArrayElement &&
- (Designator.isMostDerivedAnUnsizedArray() ||
- Designator.getMostDerivedArraySize() == 0 ||
- (Designator.getMostDerivedArraySize() == 1 &&
- StrictFlexArraysLevel < 2) ||
- StrictFlexArraysLevel == 0) &&
+ Designator.MostDerivedIsArrayElement && isFlexibleArrayMember() &&
isDesignatorAtObjectEnd(Ctx, LVal);
}
@@ -11751,10 +11840,9 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
}
bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
- if (unsigned BuiltinOp = E->getBuiltinCallee())
- return VisitBuiltinCallExpr(E, BuiltinOp);
-
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ return VisitBuiltinCallExpr(E, E->getBuiltinCallee());
}
static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
@@ -11788,7 +11876,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
switch (BuiltinOp) {
default:
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ return false;
case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size: {
@@ -12103,11 +12191,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// A call to strlen is not a constant expression.
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
- << /*isConstexpr*/0 << /*isConstructor*/0
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
+ << /*isConstexpr*/ 0 << /*isConstructor*/ 0
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_strlen:
case Builtin::BI__builtin_wcslen: {
// As an extension, we support __builtin_strlen() as a constant expression,
@@ -12128,11 +12216,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// A call to strlen is not a constant expression.
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
- << /*isConstexpr*/0 << /*isConstructor*/0
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
+ << /*isConstexpr*/ 0 << /*isConstructor*/ 0
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_strcmp:
case Builtin::BI__builtin_wcscmp:
case Builtin::BI__builtin_strncmp:
@@ -12184,7 +12272,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
!(isOneByteCharacterType(CharTy1) && isOneByteCharacterType(CharTy2))) {
// FIXME: Consider using our bit_cast implementation to support this.
Info.FFDiag(E, diag::note_constexpr_memcmp_unsupported)
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'")
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str()
<< CharTy1 << CharTy2;
return false;
}
@@ -12886,41 +12974,55 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// Reject differing bases from the normal codepath; we special-case
// comparisons to null.
if (!HasSameBase(LHSValue, RHSValue)) {
+ auto DiagComparison = [&] (unsigned DiagID, bool Reversed = false) {
+ std::string LHS = LHSValue.toString(Info.Ctx, E->getLHS()->getType());
+ std::string RHS = RHSValue.toString(Info.Ctx, E->getRHS()->getType());
+ Info.FFDiag(E, DiagID)
+ << (Reversed ? RHS : LHS) << (Reversed ? LHS : RHS);
+ return false;
+ };
// Inequalities and subtractions between unrelated pointers have
// unspecified or undefined behavior.
- if (!IsEquality) {
- Info.FFDiag(E, diag::note_constexpr_pointer_comparison_unspecified);
- return false;
- }
+ if (!IsEquality)
+ return DiagComparison(
+ diag::note_constexpr_pointer_comparison_unspecified);
// A constant address may compare equal to the address of a symbol.
// The one exception is that address of an object cannot compare equal
// to a null pointer constant.
+ // TODO: Should we restrict this to actual null pointers, and exclude the
+ // case of zero cast to pointer type?
if ((!LHSValue.Base && !LHSValue.Offset.isZero()) ||
(!RHSValue.Base && !RHSValue.Offset.isZero()))
- return Error(E);
+ return DiagComparison(diag::note_constexpr_pointer_constant_comparison,
+ !RHSValue.Base);
// It's implementation-defined whether distinct literals will have
// distinct addresses. In clang, the result of such a comparison is
// unspecified, so it is not a constant expression. However, we do know
// that the address of a literal will be non-null.
if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) &&
LHSValue.Base && RHSValue.Base)
- return Error(E);
+ return DiagComparison(diag::note_constexpr_literal_comparison);
// We can't tell whether weak symbols will end up pointing to the same
// object.
if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue))
- return Error(E);
+ return DiagComparison(diag::note_constexpr_pointer_weak_comparison,
+ !IsWeakLValue(LHSValue));
// We can't compare the address of the start of one object with the
// past-the-end address of another object, per C++ DR1652.
- if ((LHSValue.Base && LHSValue.Offset.isZero() &&
- isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) ||
- (RHSValue.Base && RHSValue.Offset.isZero() &&
- isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue)))
- return Error(E);
+ if (LHSValue.Base && LHSValue.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue))
+ return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
+ true);
+ if (RHSValue.Base && RHSValue.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))
+ return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
+ false);
// We can't tell whether an object is at the same address as another
// zero sized object.
if ((RHSValue.Base && isZeroSized(LHSValue)) ||
(LHSValue.Base && isZeroSized(RHSValue)))
- return Error(E);
+ return DiagComparison(
+ diag::note_constexpr_pointer_comparison_zero_sized);
return Success(CmpResult::Unequal, E);
}
@@ -13024,6 +13126,19 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (!EvaluateMemberPointer(E->getRHS(), RHSValue, Info) || !LHSOK)
return false;
+ // If either operand is a pointer to a weak function, the comparison is not
+ // constant.
+ if (LHSValue.getDecl() && LHSValue.getDecl()->isWeak()) {
+ Info.FFDiag(E, diag::note_constexpr_mem_pointer_weak_comparison)
+ << LHSValue.getDecl();
+ return true;
+ }
+ if (RHSValue.getDecl() && RHSValue.getDecl()->isWeak()) {
+ Info.FFDiag(E, diag::note_constexpr_mem_pointer_weak_comparison)
+ << RHSValue.getDecl();
+ return true;
+ }
+
// C++11 [expr.eq]p2:
// If both operands are null, they compare equal. Otherwise if only one is
// null, they compare unequal.
@@ -13101,6 +13216,11 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
});
}
+bool RecordExprEvaluator::VisitCXXParenListInitExpr(
+ const CXXParenListInitExpr *E) {
+ return VisitCXXParenListOrInitListExpr(E, E->getInitExprs());
+}
+
bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// We don't support assignment in C. C++ assignments don't get here because
// assignment is an lvalue in C++.
@@ -13519,12 +13639,62 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType);
}
+ if (Info.Ctx.getLangOpts().CPlusPlus && Info.InConstantContext &&
+ Info.EvalMode == EvalInfo::EM_ConstantExpression &&
+ DestType->isEnumeralType()) {
+
+ bool ConstexprVar = true;
+
+ // We know if we are here that we are in a context that we might require
+ // a constant expression or a context that requires a constant
+ // value. But if we are initializing a value we don't know if it is a
+ // constexpr variable or not. We can check the EvaluatingDecl to determine
+ // if it constexpr or not. If not then we don't want to emit a diagnostic.
+ if (const auto *VD = dyn_cast_or_null<VarDecl>(
+ Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()))
+ ConstexprVar = VD->isConstexpr();
+
+ const EnumType *ET = dyn_cast<EnumType>(DestType.getCanonicalType());
+ const EnumDecl *ED = ET->getDecl();
+ // Check that the value is within the range of the enumeration values.
+ //
+ // This corressponds to [expr.static.cast]p10 which says:
+ // A value of integral or enumeration type can be explicitly converted
+ // to a complete enumeration type ... If the enumeration type does not
+ // have a fixed underlying type, the value is unchanged if the original
+ // value is within the range of the enumeration values ([dcl.enum]), and
+ // otherwise, the behavior is undefined.
+ //
+ // This was resolved as part of DR2338 which has CD5 status.
+ if (!ED->isFixed()) {
+ llvm::APInt Min;
+ llvm::APInt Max;
+
+ ED->getValueRange(Max, Min);
+ --Max;
+
+ if (ED->getNumNegativeBits() && ConstexprVar &&
+ (Max.slt(Result.getInt().getSExtValue()) ||
+ Min.sgt(Result.getInt().getSExtValue())))
+ Info.Ctx.getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_constexpr_unscoped_enum_out_of_range)
+ << llvm::toString(Result.getInt(), 10) << Min.getSExtValue()
+ << Max.getSExtValue();
+ else if (!ED->getNumNegativeBits() && ConstexprVar &&
+ Max.ult(Result.getInt().getZExtValue()))
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_constexpr_unscoped_enum_out_of_range)
+ << llvm::toString(Result.getInt(),10) << Min.getZExtValue() << Max.getZExtValue();
+ }
+ }
+
return Success(HandleIntToIntCast(Info, E, DestType, SrcType,
Result.getInt()), E);
}
case CK_PointerToIntegral: {
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
LValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
@@ -13878,9 +14048,12 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
}
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
switch (E->getBuiltinCallee()) {
default:
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ return false;
case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_huge_valf:
@@ -13954,6 +14127,42 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Result.copySign(RHS);
return true;
}
+
+ case Builtin::BI__builtin_fmax:
+ case Builtin::BI__builtin_fmaxf:
+ case Builtin::BI__builtin_fmaxl:
+ case Builtin::BI__builtin_fmaxf16:
+ case Builtin::BI__builtin_fmaxf128: {
+ // TODO: Handle sNaN.
+ APFloat RHS(0.);
+ if (!EvaluateFloat(E->getArg(0), Result, Info) ||
+ !EvaluateFloat(E->getArg(1), RHS, Info))
+ return false;
+ // When comparing zeroes, return +0.0 if one of the zeroes is positive.
+ if (Result.isZero() && RHS.isZero() && Result.isNegative())
+ Result = RHS;
+ else if (Result.isNaN() || RHS > Result)
+ Result = RHS;
+ return true;
+ }
+
+ case Builtin::BI__builtin_fmin:
+ case Builtin::BI__builtin_fminf:
+ case Builtin::BI__builtin_fminl:
+ case Builtin::BI__builtin_fminf16:
+ case Builtin::BI__builtin_fminf128: {
+ // TODO: Handle sNaN.
+ APFloat RHS(0.);
+ if (!EvaluateFloat(E->getArg(0), Result, Info) ||
+ !EvaluateFloat(E->getArg(1), RHS, Info))
+ return false;
+ // When comparing zeroes, return -0.0 if one of the zeroes is negative.
+ if (Result.isZero() && RHS.isZero() && RHS.isNegative())
+ Result = RHS;
+ else if (Result.isNaN() || RHS < Result)
+ Result = RHS;
+ return true;
+ }
}
}
@@ -14564,6 +14773,9 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
}
bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_complex:
Result.makeComplexFloat();
@@ -14574,10 +14786,8 @@ bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {
return true;
default:
- break;
+ return false;
}
-
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
//===----------------------------------------------------------------------===//
@@ -14653,6 +14863,9 @@ public:
}
bool VisitCallExpr(const CallExpr *E) {
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
switch (E->getBuiltinCallee()) {
case Builtin::BI__assume:
case Builtin::BI__builtin_assume:
@@ -14663,10 +14876,8 @@ public:
return HandleOperatorDeleteCall(Info, E);
default:
- break;
+ return false;
}
-
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
@@ -14703,7 +14914,7 @@ bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
return true;
}
- Optional<DynAlloc *> Alloc = CheckDeleteKind(
+ std::optional<DynAlloc *> Alloc = CheckDeleteKind(
Info, E, Pointer, E->isArrayForm() ? DynAlloc::ArrayNew : DynAlloc::New);
if (!Alloc)
return false;
@@ -14871,25 +15082,27 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
/// lvalue-to-rvalue cast if it is an lvalue.
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
assert(!E->isValueDependent());
+
+ if (E->getType().isNull())
+ return false;
+
+ if (!CheckLiteralType(Info, E))
+ return false;
+
if (Info.EnableNewConstInterp) {
if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
return false;
} else {
- if (E->getType().isNull())
- return false;
-
- if (!CheckLiteralType(Info, E))
- return false;
-
if (!::Evaluate(Result, Info, E))
return false;
+ }
- if (E->isGLValue()) {
- LValue LV;
- LV.setFrom(Info.Ctx, Result);
- if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
- return false;
- }
+ // Implicit lvalue-to-rvalue cast.
+ if (E->isGLValue()) {
+ LValue LV;
+ LV.setFrom(Info.Ctx, Result);
+ if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+ return false;
}
// Check this core constant expression is a constant expression.
@@ -14909,6 +15122,12 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
return true;
}
+ if (const auto *L = dyn_cast<CXXBoolLiteralExpr>(Exp)) {
+ Result.Val = APValue(APSInt(APInt(1, L->getValue())));
+ IsConst = true;
+ return true;
+ }
+
// This case should be rare, but we need to check it before we check on
// the type below.
if (Exp->getType().isNull()) {
@@ -14986,6 +15205,7 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsRValue");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsRValue(this, Result, Ctx, Info);
@@ -14995,6 +15215,7 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsBooleanCondition");
EvalResult Scratch;
return EvaluateAsRValue(Scratch, Ctx, InConstantContext) &&
HandleConversionToBool(Scratch.Val, Result);
@@ -15005,6 +15226,7 @@ bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsInt");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info);
@@ -15015,6 +15237,7 @@ bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsFixedPoint");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info);
@@ -15029,6 +15252,7 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
if (!getType()->isRealFloatingType())
return false;
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsFloat");
EvalResult ExprResult;
if (!EvaluateAsRValue(ExprResult, Ctx, InConstantContext) ||
!ExprResult.Val.isFloat() ||
@@ -15044,6 +15268,7 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsLValue");
EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
Info.InConstantContext = InConstantContext;
LValue LV;
@@ -15087,7 +15312,11 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
ConstantExprKind Kind) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ bool IsConst;
+ if (FastEvaluateAsRValue(this, Result, Ctx, IsConst) && Result.Val.hasValue())
+ return true;
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsConstantExpr");
EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
EvalInfo Info(Ctx, Result, EM);
Info.InConstantContext = true;
@@ -15140,6 +15369,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ llvm::TimeTraceScope TimeScope("EvaluateAsInitializer", [&] {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ VD->printQualifiedName(OS);
+ return Name;
+ });
+
// FIXME: Evaluating initializers for large array and record types can cause
// performance problems. Only do so in C++11 for now.
if (isPRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
@@ -15228,6 +15464,7 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateKnownConstInt");
EvalResult EVResult;
EVResult.Diag = Diag;
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
@@ -15246,6 +15483,7 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow(
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateKnownConstIntCheckOverflow");
EvalResult EVResult;
EVResult.Diag = Diag;
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
@@ -15264,6 +15502,7 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateForOverflow");
bool IsConst;
EvalResult EVResult;
if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
@@ -15425,6 +15664,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::DependentCoawaitExprClass:
case Expr::CoyieldExprClass:
case Expr::SYCLUniqueStableNameExprClass:
+ case Expr::CXXParenListInitExprClass:
return ICEDiag(IK_NotICE, E->getBeginLoc());
case Expr::InitListExprClass: {
@@ -15755,6 +15995,8 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "isIntegerConstantExpr");
+
if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc);
@@ -15766,12 +16008,12 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
return true;
}
-Optional<llvm::APSInt> Expr::getIntegerConstantExpr(const ASTContext &Ctx,
- SourceLocation *Loc,
- bool isEvaluated) const {
+std::optional<llvm::APSInt>
+Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc,
+ bool isEvaluated) const {
if (isValueDependent()) {
// Expression evaluator can't succeed on a dependent expression.
- return None;
+ return std::nullopt;
}
APSInt Value;
@@ -15779,11 +16021,11 @@ Optional<llvm::APSInt> Expr::getIntegerConstantExpr(const ASTContext &Ctx,
if (Ctx.getLangOpts().CPlusPlus11) {
if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc))
return Value;
- return None;
+ return std::nullopt;
}
if (!isIntegerConstantExpr(Ctx, Loc))
- return None;
+ return std::nullopt;
// The only possible side-effects here are due to UB discovered in the
// evaluation (for instance, INT_MAX + 1). In such a case, we are still
@@ -15847,6 +16089,14 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ llvm::TimeTraceScope TimeScope("EvaluateWithSubstitution", [&] {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ Callee->getNameForDiagnostic(OS, Ctx.getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated);
Info.InConstantContext = true;
@@ -15911,6 +16161,14 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
if (FD->isDependentContext())
return true;
+ llvm::TimeTraceScope TimeScope("isPotentialConstantExpr", [&] {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
Expr::EvalStatus Status;
Status.Diag = &Diags;
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 257833182621..090ef02aa422 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -20,9 +20,9 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/None.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdint>
+#include <optional>
using namespace clang;
@@ -30,9 +30,9 @@ char ExternalASTSource::ID;
ExternalASTSource::~ExternalASTSource() = default;
-llvm::Optional<ASTSourceDescriptor>
+std::optional<ASTSourceDescriptor>
ExternalASTSource::getSourceDescriptor(unsigned ID) {
- return None;
+ return std::nullopt;
}
ExternalASTSource::ExtKind
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index c0879704de4d..c7dee2d421bb 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ConvertUTF.h"
+#include <optional>
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -348,7 +349,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
return Match;
case AnyCharTy: {
- if (const EnumType *ETy = argTy->getAs<EnumType>()) {
+ if (const auto *ETy = argTy->getAs<EnumType>()) {
// If the enum is incomplete we know nothing about the underlying type.
// Assume that it's 'int'.
if (!ETy->getDecl()->isComplete())
@@ -356,17 +357,34 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
argTy = ETy->getDecl()->getIntegerType();
}
- if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+ if (const auto *BT = argTy->getAs<BuiltinType>()) {
+ // The types are perfectly matched?
switch (BT->getKind()) {
+ default:
+ break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_U:
+ case BuiltinType::Bool:
+ return Match;
+ }
+ // "Partially matched" because of promotions?
+ if (!Ptr) {
+ switch (BT->getKind()) {
default:
break;
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Char_U:
- case BuiltinType::Bool:
- return Match;
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return MatchPromotion;
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ return NoMatchPromotionTypeConfusion;
+ }
}
+ }
return NoMatch;
}
@@ -383,8 +401,9 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
if (T == argTy)
return Match;
- // Check for "compatible types".
- if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+ if (const auto *BT = argTy->getAs<BuiltinType>()) {
+ // Check if the only difference between them is signed vs unsigned
+ // if true, we consider they are compatible.
switch (BT->getKind()) {
default:
break;
@@ -395,25 +414,66 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
case BuiltinType::Bool:
if (T == C.UnsignedShortTy || T == C.ShortTy)
return NoMatchTypeConfusion;
- return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
- : NoMatch;
+ if (T == C.UnsignedCharTy || T == C.SignedCharTy)
+ return Match;
+ break;
case BuiltinType::Short:
- return T == C.UnsignedShortTy ? Match : NoMatch;
+ if (T == C.UnsignedShortTy)
+ return Match;
+ break;
case BuiltinType::UShort:
- return T == C.ShortTy ? Match : NoMatch;
+ if (T == C.ShortTy)
+ return Match;
+ break;
case BuiltinType::Int:
- return T == C.UnsignedIntTy ? Match : NoMatch;
+ if (T == C.UnsignedIntTy)
+ return Match;
+ break;
case BuiltinType::UInt:
- return T == C.IntTy ? Match : NoMatch;
+ if (T == C.IntTy)
+ return Match;
+ break;
case BuiltinType::Long:
- return T == C.UnsignedLongTy ? Match : NoMatch;
+ if (T == C.UnsignedLongTy)
+ return Match;
+ break;
case BuiltinType::ULong:
- return T == C.LongTy ? Match : NoMatch;
+ if (T == C.LongTy)
+ return Match;
+ break;
case BuiltinType::LongLong:
- return T == C.UnsignedLongLongTy ? Match : NoMatch;
+ if (T == C.UnsignedLongLongTy)
+ return Match;
+ break;
case BuiltinType::ULongLong:
- return T == C.LongLongTy ? Match : NoMatch;
- }
+ if (T == C.LongLongTy)
+ return Match;
+ break;
+ }
+ // "Partially matched" because of promotions?
+ if (!Ptr) {
+ switch (BT->getKind()) {
+ default:
+ break;
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ if (T == C.SignedCharTy || T == C.UnsignedCharTy ||
+ T == C.ShortTy || T == C.UnsignedShortTy || T == C.WCharTy ||
+ T == C.WideCharTy)
+ return MatchPromotion;
+ break;
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ if (T == C.SignedCharTy || T == C.UnsignedCharTy)
+ return NoMatchPromotionTypeConfusion;
+ break;
+ case BuiltinType::WChar_U:
+ case BuiltinType::WChar_S:
+ if (T != C.WCharTy && T != C.WideCharTy)
+ return NoMatchPromotionTypeConfusion;
+ }
+ }
+ }
return NoMatch;
}
@@ -451,7 +511,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
return Match;
- QualType PromoArg = argTy->isPromotableIntegerType()
+ QualType PromoArg = C.isPromotableIntegerType(argTy)
? C.getPromotedIntegerType(argTy)
: argTy;
PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
@@ -624,6 +684,8 @@ analyze_format_string::LengthModifier::toString() const {
const char *ConversionSpecifier::toString() const {
switch (kind) {
+ case bArg: return "b";
+ case BArg: return "B";
case dArg: return "d";
case DArg: return "D";
case iArg: return "i";
@@ -673,13 +735,13 @@ const char *ConversionSpecifier::toString() const {
return nullptr;
}
-Optional<ConversionSpecifier>
+std::optional<ConversionSpecifier>
ConversionSpecifier::getStandardSpecifier() const {
ConversionSpecifier::Kind NewKind;
switch (getKind()) {
default:
- return None;
+ return std::nullopt;
case DArg:
NewKind = dArg;
break;
@@ -745,7 +807,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
break;
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LengthModifier::AsChar:
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
@@ -753,6 +815,8 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
case LengthModifier::AsSizeT:
case LengthModifier::AsPtrDiff:
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
@@ -908,6 +972,8 @@ bool FormatSpecifier::hasStandardLengthModifier() const {
bool FormatSpecifier::hasStandardConversionSpecifier(
const LangOptions &LangOpt) const {
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::cArg:
case ConversionSpecifier::dArg:
case ConversionSpecifier::iArg:
@@ -966,7 +1032,8 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
return true;
}
-Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
+std::optional<LengthModifier>
+FormatSpecifier::getCorrectedLengthModifier() const {
if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
if (LM.getKind() == LengthModifier::AsLongDouble ||
LM.getKind() == LengthModifier::AsQuad) {
@@ -976,15 +1043,14 @@ Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
}
}
- return None;
+ return std::nullopt;
}
bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
LengthModifier &LM) {
- assert(isa<TypedefType>(QT) && "Expected a TypedefType");
- const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
-
- for (;;) {
+ for (/**/; const auto *TT = QT->getAs<TypedefType>();
+ QT = TT->getDecl()->getUnderlyingType()) {
+ const TypedefNameDecl *Typedef = TT->getDecl();
const IdentifierInfo *Identifier = Typedef->getIdentifier();
if (Identifier->getName() == "size_t") {
LM.setKind(LengthModifier::AsSizeT);
@@ -1003,12 +1069,6 @@ bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
LM.setKind(LengthModifier::AsPtrDiff);
return true;
}
-
- QualType T = Typedef->getUnderlyingType();
- if (!isa<TypedefType>(T))
- break;
-
- Typedef = cast<TypedefType>(T)->getDecl();
}
return false;
}
diff --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h
index 2baa717311bc..3122388a49a5 100644
--- a/clang/lib/AST/Interp/Boolean.h
+++ b/clang/lib/AST/Interp/Boolean.h
@@ -22,7 +22,7 @@ namespace clang {
namespace interp {
/// Wrapper around boolean types.
-class Boolean {
+class Boolean final {
private:
/// Underlying boolean.
bool V;
@@ -46,9 +46,15 @@ class Boolean {
Boolean operator-() const { return Boolean(V); }
Boolean operator~() const { return Boolean(true); }
- explicit operator unsigned() const { return V; }
+ explicit operator int8_t() const { return V; }
+ explicit operator uint8_t() const { return V; }
+ explicit operator int16_t() const { return V; }
+ explicit operator uint16_t() const { return V; }
+ explicit operator int32_t() const { return V; }
+ explicit operator uint32_t() const { return V; }
explicit operator int64_t() const { return V; }
explicit operator uint64_t() const { return V; }
+ explicit operator bool() const { return V; }
APSInt toAPSInt() const {
return APSInt(APInt(1, static_cast<uint64_t>(V), false), true);
@@ -84,9 +90,10 @@ class Boolean {
static Boolean min(unsigned NumBits) { return Boolean(false); }
static Boolean max(unsigned NumBits) { return Boolean(true); }
- template <typename T>
- static std::enable_if_t<std::is_integral<T>::value, Boolean> from(T Value) {
- return Boolean(Value != 0);
+ template <typename T> static Boolean from(T Value) {
+ if constexpr (std::is_integral<T>::value)
+ return Boolean(Value != 0);
+ return Boolean(static_cast<decltype(Boolean::V)>(Value) != 0);
}
template <unsigned SrcBits, bool SrcSign>
@@ -134,6 +141,16 @@ class Boolean {
*R = Boolean(A.V && B.V);
return false;
}
+
+ static bool inv(Boolean A, Boolean *R) {
+ *R = Boolean(!A.V);
+ return false;
+ }
+
+ static bool neg(Boolean A, Boolean *R) {
+ *R = Boolean(A.V);
+ return false;
+ }
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Boolean &B) {
diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index a69b23fd613c..4633d1e0823b 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -19,51 +19,72 @@ 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));
- }
+Expected<Function *>
+ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
+ // Function is not defined at all or not yet. We will
+ // create a Function instance but not compile the body. That
+ // will (maybe) happen later.
+ bool HasBody = FuncDecl->hasBody(FuncDecl);
+
+ // Create a handle over the emitted code.
+ Function *Func = P.getFunction(FuncDecl);
+ if (!Func) {
+ // 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. See 'RVO'
+ // elsewhere in the code.
+ QualType Ty = FuncDecl->getReturnType();
+ bool HasRVO = false;
+ if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
+ HasRVO = true;
+ ParamTypes.push_back(PT_Ptr);
+ ParamOffset += align(primSize(PT_Ptr));
+ }
+
+ // If the function decl is a member decl, the next parameter is
+ // the 'this' pointer. This parameter is pop()ed from the
+ // InterpStack when calling the function.
+ bool HasThisPointer = false;
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);
+ MD && MD->isInstance()) {
+ HasThisPointer = true;
+ 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;
+ // Assign descriptors to all parameters.
+ // Composite objects are lowered to pointers.
+ for (const ParmVarDecl *PD : FuncDecl->parameters()) {
+ PrimType Ty = Ctx.classify(PD->getType()).value_or(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);
}
- Descriptor *Desc = P.createDescriptor(PD, Ty);
- ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
- Params.insert({PD, ParamOffset});
- ParamOffset += align(primSize(Ty));
- ParamTypes.push_back(Ty);
+ Func =
+ P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes),
+ std::move(ParamDescriptors), HasThisPointer, HasRVO);
}
- // Create a handle over the emitted code.
- Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes),
- std::move(ParamDescriptors));
+ assert(Func);
+ if (!HasBody)
+ return Func;
+
// Compile the function body.
- if (!F->isConstexpr() || !visitFunc(F)) {
+ if (!FuncDecl->isConstexpr() || !visitFunc(FuncDecl)) {
// Return a dummy function if compilation failed.
if (BailLocation)
return llvm::make_error<ByteCodeGenError>(*BailLocation);
- else
+ else {
+ Func->setIsFullyCompiled(true);
return Func;
+ }
} else {
// Create scopes from descriptors.
llvm::SmallVector<Scope, 2> Scopes;
@@ -74,6 +95,7 @@ Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
// Set the function's code.
Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
std::move(Scopes));
+ Func->setIsFullyCompiled(true);
return Func;
}
}
@@ -94,7 +116,8 @@ void ByteCodeEmitter::emitLabel(LabelTy Label) {
using namespace llvm::support;
/// Rewrite the operand of all jumps to this label.
- void *Location = Code.data() + Reloc - sizeof(int32_t);
+ void *Location = Code.data() + Reloc - align(sizeof(int32_t));
+ assert(aligned(Location));
const int32_t Offset = Target - static_cast<int64_t>(Reloc);
endian::write<int32_t, endianness::native, 1>(Location, Offset);
}
@@ -104,7 +127,9 @@ void ByteCodeEmitter::emitLabel(LabelTy Label) {
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);
+ const int64_t Position =
+ Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t));
+ assert(aligned(Position));
// If target is known, compute jump offset.
auto It = LabelOffsets.find(Label);
@@ -126,30 +151,32 @@ bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
/// Helper to write bytecode and bail out if 32-bit offsets become invalid.
/// Pointers will be automatically marshalled as 32-bit IDs.
template <typename T>
-static std::enable_if_t<!std::is_pointer<T>::value, void>
-emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) {
- size_t Size = sizeof(Val);
- if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
- Success = false;
- return;
- }
+static void emit(Program &P, std::vector<char> &Code, const T &Val,
+ bool &Success) {
+ size_t Size;
- const char *Data = reinterpret_cast<const char *>(&Val);
- Code.insert(Code.end(), Data, Data + Size);
-}
+ if constexpr (std::is_pointer_v<T>)
+ Size = sizeof(uint32_t);
+ else
+ Size = sizeof(T);
-template <typename T>
-static std::enable_if_t<std::is_pointer<T>::value, void>
-emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) {
- size_t Size = sizeof(uint32_t);
if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
Success = false;
return;
}
- uint32_t ID = P.getOrCreateNativePointer(Val);
- const char *Data = reinterpret_cast<const char *>(&ID);
- Code.insert(Code.end(), Data, Data + Size);
+ // Access must be aligned!
+ size_t ValPos = align(Code.size());
+ Size = align(Size);
+ assert(aligned(ValPos + Size));
+ Code.resize(ValPos + Size);
+
+ if constexpr (!std::is_pointer_v<T>) {
+ new (Code.data() + ValPos) T(Val);
+ } else {
+ uint32_t ID = P.getOrCreateNativePointer(Val);
+ new (Code.data() + ValPos) uint32_t(ID);
+ }
}
template <typename... Tys>
diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.h b/clang/lib/AST/Interp/ByteCodeEmitter.h
index 03452a350c96..30da06b20250 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.h
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.h
@@ -37,7 +37,7 @@ protected:
public:
/// Compiles the function into the module.
- llvm::Expected<Function *> compileFunc(const FunctionDecl *F);
+ llvm::Expected<Function *> compileFunc(const FunctionDecl *FuncDecl);
protected:
ByteCodeEmitter(Context &Ctx, Program &P) : Ctx(Ctx), P(P) {}
@@ -83,7 +83,7 @@ private:
/// Offset of the next local variable.
unsigned NextLocalOffset = 0;
/// Location of a failure.
- llvm::Optional<SourceLocation> BailLocation;
+ std::optional<SourceLocation> BailLocation;
/// Label information for linker.
llvm::DenseMap<LabelTy, unsigned> LabelOffsets;
/// Location of label relocations.
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 9b729e347a24..615dbdefefbe 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -9,6 +9,7 @@
#include "ByteCodeExprGen.h"
#include "ByteCodeEmitter.h"
#include "ByteCodeGenError.h"
+#include "ByteCodeStmtGen.h"
#include "Context.h"
#include "Function.h"
#include "PrimType.h"
@@ -19,8 +20,6 @@ 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 {
@@ -42,45 +41,19 @@ private:
/// 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(Ctx), OldDiscardResult(Ctx->DiscardResult) {
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);
- }
+ ~OptionScope() { Ctx->DiscardResult = OldDiscardResult; }
private:
/// Parent context.
ByteCodeExprGen<Emitter> *Ctx;
/// Old discard flag to restore.
bool OldDiscardResult;
- /// Old pointer emitter to restore.
- llvm::Optional<InitFnRef> OldInitFn;
};
} // namespace interp
@@ -106,6 +79,22 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
});
}
+ case CK_UncheckedDerivedToBase:
+ case CK_DerivedToBase: {
+ if (!this->visit(SubExpr))
+ return false;
+
+ const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr);
+ assert(FromDecl);
+ const CXXRecordDecl *ToDecl = getRecordDecl(CE);
+ assert(ToDecl);
+ const Record *R = getRecord(FromDecl);
+ const Record::Base *ToBase = R->getBase(ToDecl);
+ assert(ToBase);
+
+ return this->emitGetPtrBase(ToBase->Offset, CE);
+ }
+
case CK_ArrayToPointerDecay:
case CK_AtomicToNonAtomic:
case CK_ConstructorConversion:
@@ -113,16 +102,30 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_UserDefinedConversion:
- return this->Visit(SubExpr);
+ case CK_NullToPointer:
+ return this->visit(SubExpr);
+
+ case CK_IntegralToBoolean:
+ case CK_IntegralCast: {
+ std::optional<PrimType> FromT = classify(SubExpr->getType());
+ std::optional<PrimType> ToT = classify(CE->getType());
+ if (!FromT || !ToT)
+ return false;
+
+ if (!this->visit(SubExpr))
+ return false;
+
+ // TODO: Emit this only if FromT != ToT.
+ return this->emitCast(*FromT, *ToT, CE);
+ }
case CK_ToVoid:
return discard(SubExpr);
- default: {
- // TODO: implement other casts.
- return this->bail(CE);
- }
+ default:
+ assert(false && "Cast not implemented");
}
+ llvm_unreachable("Unhandled clang::CastKind enum");
}
template <class Emitter>
@@ -130,16 +133,12 @@ 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);
+ return this->emitConst(LE->getValue(), LE);
}
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *PE) {
- return this->Visit(PE->getSubExpr());
+ return this->visit(PE->getSubExpr());
}
template <class Emitter>
@@ -152,7 +151,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
case BO_Comma:
if (!discard(LHS))
return false;
- if (!this->Visit(RHS))
+ if (!this->visit(RHS))
return false;
return true;
default:
@@ -160,53 +159,398 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
}
// Typecheck the args.
- Optional<PrimType> LT = classify(LHS->getType());
- Optional<PrimType> RT = classify(RHS->getType());
- if (!LT || !RT) {
+ std::optional<PrimType> LT = classify(LHS->getType());
+ std::optional<PrimType> RT = classify(RHS->getType());
+ std::optional<PrimType> T = classify(BO->getType());
+ if (!LT || !RT || !T) {
return this->bail(BO);
}
- if (Optional<PrimType> T = classify(BO->getType())) {
- if (!visit(LHS))
+ auto Discard = [this, T, BO](bool Result) {
+ if (!Result)
return false;
- if (!visit(RHS))
+ return DiscardResult ? this->emitPop(*T, BO) : true;
+ };
+
+ // Pointer arithmetic special case.
+ if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
+ if (*T == PT_Ptr || (*LT == PT_Ptr && *RT == PT_Ptr))
+ return this->VisitPointerArithBinOp(BO);
+ }
+
+ if (!visit(LHS) || !visit(RHS))
+ return false;
+
+ 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));
+ case BO_Rem:
+ return Discard(this->emitRem(*T, BO));
+ case BO_Div:
+ return Discard(this->emitDiv(*T, BO));
+ case BO_Assign:
+ if (DiscardResult)
+ return this->emitStorePop(*T, BO);
+ return this->emitStore(*T, BO);
+ case BO_And:
+ return Discard(this->emitBitAnd(*T, BO));
+ case BO_Or:
+ return Discard(this->emitBitOr(*T, BO));
+ case BO_Shl:
+ return Discard(this->emitShl(*LT, *RT, BO));
+ case BO_Shr:
+ return Discard(this->emitShr(*LT, *RT, BO));
+ case BO_Xor:
+ return Discard(this->emitBitXor(*T, BO));
+ case BO_LAnd:
+ case BO_LOr:
+ default:
+ return this->bail(BO);
+ }
+
+ llvm_unreachable("Unhandled binary op");
+}
+
+/// Perform addition/subtraction of a pointer and an integer or
+/// subtraction of two pointers.
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
+ BinaryOperatorKind Op = E->getOpcode();
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
+
+ if ((Op != BO_Add && Op != BO_Sub) ||
+ (!LHS->getType()->isPointerType() && !RHS->getType()->isPointerType()))
+ return false;
+
+ std::optional<PrimType> LT = classify(LHS);
+ std::optional<PrimType> RT = classify(RHS);
+
+ if (!LT || !RT)
+ return false;
+
+ if (LHS->getType()->isPointerType() && RHS->getType()->isPointerType()) {
+ if (Op != BO_Sub)
+ return false;
+
+ assert(E->getType()->isIntegerType());
+ if (!visit(RHS) || !visit(LHS))
+ return false;
+
+ return this->emitSubPtr(classifyPrim(E->getType()), E);
+ }
+
+ PrimType OffsetType;
+ if (LHS->getType()->isIntegerType()) {
+ if (!visit(RHS) || !visit(LHS))
+ return false;
+ OffsetType = *LT;
+ } else if (RHS->getType()->isIntegerType()) {
+ if (!visit(LHS) || !visit(RHS))
+ return false;
+ OffsetType = *RT;
+ } else {
+ return false;
+ }
+
+ if (Op == BO_Add)
+ return this->emitAddOffset(OffsetType, E);
+ else if (Op == BO_Sub)
+ return this->emitSubOffset(OffsetType, E);
+
+ return this->bail(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+ if (std::optional<PrimType> T = classify(E))
+ return this->emitZero(*T, E);
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitArraySubscriptExpr(
+ const ArraySubscriptExpr *E) {
+ const Expr *Base = E->getBase();
+ const Expr *Index = E->getIdx();
+ PrimType IndexT = classifyPrim(Index->getType());
+
+ // Take pointer of LHS, add offset from RHS, narrow result.
+ // What's left on the stack after this is a pointer.
+ if (!this->visit(Base))
+ return false;
+
+ if (!this->visit(Index))
+ return false;
+
+ if (!this->emitAddOffset(IndexT, E))
+ return false;
+
+ if (!this->emitNarrowPtr(E))
+ return false;
+
+ if (DiscardResult)
+ return this->emitPopPtr(E);
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
+ for (const Expr *Init : E->inits()) {
+ if (!this->visit(Init))
return false;
+ }
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitSubstNonTypeTemplateParmExpr(
+ const SubstNonTypeTemplateParmExpr *E) {
+ return this->visit(E->getReplacement());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) {
+ // TODO: Check if the ConstantExpr already has a value set and if so,
+ // use that instead of evaluating it again.
+ return this->visit(E->getSubExpr());
+}
+
+static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx,
+ UnaryExprOrTypeTrait Kind) {
+ bool AlignOfReturnsPreferred =
+ ASTCtx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
- auto Discard = [this, T, BO](bool Result) {
- if (!Result)
+ // C++ [expr.alignof]p3:
+ // When alignof is applied to a reference type, the result is the
+ // alignment of the referenced type.
+ if (const auto *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
+ // __alignof is defined to return the preferred alignment.
+ // Before 8, clang returned the preferred alignment for alignof and
+ // _Alignof as well.
+ if (Kind == UETT_PreferredAlignOf || AlignOfReturnsPreferred)
+ return ASTCtx.toCharUnitsFromBits(ASTCtx.getPreferredTypeAlign(T));
+
+ return ASTCtx.getTypeAlignInChars(T);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *E) {
+ UnaryExprOrTypeTrait Kind = E->getKind();
+ ASTContext &ASTCtx = Ctx.getASTContext();
+
+ if (Kind == UETT_SizeOf) {
+ QualType ArgType = E->getTypeOfArgument();
+ CharUnits Size;
+ if (ArgType->isVoidType() || ArgType->isFunctionType())
+ Size = CharUnits::One();
+ else {
+ if (ArgType->isDependentType() || !ArgType->isConstantSizeType())
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);
+
+ Size = ASTCtx.getTypeSizeInChars(ArgType);
}
+
+ return this->emitConst(Size.getQuantity(), E);
+ }
+
+ if (Kind == UETT_AlignOf || Kind == UETT_PreferredAlignOf) {
+ CharUnits Size;
+
+ if (E->isArgumentType()) {
+ QualType ArgType = E->getTypeOfArgument();
+
+ Size = AlignOfType(ArgType, ASTCtx, Kind);
+ } else {
+ // Argument is an expression, not a type.
+ const Expr *Arg = E->getArgumentExpr()->IgnoreParens();
+
+ // The kinds of expressions that we have special-case logic here for
+ // should be kept up to date with the special checks for those
+ // expressions in Sema.
+
+ // alignof decl is always accepted, even if it doesn't make sense: we
+ // default to 1 in those cases.
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(Arg))
+ Size = ASTCtx.getDeclAlign(DRE->getDecl(),
+ /*RefAsPointee*/ true);
+ else if (const auto *ME = dyn_cast<MemberExpr>(Arg))
+ Size = ASTCtx.getDeclAlign(ME->getMemberDecl(),
+ /*RefAsPointee*/ true);
+ else
+ Size = AlignOfType(Arg->getType(), ASTCtx, Kind);
+ }
+
+ return this->emitConst(Size.getQuantity(), E);
}
- return this->bail(BO);
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
+ if (DiscardResult)
+ return true;
+
+ // 'Base.Member'
+ const Expr *Base = E->getBase();
+ const ValueDecl *Member = E->getMemberDecl();
+
+ if (!this->visit(Base))
+ return false;
+
+ // Base above gives us a pointer on the stack.
+ // TODO: Implement non-FieldDecl members.
+ if (const auto *FD = dyn_cast<FieldDecl>(Member)) {
+ const RecordDecl *RD = FD->getParent();
+ const Record *R = getRecord(RD);
+ const Record::Field *F = R->getField(FD);
+ // Leave a pointer to the field on the stack.
+ if (F->Decl->getType()->isReferenceType())
+ return this->emitGetFieldPop(PT_Ptr, F->Offset, E);
+ return this->emitGetPtrField(F->Offset, E);
+ }
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
+ const ArrayInitIndexExpr *E) {
+ // ArrayIndex might not be set if a ArrayInitIndexExpr is being evaluated
+ // stand-alone, e.g. via EvaluateAsInt().
+ if (!ArrayIndex)
+ return false;
+ return this->emitConst(*ArrayIndex, E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+ return this->visit(E->getSourceExpr());
}
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
+bool ByteCodeExprGen<Emitter>::VisitAbstractConditionalOperator(
+ const AbstractConditionalOperator *E) {
+ const Expr *Condition = E->getCond();
+ const Expr *TrueExpr = E->getTrueExpr();
+ const Expr *FalseExpr = E->getFalseExpr();
+
+ LabelTy LabelEnd = this->getLabel(); // Label after the operator.
+ LabelTy LabelFalse = this->getLabel(); // Label for the false expr.
+
+ if (!this->visit(Condition))
+ return false;
+ if (!this->jumpFalse(LabelFalse))
+ return false;
+
+ if (!this->visit(TrueExpr))
+ return false;
+ if (!this->jump(LabelEnd))
+ return false;
+
+ this->emitLabel(LabelFalse);
+
+ if (!this->visit(FalseExpr))
+ return false;
+
+ this->fallthrough(LabelEnd);
+ this->emitLabel(LabelEnd);
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitStringLiteral(const StringLiteral *E) {
+ unsigned StringIndex = P.createGlobalString(E);
+ return this->emitGetPtrGlobal(StringIndex, E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCharacterLiteral(
+ const CharacterLiteral *E) {
+ return this->emitConst(E->getValue(), E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
+ const CompoundAssignOperator *E) {
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
+ std::optional<PrimType> LT = classify(E->getLHS()->getType());
+ std::optional<PrimType> RT = classify(E->getRHS()->getType());
+
+ if (!LT || !RT)
+ return false;
+
+ assert(!E->getType()->isPointerType() &&
+ "Support pointer arithmethic in compound assignment operators");
+
+ // Get LHS pointer, load its value and get RHS value.
+ if (!visit(LHS))
+ return false;
+ if (!this->emitLoad(*LT, E))
+ return false;
+ if (!visit(RHS))
+ return false;
+
+ // Perform operation.
+ switch (E->getOpcode()) {
+ case BO_AddAssign:
+ if (!this->emitAdd(*LT, E))
+ return false;
+ break;
+ case BO_SubAssign:
+ if (!this->emitSub(*LT, E))
+ return false;
+ break;
+
+ case BO_MulAssign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ if (!this->emitShl(*LT, *RT, E))
+ return false;
+ break;
+ case BO_ShrAssign:
+ if (!this->emitShr(*LT, *RT, E))
+ return false;
+ break;
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ default:
+ llvm_unreachable("Unimplemented compound assign operator");
+ }
+
+ // And store the result in LHS.
+ if (DiscardResult)
+ return this->emitStorePop(*LT, E);
+ return this->emitStore(*LT, E);
+}
+
+template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
return this->Visit(E);
}
@@ -219,7 +563,7 @@ bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
- if (Optional<PrimType> T = classify(E->getType())) {
+ if (std::optional<PrimType> T = classify(E->getType())) {
return visit(E);
} else {
return this->bail(E);
@@ -257,7 +601,7 @@ 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 (std::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)) {
@@ -350,7 +694,7 @@ bool ByteCodeExprGen<Emitter>::dereferenceVar(
return false;
return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
}
- } else if (auto Idx = getGlobalIdx(VD)) {
+ } else if (auto Idx = P.getGlobal(VD)) {
switch (AK) {
case DerefKind::Read:
if (!this->emitGetGlobal(T, *Idx, LV))
@@ -382,7 +726,7 @@ bool ByteCodeExprGen<Emitter>::dereferenceVar(
if (VD->hasLocalStorage() && VD->hasInit() && !VD->isConstexpr()) {
QualType VT = VD->getType();
if (VT.isConstQualified() && VT->isFundamentalType())
- return this->Visit(VD->getInit());
+ return this->visit(VD->getInit());
}
}
@@ -391,27 +735,27 @@ bool ByteCodeExprGen<Emitter>::dereferenceVar(
}
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitConst(PrimType T, unsigned NumBits,
- const APInt &Value, const Expr *E) {
- switch (T) {
+template <typename T>
+bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
+ switch (classifyPrim(E->getType())) {
case PT_Sint8:
- return this->emitConstSint8(Value.getSExtValue(), E);
+ return this->emitConstSint8(Value, E);
case PT_Uint8:
- return this->emitConstUint8(Value.getZExtValue(), E);
+ return this->emitConstUint8(Value, E);
case PT_Sint16:
- return this->emitConstSint16(Value.getSExtValue(), E);
+ return this->emitConstSint16(Value, E);
case PT_Uint16:
- return this->emitConstUint16(Value.getZExtValue(), E);
+ return this->emitConstUint16(Value, E);
case PT_Sint32:
- return this->emitConstSint32(Value.getSExtValue(), E);
+ return this->emitConstSint32(Value, E);
case PT_Uint32:
- return this->emitConstUint32(Value.getZExtValue(), E);
+ return this->emitConstUint32(Value, E);
case PT_Sint64:
- return this->emitConstSint64(Value.getSExtValue(), E);
+ return this->emitConstSint64(Value, E);
case PT_Uint64:
- return this->emitConstUint64(Value.getZExtValue(), E);
+ return this->emitConstUint64(Value, E);
case PT_Bool:
- return this->emitConstBool(Value.getBoolValue(), E);
+ return this->emitConstBool(Value, E);
case PT_Ptr:
llvm_unreachable("Invalid integral type");
break;
@@ -420,11 +764,29 @@ bool ByteCodeExprGen<Emitter>::emitConst(PrimType T, unsigned NumBits,
}
template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
+ if (Value.isSigned())
+ return this->emitConst(Value.getSExtValue(), E);
+ return this->emitConst(Value.getZExtValue(), E);
+}
+
+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 *>());
+ // Make sure we don't accidentally register the same decl twice.
+ if (const auto *VD =
+ dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
+ assert(!P.getGlobal(VD));
+ assert(Locals.find(VD) == Locals.end());
+ }
+
+ // FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
+ // (int){12} in C. Consider using Expr::isTemporaryObject() instead
+ // or isa<MaterializeTemporaryExpr>().
+ Descriptor *D = P.createDescriptor(Src, Ty, Descriptor::InlineDescMD, 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});
@@ -433,23 +795,34 @@ unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
}
template <class Emitter>
-llvm::Optional<unsigned>
+std::optional<unsigned>
ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
- QualType Ty;
+ // Make sure we don't accidentally register the same decl twice.
+ if (const auto *VD =
+ dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
+ assert(!P.getGlobal(VD));
+ assert(Locals.find(VD) == Locals.end());
+ }
+ QualType Ty;
const ValueDecl *Key = nullptr;
+ const Expr *Init = nullptr;
bool IsTemporary = false;
- if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>())) {
+ if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
Key = VD;
Ty = VD->getType();
+
+ if (const auto *VarD = dyn_cast<VarDecl>(VD))
+ Init = VarD->getInit();
}
if (auto *E = Src.dyn_cast<const Expr *>()) {
IsTemporary = true;
Ty = E->getType();
}
- Descriptor *D = P.createDescriptor(Src, Ty.getTypePtr(),
- Ty.isConstQualified(), IsTemporary);
+ Descriptor *D = P.createDescriptor(
+ Src, Ty.getTypePtr(), Descriptor::InlineDescMD, Ty.isConstQualified(),
+ IsTemporary, /*IsMutable=*/false, Init);
if (!D)
return {};
@@ -460,38 +833,230 @@ ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
return Local.Offset;
}
+// NB: When calling this function, we have a pointer to the
+// array-to-initialize on the stack.
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitInitializer(
- const Expr *Init, InitFnRef InitFn) {
- OptionScope<Emitter> Scope(this, InitFn);
- return this->Visit(Init);
+bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
+ assert(Initializer->getType()->isArrayType());
+
+ // TODO: Fillers?
+ if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
+ unsigned ElementIndex = 0;
+ for (const Expr *Init : InitList->inits()) {
+ if (std::optional<PrimType> T = classify(Init->getType())) {
+ // Visit the primitive element like normal.
+ if (!this->emitDupPtr(Init))
+ return false;
+ if (!this->visit(Init))
+ return false;
+ if (!this->emitInitElem(*T, ElementIndex, Init))
+ return false;
+ } else {
+ // Advance the pointer currently on the stack to the given
+ // dimension and narrow().
+ if (!this->emitDupPtr(Init))
+ return false;
+ if (!this->emitConstUint32(ElementIndex, Init))
+ return false;
+ if (!this->emitAddOffsetUint32(Init))
+ return false;
+ if (!this->emitNarrowPtr(Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+ }
+ if (!this->emitPopPtr(Init))
+ return false;
+
+ ++ElementIndex;
+ }
+ return true;
+ } else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
+ return this->visitInitializer(DIE->getExpr());
+ } else if (const auto *AILE = dyn_cast<ArrayInitLoopExpr>(Initializer)) {
+ // TODO: This compiles to quite a lot of bytecode if the array is larger.
+ // Investigate compiling this to a loop, or at least try to use
+ // the AILE's Common expr.
+ const Expr *SubExpr = AILE->getSubExpr();
+ size_t Size = AILE->getArraySize().getZExtValue();
+ std::optional<PrimType> ElemT = classify(SubExpr->getType());
+
+ // So, every iteration, we execute an assignment here
+ // where the LHS is on the stack (the target array)
+ // and the RHS is our SubExpr.
+ for (size_t I = 0; I != Size; ++I) {
+ ArrayIndexScope<Emitter> IndexScope(this, I);
+
+ if (!this->emitDupPtr(SubExpr)) // LHS
+ return false;
+
+ if (ElemT) {
+ if (!this->visit(SubExpr))
+ return false;
+ if (!this->emitInitElem(*ElemT, I, Initializer))
+ return false;
+ } else {
+ // Narrow to our array element and recurse into visitInitializer()
+ if (!this->emitConstUint64(I, SubExpr))
+ return false;
+
+ if (!this->emitAddOffsetUint64(SubExpr))
+ return false;
+
+ if (!this->emitNarrowPtr(SubExpr))
+ return false;
+
+ if (!visitInitializer(SubExpr))
+ return false;
+ }
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ }
+ return true;
+ } else if (const auto *IVIE = dyn_cast<ImplicitValueInitExpr>(Initializer)) {
+ const ArrayType *AT = IVIE->getType()->getAsArrayTypeUnsafe();
+ assert(AT);
+ const auto *CAT = cast<ConstantArrayType>(AT);
+ size_t NumElems = CAT->getSize().getZExtValue();
+
+ if (std::optional<PrimType> ElemT = classify(CAT->getElementType())) {
+ // TODO(perf): For int and bool types, we can probably just skip this
+ // since we memset our Block*s to 0 and so we have the desired value
+ // without this.
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!this->emitZero(*ElemT, Initializer))
+ return false;
+ if (!this->emitInitElem(*ElemT, I, Initializer))
+ return false;
+ }
+ } else {
+ assert(false && "default initializer for non-primitive type");
+ }
+
+ return true;
+ } else if (const auto *Ctor = dyn_cast<CXXConstructExpr>(Initializer)) {
+ const ConstantArrayType *CAT =
+ Ctx.getASTContext().getAsConstantArrayType(Ctor->getType());
+ assert(CAT);
+ size_t NumElems = CAT->getSize().getZExtValue();
+ const Function *Func = getFunction(Ctor->getConstructor());
+ if (!Func || !Func->isConstexpr())
+ return false;
+
+ // FIXME(perf): We're calling the constructor once per array element here,
+ // in the old intepreter we had a special-case for trivial constructors.
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!this->emitDupPtr(Initializer))
+ return false;
+ if (!this->emitConstUint64(I, Initializer))
+ return false;
+ if (!this->emitAddOffsetUint64(Initializer))
+ return false;
+ if (!this->emitNarrowPtr(Initializer))
+ return false;
+
+ // Constructor arguments.
+ for (const auto *Arg : Ctor->arguments()) {
+ if (!this->visit(Arg))
+ return false;
+ }
+
+ if (!this->emitCall(Func, Initializer))
+ return false;
+ }
+ return true;
+ }
+
+ assert(false && "Unknown expression for array initialization");
+ return false;
}
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);
+bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
+ Initializer = Initializer->IgnoreParenImpCasts();
+ assert(Initializer->getType()->isRecordType());
+
+ if (const auto CtorExpr = dyn_cast<CXXConstructExpr>(Initializer)) {
+ const Function *Func = getFunction(CtorExpr->getConstructor());
+
+ if (!Func || !Func->isConstexpr())
+ return false;
+
+ // The This pointer is already on the stack because this is an initializer,
+ // but we need to dup() so the call() below has its own copy.
+ if (!this->emitDupPtr(Initializer))
+ return false;
+
+ // Constructor arguments.
+ for (const auto *Arg : CtorExpr->arguments()) {
+ if (!this->visit(Arg))
+ return false;
+ }
+
+ return this->emitCall(Func, Initializer);
+ } else if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
+ const Record *R = getRecord(InitList->getType());
+
+ unsigned InitIndex = 0;
+ for (const Expr *Init : InitList->inits()) {
+ const Record::Field *FieldToInit = R->getField(InitIndex);
+
+ if (!this->emitDupPtr(Initializer))
+ return false;
+
+ if (std::optional<PrimType> T = classify(Init)) {
+ if (!this->visit(Init))
+ return false;
+
+ if (!this->emitInitField(*T, FieldToInit->Offset, Initializer))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ } else {
+ // Non-primitive case. Get a pointer to the field-to-initialize
+ // on the stack and recurse into visitInitializer().
+ if (!this->emitGetPtrField(FieldToInit->Offset, Init))
+ return false;
+
+ if (!this->visitInitializer(Init))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ }
+ ++InitIndex;
+ }
+
+ return true;
+ } else if (const CallExpr *CE = dyn_cast<CallExpr>(Initializer)) {
+ // RVO functions expect a pointer to initialize on the stack.
+ // Dup our existing pointer so it has its own copy to use.
+ if (!this->emitDupPtr(Initializer))
+ return false;
+
+ return this->VisitCallExpr(CE);
+ } else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
+ return this->visitInitializer(DIE->getExpr());
}
- return this->bail(VD);
+
+ return false;
}
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 {};
+bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *Initializer) {
+ QualType InitializerType = Initializer->getType();
+
+ if (InitializerType->isArrayType())
+ return visitArrayInitializer(Initializer);
+
+ if (InitializerType->isRecordType())
+ return visitRecordInitializer(Initializer);
+
+ // Otherwise, visit the expression like normal.
+ return this->visit(Initializer);
}
template <class Emitter>
@@ -516,52 +1081,339 @@ Record *ByteCodeExprGen<Emitter>::getRecord(const RecordDecl *RD) {
}
template <class Emitter>
+const Function *ByteCodeExprGen<Emitter>::getFunction(const FunctionDecl *FD) {
+ assert(FD);
+ const Function *Func = P.getFunction(FD);
+ bool IsBeingCompiled = Func && !Func->isFullyCompiled();
+ bool WasNotDefined = Func && !Func->hasBody();
+
+ if (IsBeingCompiled)
+ return Func;
+
+ if (!Func || WasNotDefined) {
+ if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(Ctx, P).compileFunc(FD))
+ Func = *R;
+ else {
+ llvm::consumeError(R.takeError());
+ return nullptr;
+ }
+ }
+
+ return Func;
+}
+
+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))
+ if (std::optional<PrimType> T = classify(Exp))
return this->emitRet(*T, Exp);
else
return this->emitRetValue(Exp);
}
+/// Toplevel visitDecl().
+/// We get here from evaluateAsInitializer().
+/// We need to evaluate the initializer and return its value.
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
+ std::optional<PrimType> VarT = classify(VD->getType());
+
+ // Create and initialize the variable.
+ if (!this->visitVarDecl(VD))
+ return false;
+
+ // Get a pointer to the variable
+ if (shouldBeGloballyIndexed(VD)) {
+ auto GlobalIndex = P.getGlobal(VD);
+ assert(GlobalIndex); // visitVarDecl() didn't return false.
+ if (!this->emitGetPtrGlobal(*GlobalIndex, VD))
+ return false;
+ } else {
+ auto Local = Locals.find(VD);
+ assert(Local != Locals.end()); // Same here.
+ if (!this->emitGetPtrLocal(Local->second.Offset, VD))
+ return false;
+ }
+
+ // Return the value
+ if (VarT) {
+ if (!this->emitLoadPop(*VarT, VD))
+ return false;
+
+ return this->emitRet(*VarT, VD);
+ }
+
+ return this->emitRetValue(VD);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
const Expr *Init = VD->getInit();
+ std::optional<PrimType> VarT = classify(VD->getType());
+
+ if (shouldBeGloballyIndexed(VD)) {
+ std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(VD, Init);
+
+ if (!GlobalIndex)
+ return this->bail(VD);
+
+ assert(Init);
+ {
+ DeclScope<Emitter> LocalScope(this, VD);
- 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))
+ if (VarT) {
+ if (!this->visit(Init))
return false;
+ return this->emitInitGlobal(*VarT, *GlobalIndex, VD);
}
+ return this->visitGlobalInitializer(Init, *GlobalIndex);
+ }
+ } else {
+ VariableScope<Emitter> LocalScope(this);
+ if (VarT) {
+ unsigned Offset = this->allocateLocalPrimitive(
+ VD, *VarT, VD->getType().isConstQualified());
+ if (Init) {
+ // Compile the initializer in its own scope.
+ ExprScope<Emitter> Scope(this);
+ if (!this->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);
+ return this->emitSetLocal(*VarT, Offset, VD);
+ }
} else {
- {
- // Composite declarations - allocate storage and initialize it.
- DeclScope<Emitter> LocalScope(this, VD);
- if (!visitGlobalInitializer(Init, *I))
+ if (std::optional<unsigned> Offset = this->allocateLocal(VD)) {
+ if (Init)
+ return this->visitLocalInitializer(Init, *Offset);
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
+ assert(!E->getBuiltinCallee() && "Builtin functions aren't supported yet");
+
+ const Decl *Callee = E->getCalleeDecl();
+ if (const auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(Callee)) {
+ const Function *Func = getFunction(FuncDecl);
+ if (!Func)
+ return false;
+ // If the function is being compiled right now, this is a recursive call.
+ // In that case, the function can't be valid yet, even though it will be
+ // later.
+ // If the function is already fully compiled but not constexpr, it was
+ // found to be faulty earlier on, so bail out.
+ if (Func->isFullyCompiled() && !Func->isConstexpr())
+ return false;
+
+ QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
+ std::optional<PrimType> T = classify(ReturnType);
+
+ if (Func->hasRVO() && DiscardResult) {
+ // If we need to discard the return value but the function returns its
+ // value via an RVO pointer, we need to create one such pointer just
+ // for this call.
+ if (std::optional<unsigned> LocalIndex = allocateLocal(E)) {
+ if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}
+ }
- // Return a pointer to the global.
- if (!this->emitGetPtrGlobal(*I, VD))
+ // Put arguments on the stack.
+ for (const auto *Arg : E->arguments()) {
+ if (!this->visit(Arg))
return false;
- return this->emitRetValue(VD);
}
+
+ // In any case call the function. The return value will end up on the stack and
+ // if the function has RVO, we already have the pointer on the stack to write
+ // the result into.
+ if (!this->emitCall(Func, E))
+ return false;
+
+ if (DiscardResult && !ReturnType->isVoidType() && T)
+ return this->emitPop(*T, E);
+
+ return true;
+ } else {
+ assert(false && "We don't support non-FunctionDecl callees right now.");
}
- return this->bail(VD);
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXMemberCallExpr(
+ const CXXMemberCallExpr *E) {
+ // Get a This pointer on the stack.
+ if (!this->visit(E->getImplicitObjectArgument()))
+ return false;
+
+ return VisitCallExpr(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr(
+ const CXXDefaultInitExpr *E) {
+ return this->visit(E->getExpr());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr(
+ const CXXDefaultArgExpr *E) {
+ return this->visit(E->getExpr());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXBoolLiteralExpr(
+ const CXXBoolLiteralExpr *E) {
+ if (DiscardResult)
+ return true;
+
+ return this->emitConstBool(E->getValue(), E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
+ const CXXNullPtrLiteralExpr *E) {
+ if (DiscardResult)
+ return true;
+
+ return this->emitNullPtr(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
+ if (DiscardResult)
+ return true;
+ return this->emitThis(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
+ const Expr *SubExpr = E->getSubExpr();
+ std::optional<PrimType> T = classify(SubExpr->getType());
+
+ // TODO: Support pointers for inc/dec operators.
+ switch (E->getOpcode()) {
+ case UO_PostInc: { // x++
+ if (!this->visit(SubExpr))
+ return false;
+
+ return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E);
+ }
+ case UO_PostDec: { // x--
+ if (!this->visit(SubExpr))
+ return false;
+
+ return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E);
+ }
+ case UO_PreInc: { // ++x
+ if (!this->visit(SubExpr))
+ return false;
+
+ // Post-inc and pre-inc are the same if the value is to be discarded.
+ if (DiscardResult)
+ return this->emitIncPop(*T, E);
+
+ this->emitLoad(*T, E);
+ this->emitConst(1, E);
+ this->emitAdd(*T, E);
+ return this->emitStore(*T, E);
+ }
+ case UO_PreDec: { // --x
+ if (!this->visit(SubExpr))
+ return false;
+
+ // Post-dec and pre-dec are the same if the value is to be discarded.
+ if (DiscardResult)
+ return this->emitDecPop(*T, E);
+
+ this->emitLoad(*T, E);
+ this->emitConst(1, E);
+ this->emitSub(*T, E);
+ return this->emitStore(*T, E);
+ }
+ case UO_LNot: // !x
+ if (!this->visit(SubExpr))
+ return false;
+ // The Inv doesn't change anything, so skip it if we don't need the result.
+ return DiscardResult ? this->emitPop(*T, E) : this->emitInvBool(E);
+ case UO_Minus: // -x
+ if (!this->visit(SubExpr))
+ return false;
+ return DiscardResult ? this->emitPop(*T, E) : this->emitNeg(*T, E);
+ case UO_Plus: // +x
+ if (!this->visit(SubExpr)) // noop
+ return false;
+ return DiscardResult ? this->emitPop(*T, E) : true;
+ case UO_AddrOf: // &x
+ // We should already have a pointer when we get here.
+ if (!this->visit(SubExpr))
+ return false;
+ return DiscardResult ? this->emitPop(*T, E) : true;
+ case UO_Deref: // *x
+ return dereference(
+ SubExpr, DerefKind::Read,
+ [](PrimType) {
+ llvm_unreachable("Dereferencing requires a pointer");
+ return false;
+ },
+ [this, E](PrimType T) {
+ return DiscardResult ? this->emitPop(T, E) : true;
+ });
+ case UO_Not: // ~x
+ if (!this->visit(SubExpr))
+ return false;
+ return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E);
+ case UO_Real: // __real x
+ case UO_Imag: // __imag x
+ case UO_Extension:
+ case UO_Coawait:
+ assert(false && "Unhandled opcode");
+ }
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
+ const auto *Decl = E->getDecl();
+ // References are implemented via pointers, so when we see a DeclRefExpr
+ // pointing to a reference, we need to get its value directly (i.e. the
+ // pointer to the actual value) instead of a pointer to the pointer to the
+ // value.
+ bool IsReference = Decl->getType()->isReferenceType();
+
+ if (auto It = Locals.find(Decl); It != Locals.end()) {
+ const unsigned Offset = It->second.Offset;
+
+ if (IsReference)
+ return this->emitGetLocal(PT_Ptr, Offset, E);
+ return this->emitGetPtrLocal(Offset, E);
+ } else if (auto GlobalIndex = P.getGlobal(Decl)) {
+ if (IsReference)
+ return this->emitGetGlobal(PT_Ptr, *GlobalIndex, E);
+
+ return this->emitGetPtrGlobal(*GlobalIndex, E);
+ } else if (const auto *PVD = dyn_cast<ParmVarDecl>(Decl)) {
+ if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+ if (IsReference)
+ return this->emitGetParam(PT_Ptr, It->second, E);
+ return this->emitGetPtrParam(It->second, E);
+ }
+ } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(Decl)) {
+ return this->emitConst(ECD->getInitVal(), E);
+ }
+
+ return false;
}
template <class Emitter>
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 82aa413dabbc..c7fcc59e5a60 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -22,7 +22,6 @@
#include "clang/AST/Expr.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/Optional.h"
namespace clang {
class QualType;
@@ -34,25 +33,17 @@ template <class Emitter> class RecordScope;
template <class Emitter> class VariableScope;
template <class Emitter> class DeclScope;
template <class Emitter> class OptionScope;
+template <class Emitter> class ArrayIndexScope;
/// 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.
@@ -64,11 +55,34 @@ public:
ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
: Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
- // Expression visitors - result returned on stack.
+ // Expression visitors - result returned on interp stack.
bool VisitCastExpr(const CastExpr *E);
bool VisitIntegerLiteral(const IntegerLiteral *E);
bool VisitParenExpr(const ParenExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitPointerArithBinOp(const BinaryOperator *E);
+ bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
+ bool VisitCallExpr(const CallExpr *E);
+ bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E);
+ bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
+ bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
+ bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
+ bool VisitCXXThisExpr(const CXXThisExpr *E);
+ bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitDeclRefExpr(const DeclRefExpr *E);
+ bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
+ bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
+ bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitConstantExpr(const ConstantExpr *E);
+ bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
+ bool VisitMemberExpr(const MemberExpr *E);
+ bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
+ bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
+ bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
+ bool VisitStringLiteral(const StringLiteral *E);
+ bool VisitCharacterLiteral(const CharacterLiteral *E);
+ bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
protected:
bool visitExpr(const Expr *E) override;
@@ -85,31 +99,18 @@ protected:
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();
- }
+ // Returns a function for the given FunctionDecl.
+ // If the function does not exist yet, it is compiled.
+ const Function *getFunction(const FunctionDecl *FD);
/// Classifies a type.
- llvm::Optional<PrimType> classify(const Expr *E) const {
+ std::optional<PrimType> classify(const Expr *E) const {
return E->isGLValue() ? PT_Ptr : classify(E->getType());
}
- llvm::Optional<PrimType> classify(QualType Ty) const {
+ std::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)) {
@@ -122,29 +123,49 @@ protected:
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);
+ /// Compiles an initializer.
+ bool visitInitializer(const Expr *E);
+ /// Compiles an array initializer.
+ bool visitArrayInitializer(const Expr *Initializer);
+ /// Compiles a record initializer.
+ bool visitRecordInitializer(const Expr *Initializer);
+ /// Creates and initializes a variable from the given decl.
+ bool visitVarDecl(const VarDecl *VD);
/// 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);
- });
+ if (!this->emitGetPtrLocal(I, Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+
+ return this->emitPopPtr(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);
- });
+ if (!this->emitGetPtrGlobal(I, Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+
+ return this->emitPopPtr(Init);
}
/// Visits a delegated initializer.
bool visitThisInitializer(const Expr *I) {
- return visitInitializer(I, [this, I] { return this->emitThis(I); });
+ if (!this->emitThis(I))
+ return false;
+
+ if (!visitInitializer(I))
+ return false;
+
+ return this->emitPopPtr(I);
}
/// Creates a local primitive value.
@@ -152,8 +173,7 @@ protected:
bool IsExtended = false);
/// Allocates a space storing a local given its type.
- llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl,
- bool IsExtended = false);
+ std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false);
private:
friend class VariableScope<Emitter>;
@@ -161,6 +181,7 @@ private:
friend class RecordScope<Emitter>;
friend class DeclScope<Emitter>;
friend class OptionScope<Emitter>;
+ friend class ArrayIndexScope<Emitter>;
/// Emits a zero initializer.
bool visitZeroInitializer(PrimType T, const Expr *E);
@@ -188,28 +209,28 @@ private:
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 APSInt constant.
+ bool emitConst(const APSInt &Value, const Expr *E);
+ bool emitConst(const APInt &Value, const Expr *E) {
+ return emitConst(static_cast<APSInt>(Value), 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);
+ template <typename T> bool emitConst(T Value, const Expr *E);
+
+ /// Returns the CXXRecordDecl for the type of the given expression,
+ /// or nullptr if no such decl exists.
+ const CXXRecordDecl *getRecordDecl(const Expr *E) const {
+ QualType T = E->getType();
+ if (const auto *RD = T->getPointeeCXXRecordDecl())
+ return RD;
+ return T->getAsCXXRecordDecl();
}
- /// 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)();
+ /// Returns whether we should create a global variable for the
+ /// given VarDecl.
+ bool shouldBeGloballyIndexed(const VarDecl *VD) const {
+ return VD->hasGlobalStorage() || VD->isConstexpr();
}
protected:
@@ -222,14 +243,11 @@ protected:
/// Current scope.
VariableScope<Emitter> *VarScope = nullptr;
- /// Current argument index.
- llvm::Optional<uint64_t> ArrayIndex;
+ /// Current argument index. Needed to emit ArrayInitIndexExpr.
+ std::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>;
@@ -238,6 +256,11 @@ extern template class ByteCodeExprGen<EvalEmitter>;
/// Scope chain managing the variable lifetimes.
template <class Emitter> class VariableScope {
public:
+ VariableScope(ByteCodeExprGen<Emitter> *Ctx)
+ : Ctx(Ctx), Parent(Ctx->VarScope) {
+ Ctx->VarScope = this;
+ }
+
virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
void add(const Scope::Local &Local, bool IsExtended) {
@@ -262,11 +285,6 @@ public:
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.
@@ -300,7 +318,7 @@ public:
protected:
/// Index of the scope in the chain.
- Optional<unsigned> Idx;
+ std::optional<unsigned> Idx;
};
/// Scope for storage declared in a compound statement.
@@ -320,10 +338,25 @@ public:
ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
void addExtended(const Scope::Local &Local) override {
+ assert(this->Parent);
this->Parent->addLocal(Local);
}
};
+template <class Emitter> class ArrayIndexScope final {
+public:
+ ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
+ OldArrayIndex = Ctx->ArrayIndex;
+ Ctx->ArrayIndex = Index;
+ }
+
+ ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
+
+private:
+ ByteCodeExprGen<Emitter> *Ctx;
+ std::optional<uint64_t> OldArrayIndex;
+};
+
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/Interp/ByteCodeGenError.h b/clang/lib/AST/Interp/ByteCodeGenError.h
index a4fa4917705d..af464b5ed4ab 100644
--- a/clang/lib/AST/Interp/ByteCodeGenError.h
+++ b/clang/lib/AST/Interp/ByteCodeGenError.h
@@ -20,19 +20,19 @@ 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()) {}
+ ByteCodeGenError(SourceRange Range) : Range(Range) {}
+ ByteCodeGenError(const Stmt *S) : ByteCodeGenError(S->getSourceRange()) {}
+ ByteCodeGenError(const Decl *D) : ByteCodeGenError(D->getSourceRange()) {}
void log(raw_ostream &OS) const override { OS << "unimplemented feature"; }
- const SourceLocation &getLoc() const { return Loc; }
+ const SourceRange &getRange() const { return Range; }
static char ID;
private:
- // Start of the item where the error occurred.
- SourceLocation Loc;
+ // Range of the item where the error occurred.
+ SourceRange Range;
// Users are not expected to use error_code.
std::error_code convertToErrorCode() const override {
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 90e84149b055..af97c57c98b7 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -94,11 +94,63 @@ 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);
+ // Constructor. Set up field initializers.
+ if (const auto Ctor = dyn_cast<CXXConstructorDecl>(F)) {
+ const RecordDecl *RD = Ctor->getParent();
+ const Record *R = this->getRecord(RD);
+ if (!R)
+ return false;
+
+ for (const auto *Init : Ctor->inits()) {
+ const Expr *InitExpr = Init->getInit();
+ if (const FieldDecl *Member = Init->getMember()) {
+ const Record::Field *F = R->getField(Member);
+
+ if (std::optional<PrimType> T = this->classify(InitExpr)) {
+ if (!this->emitThis(InitExpr))
+ return false;
+
+ if (!this->visit(InitExpr))
+ return false;
+
+ if (!this->emitInitField(*T, F->Offset, InitExpr))
+ return false;
+
+ if (!this->emitPopPtr(InitExpr))
+ return false;
+ } else {
+ // Non-primitive case. Get a pointer to the field-to-initialize
+ // on the stack and call visitInitialzer() for it.
+ if (!this->emitThis(InitExpr))
+ return false;
+
+ if (!this->emitGetPtrField(F->Offset, InitExpr))
+ return false;
+
+ if (!this->visitInitializer(InitExpr))
+ return false;
+
+ if (!this->emitPopPtr(InitExpr))
+ return false;
+ }
+ } else if (const Type *Base = Init->getBaseClass()) {
+ // Base class initializer.
+ // Get This Base and call initializer on it.
+ auto *BaseDecl = Base->getAsCXXRecordDecl();
+ assert(BaseDecl);
+ const Record::Base *B = R->getBase(BaseDecl);
+ assert(B);
+ if (!this->emitGetPtrThisBase(B->Offset, InitExpr))
+ return false;
+ if (!this->visitInitializer(InitExpr))
+ return false;
+ if (!this->emitPopPtr(InitExpr))
+ return false;
+ }
+ }
+ }
- if (auto *Body = F->getBody())
+ if (const auto *Body = F->getBody())
if (!visitStmt(Body))
return false;
@@ -120,6 +172,16 @@ bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
return visitReturnStmt(cast<ReturnStmt>(S));
case Stmt::IfStmtClass:
return visitIfStmt(cast<IfStmt>(S));
+ case Stmt::WhileStmtClass:
+ return visitWhileStmt(cast<WhileStmt>(S));
+ case Stmt::DoStmtClass:
+ return visitDoStmt(cast<DoStmt>(S));
+ case Stmt::ForStmtClass:
+ return visitForStmt(cast<ForStmt>(S));
+ case Stmt::BreakStmtClass:
+ return visitBreakStmt(cast<BreakStmt>(S));
+ case Stmt::ContinueStmtClass:
+ return visitContinueStmt(cast<ContinueStmt>(S));
case Stmt::NullStmtClass:
return true;
default: {
@@ -145,7 +207,7 @@ bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
for (auto *D : DS->decls()) {
// Variable declarator.
if (auto *VD = dyn_cast<VarDecl>(D)) {
- if (!visitVarDecl(VD))
+ if (!this->visitVarDecl(VD))
return false;
continue;
}
@@ -171,18 +233,21 @@ bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
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))
+ if (!this->emitRVOPtr(RE))
return false;
+ if (!this->visitInitializer(RE))
+ return false;
+ if (!this->emitPopPtr(RE))
+ return false;
+
this->emitCleanup();
return this->emitRetVoid(RS);
}
- } else {
- this->emitCleanup();
- if (!this->emitRetVoid(RS))
- return false;
- return true;
}
+
+ // Void return.
+ this->emitCleanup();
+ return this->emitRetVoid(RS);
}
template <class Emitter>
@@ -231,33 +296,99 @@ bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
}
template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
- auto DT = VD->getType();
+bool ByteCodeStmtGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
+ const Expr *Cond = S->getCond();
+ const Stmt *Body = S->getBody();
- if (!VD->hasLocalStorage()) {
- // No code generation required.
- return true;
- }
+ LabelTy CondLabel = this->getLabel(); // Label before the condition.
+ LabelTy EndLabel = this->getLabel(); // Label after the loop.
+ LoopScope<Emitter> LS(this, EndLabel, CondLabel);
- // 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);
- }
+ this->emitLabel(CondLabel);
+ if (!this->visitBool(Cond))
+ return false;
+ if (!this->jumpFalse(EndLabel))
+ return false;
+
+ if (!this->visitStmt(Body))
+ return false;
+ if (!this->jump(CondLabel))
+ return false;
+
+ this->emitLabel(EndLabel);
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitDoStmt(const DoStmt *S) {
+ const Expr *Cond = S->getCond();
+ const Stmt *Body = S->getBody();
+
+ LabelTy StartLabel = this->getLabel();
+ LabelTy EndLabel = this->getLabel();
+ LabelTy CondLabel = this->getLabel();
+ LoopScope<Emitter> LS(this, EndLabel, CondLabel);
+
+ this->emitLabel(StartLabel);
+ if (!this->visitStmt(Body))
+ return false;
+ this->emitLabel(CondLabel);
+ if (!this->visitBool(Cond))
+ return false;
+ if (!this->jumpTrue(StartLabel))
+ return false;
+ this->emitLabel(EndLabel);
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitForStmt(const ForStmt *S) {
+ // for (Init; Cond; Inc) { Body }
+ const Stmt *Init = S->getInit();
+ const Expr *Cond = S->getCond();
+ const Expr *Inc = S->getInc();
+ const Stmt *Body = S->getBody();
+
+ LabelTy EndLabel = this->getLabel();
+ LabelTy CondLabel = this->getLabel();
+ LabelTy IncLabel = this->getLabel();
+ LoopScope<Emitter> LS(this, EndLabel, IncLabel);
+
+ if (Init && !this->visitStmt(Init))
+ return false;
+ this->emitLabel(CondLabel);
+ if (Cond) {
+ if (!this->visitBool(Cond))
+ return false;
+ if (!this->jumpFalse(EndLabel))
+ return false;
}
+ if (Body && !this->visitStmt(Body))
+ return false;
+ this->emitLabel(IncLabel);
+ if (Inc && !this->discard(Inc))
+ return false;
+ if (!this->jump(CondLabel))
+ return false;
+ this->emitLabel(EndLabel);
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
+ if (!BreakLabel)
+ return false;
+
+ return this->jump(*BreakLabel);
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
+ if (!ContinueLabel)
+ return false;
+
+ return this->jump(*ContinueLabel);
}
namespace clang {
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h
index 3bc665b84b4d..829e199f827c 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.h
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h
@@ -22,7 +22,6 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/ADT/Optional.h"
namespace clang {
namespace interp {
@@ -33,10 +32,10 @@ template <class Emitter> class LabelScope;
/// Compilation context for statements.
template <class Emitter>
-class ByteCodeStmtGen : public ByteCodeExprGen<Emitter> {
+class ByteCodeStmtGen final : public ByteCodeExprGen<Emitter> {
using LabelTy = typename Emitter::LabelTy;
using AddrTy = typename Emitter::AddrTy;
- using OptLabelTy = llvm::Optional<LabelTy>;
+ using OptLabelTy = std::optional<LabelTy>;
using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
public:
@@ -58,13 +57,14 @@ private:
bool visitDeclStmt(const DeclStmt *DS);
bool visitReturnStmt(const ReturnStmt *RS);
bool visitIfStmt(const IfStmt *IS);
+ bool visitWhileStmt(const WhileStmt *S);
+ bool visitDoStmt(const DoStmt *S);
+ bool visitForStmt(const ForStmt *S);
+ bool visitBreakStmt(const BreakStmt *S);
+ bool visitContinueStmt(const ContinueStmt *S);
- /// Compiles a variable declaration.
- bool visitVarDecl(const VarDecl *VD);
-
-private:
/// Type of the expression returned by the function.
- llvm::Optional<PrimType> ReturnType;
+ std::optional<PrimType> ReturnType;
/// Switch case mapping.
CaseMap CaseLabels;
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 3bfcdfcd4c58..16471242f328 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -27,39 +27,52 @@ Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {}
Context::~Context() {}
bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
+ assert(Stk.empty());
Function *Func = P->getFunction(FD);
- if (!Func) {
+ if (!Func || !Func->hasBody()) {
if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) {
Func = *R;
} else {
handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
- Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
+ Parent.FFDiag(Err.getRange().getBegin(),
+ diag::err_experimental_clang_interp_failed)
+ << Err.getRange();
});
return false;
}
}
- if (!Func->isConstexpr())
- return false;
-
- APValue Dummy;
- return Run(Parent, Func, Dummy);
+ return Func->isConstexpr();
}
bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
+ assert(Stk.empty());
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
- return Check(Parent, C.interpretExpr(E));
+ if (Check(Parent, C.interpretExpr(E))) {
+ assert(Stk.empty());
+ return true;
+ }
+
+ Stk.clear();
+ return false;
}
bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
APValue &Result) {
+ assert(Stk.empty());
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
- return Check(Parent, C.interpretDecl(VD));
+ if (Check(Parent, C.interpretDecl(VD))) {
+ assert(Stk.empty());
+ return true;
+ }
+
+ Stk.clear();
+ return false;
}
const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
-llvm::Optional<PrimType> Context::classify(QualType T) {
+std::optional<PrimType> Context::classify(QualType T) const {
if (T->isReferenceType() || T->isPointerType()) {
return PT_Ptr;
}
@@ -112,7 +125,7 @@ unsigned Context::getCharBit() const {
bool Context::Run(State &Parent, Function *Func, APValue &Result) {
InterpState State(Parent, *P, Stk, *this);
- State.Current = new InterpFrame(State, Func, nullptr, {}, {});
+ State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, {});
if (Interpret(State, Result))
return true;
Stk.clear();
@@ -123,7 +136,9 @@ bool Context::Check(State &Parent, llvm::Expected<bool> &&Flag) {
if (Flag)
return *Flag;
handleAllErrors(Flag.takeError(), [&Parent](ByteCodeGenError &Err) {
- Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
+ Parent.FFDiag(Err.getRange().getBegin(),
+ diag::err_experimental_clang_interp_failed)
+ << Err.getRange();
});
return false;
}
diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h
index 0627d9fb14f5..e49422e64b87 100644
--- a/clang/lib/AST/Interp/Context.h
+++ b/clang/lib/AST/Interp/Context.h
@@ -18,7 +18,6 @@
#include "InterpStack.h"
#include "clang/AST/APValue.h"
-#include "llvm/ADT/PointerIntPair.h"
namespace clang {
class ASTContext;
@@ -33,7 +32,7 @@ class State;
enum PrimType : unsigned;
/// Holds all information required to evaluate constexpr code in a module.
-class Context {
+class Context final {
public:
/// Initialises the constexpr VM.
Context(ASTContext &Ctx);
@@ -60,7 +59,7 @@ public:
unsigned getCharBit() const;
/// Classifies an expression.
- llvm::Optional<PrimType> classify(QualType T);
+ std::optional<PrimType> classify(QualType T) const;
private:
/// Runs a function.
@@ -69,7 +68,6 @@ private:
/// Checks a result from the interpreter.
bool Check(State &Parent, llvm::Expected<bool> &&R);
-private:
/// Current compilation context.
ASTContext &Ctx;
/// Interpreter stack, shared across invocations.
diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp
index 5c1a8a9cf306..04bc8681dd6e 100644
--- a/clang/lib/AST/Interp/Descriptor.cpp
+++ b/clang/lib/AST/Interp/Descriptor.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Descriptor.h"
+#include "Boolean.h"
#include "Pointer.h"
#include "PrimType.h"
#include "Record.h"
@@ -39,6 +40,11 @@ static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) {
template <typename T>
static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) {
+ InitMap *IM = *reinterpret_cast<InitMap **>(Ptr);
+ if (IM != (InitMap *)-1)
+ free(IM);
+
+ Ptr += sizeof(InitMap *);
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
reinterpret_cast<T *>(Ptr)[I].~T();
}
@@ -72,9 +78,10 @@ static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable,
Desc->IsBase = false;
Desc->IsActive = IsActive;
Desc->IsConst = IsConst || D->IsConst;
- Desc->IsMutable = IsMutable || D->IsMutable;
+ Desc->IsFieldMutable = IsMutable || D->IsMutable;
if (auto Fn = D->ElemDesc->CtorFn)
- Fn(B, ElemLoc, Desc->IsConst, Desc->IsMutable, IsActive, D->ElemDesc);
+ Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsActive,
+ D->ElemDesc);
}
}
@@ -121,13 +128,14 @@ static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable,
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
Desc->Offset = SubOff;
Desc->Desc = F;
- Desc->IsInitialized = (B->isStatic() || F->IsArray) && !IsBase;
+ Desc->IsInitialized = F->IsArray && !IsBase;
Desc->IsBase = IsBase;
Desc->IsActive = IsActive && !IsUnion;
Desc->IsConst = IsConst || F->IsConst;
- Desc->IsMutable = IsMutable || F->IsMutable;
+ Desc->IsFieldMutable = IsMutable || F->IsMutable;
if (auto Fn = F->CtorFn)
- Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsMutable, Desc->IsActive, F);
+ Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsFieldMutable, Desc->IsActive,
+ F);
};
for (const auto &B : D->ElemRecord->bases())
CtorSub(B.Offset, B.Desc, /*isBase=*/true);
@@ -178,26 +186,30 @@ static BlockCtorFn getCtorArrayPrim(PrimType Type) {
}
static BlockDtorFn getDtorArrayPrim(PrimType Type) {
- COMPOSITE_TYPE_SWITCH(Type, return dtorArrayTy<T>, return nullptr);
+ TYPE_SWITCH(Type, return dtorArrayTy<T>);
+ llvm_unreachable("unknown Expr");
}
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)) {
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
+ bool IsConst, bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(primSize(Type)), Size(ElemSize),
+ MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), IsConst(IsConst),
+ IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(getCtorPrim(Type)),
+ DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) {
+ assert(AllocSize >= Size);
assert(Source && "Missing source");
}
-Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems,
- bool IsConst, bool IsTemporary, bool IsMutable)
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
+ size_t NumElems, bool IsConst, bool IsTemporary,
+ bool IsMutable)
: Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
- AllocSize(align(Size) + sizeof(InitMap *)), IsConst(IsConst),
+ MDSize(MD.value_or(0)),
+ AllocSize(align(Size) + sizeof(InitMap *) + MDSize), IsConst(IsConst),
IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true),
CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
MoveFn(getMoveArrayPrim(Type)) {
@@ -206,39 +218,42 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems,
Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary,
UnknownSize)
- : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
+ : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), MDSize(0),
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)
+Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, MetadataSize MD,
+ 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) {
+ Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
+ AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
+ 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) {
+ Size(UnknownSizeMark), MDSize(0), 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)
+Descriptor::Descriptor(const DeclTy &D, Record *R, MetadataSize MD,
+ 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) {
+ Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
+ ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
+ IsTemporary(IsTemporary), CtorFn(ctorRecord), DtorFn(dtorRecord),
+ MoveFn(moveRecord) {
assert(Source && "Missing source");
}
@@ -259,9 +274,7 @@ SourceLocation Descriptor::getLocation() const {
}
InitMap::InitMap(unsigned N) : UninitFields(N) {
- for (unsigned I = 0; I < N / PER_FIELD; ++I) {
- data()[I] = 0;
- }
+ std::fill_n(data(), (N + PER_FIELD - 1) / PER_FIELD, 0);
}
InitMap::T *InitMap::data() {
@@ -269,9 +282,14 @@ InitMap::T *InitMap::data() {
return reinterpret_cast<T *>(Start);
}
+const InitMap::T *InitMap::data() const {
+ auto *Start = reinterpret_cast<const char *>(this) + align(sizeof(InitMap));
+ return reinterpret_cast<const T *>(Start);
+}
+
bool InitMap::initialize(unsigned I) {
unsigned Bucket = I / PER_FIELD;
- unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
+ T Mask = T(1) << (I % PER_FIELD);
if (!(data()[Bucket] & Mask)) {
data()[Bucket] |= Mask;
UninitFields -= 1;
@@ -279,10 +297,9 @@ bool InitMap::initialize(unsigned I) {
return UninitFields == 0;
}
-bool InitMap::isInitialized(unsigned I) {
+bool InitMap::isInitialized(unsigned I) const {
unsigned Bucket = I / PER_FIELD;
- unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
- return data()[Bucket] & Mask;
+ return data()[Bucket] & (T(1) << (I % PER_FIELD));
}
InitMap *InitMap::allocate(unsigned N) {
diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h
index 11072cab3e90..6ef4fc2f4c9b 100644
--- a/clang/lib/AST/Interp/Descriptor.h
+++ b/clang/lib/AST/Interp/Descriptor.h
@@ -47,8 +47,36 @@ using BlockMoveFn = void (*)(Block *Storage, char *SrcFieldPtr,
/// Object size as used by the interpreter.
using InterpSize = unsigned;
+/// 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 IsFieldMutable : 1;
+
+ Descriptor *Desc;
+};
+
/// Describes a memory block created by an allocation site.
-struct Descriptor {
+struct Descriptor final {
private:
/// Original declaration, used to emit the error message.
const DeclTy Source;
@@ -56,6 +84,8 @@ private:
const InterpSize ElemSize;
/// Size of the storage, in host bytes.
const InterpSize Size;
+ // Size of the metadata.
+ const InterpSize MDSize;
/// Size of the allocation (storage + metadata), in host bytes.
const InterpSize AllocSize;
@@ -66,6 +96,9 @@ public:
/// Token to denote structures of unknown size.
struct UnknownSize {};
+ using MetadataSize = std::optional<InterpSize>;
+ static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor);
+
/// Pointer to the record, if block contains records.
Record *const ElemRecord = nullptr;
/// Descriptor of the array element.
@@ -85,26 +118,26 @@ public:
const BlockMoveFn MoveFn = nullptr;
/// Allocates a descriptor for a primitive.
- Descriptor(const DeclTy &D, PrimType Type, bool IsConst, bool IsTemporary,
- bool IsMutable);
+ Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, 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);
+ Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, 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);
+ Descriptor(const DeclTy &D, Descriptor *Elem, MetadataSize MD,
+ 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);
+ Descriptor(const DeclTy &D, Record *R, MetadataSize MD, bool IsConst,
+ bool IsTemporary, bool IsMutable);
QualType getType() const;
SourceLocation getLocation() const;
@@ -113,15 +146,15 @@ public:
const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
const ValueDecl *asValueDecl() const {
- return dyn_cast_or_null<ValueDecl>(asDecl());
+ return dyn_cast_if_present<ValueDecl>(asDecl());
}
const FieldDecl *asFieldDecl() const {
- return dyn_cast_or_null<FieldDecl>(asDecl());
+ return dyn_cast_if_present<FieldDecl>(asDecl());
}
const RecordDecl *asRecordDecl() const {
- return dyn_cast_or_null<RecordDecl>(asDecl());
+ return dyn_cast_if_present<RecordDecl>(asDecl());
}
/// Returns the size of the object without metadata.
@@ -134,6 +167,8 @@ public:
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 size of the metadata.
+ unsigned getMetadataSize() const { return MDSize; }
/// Returns the number of elements stored in the block.
unsigned getNumElems() const {
@@ -154,39 +189,11 @@ public:
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 initialized, the pointer to
/// this structure is 0. If the object was fully initialized, the pointer is -1.
-struct InitMap {
+struct InitMap final {
private:
/// Type packing bits.
using T = uint64_t;
@@ -198,13 +205,14 @@ private:
/// Returns a pointer to storage.
T *data();
+ const T *data() const;
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);
+ bool isInitialized(unsigned I) const;
/// Allocates a map holding N elements.
static InitMap *allocate(unsigned N);
diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp
index 36adbe296b0c..d31e879d516f 100644
--- a/clang/lib/AST/Interp/Disasm.cpp
+++ b/clang/lib/AST/Interp/Disasm.cpp
@@ -21,17 +21,13 @@
using namespace clang;
using namespace clang::interp;
-template <typename T>
-inline std::enable_if_t<!std::is_pointer<T>::value, T> ReadArg(Program &P,
- CodePtr OpPC) {
- return OpPC.read<T>();
-}
-
-template <typename T>
-inline std::enable_if_t<std::is_pointer<T>::value, T> ReadArg(Program &P,
- CodePtr OpPC) {
- uint32_t ID = OpPC.read<uint32_t>();
- return reinterpret_cast<T>(P.getNativePointer(ID));
+template <typename T> inline T ReadArg(Program &P, CodePtr &OpPC) {
+ if constexpr (std::is_pointer_v<T>) {
+ uint32_t ID = OpPC.read<uint32_t>();
+ return reinterpret_cast<T>(P.getNativePointer(ID));
+ } else {
+ return OpPC.read<T>();
+ }
}
LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
@@ -40,10 +36,11 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
if (F) {
if (auto *Cons = dyn_cast<CXXConstructorDecl>(F)) {
DeclarationName Name = Cons->getParent()->getDeclName();
- OS << Name << "::" << Name << ":\n";
+ OS << Name << "::" << Name;
} else {
- OS << F->getDeclName() << ":\n";
+ OS << F->getDeclName();
}
+ OS << " " << (const void*)this << ":\n";
} else {
OS << "<<expr>>\n";
}
@@ -51,6 +48,7 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
OS << "frame size: " << getFrameSize() << "\n";
OS << "arg size: " << getArgSize() << "\n";
OS << "rvo: " << hasRVO() << "\n";
+ OS << "this arg: " << hasThisPointer() << "\n";
auto PrintName = [&OS](const char *Name) {
OS << Name;
@@ -74,6 +72,10 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
+ OS << ":: Program\n";
+ OS << "Global Variables: " << Globals.size() << "\n";
+ OS << "Functions: " << Funcs.size() << "\n";
+ OS << "\n";
for (auto &Func : Funcs) {
Func.second->dump();
}
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index 22e8695b9211..72fd3b45254b 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -23,7 +23,8 @@ 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());
+ S.Current =
+ new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr());
}
llvm::Expected<bool> EvalEmitter::interpretExpr(const Expr *E) {
@@ -54,6 +55,16 @@ Scope::Local EvalEmitter::createLocal(Descriptor *D) {
auto *B = new (Memory.get()) Block(D, /*isStatic=*/false);
B->invokeCtor();
+ // Initialize local variable inline descriptor.
+ InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
+ Desc.Desc = D;
+ Desc.Offset = sizeof(InlineDescriptor);
+ Desc.IsActive = true;
+ Desc.IsBase = false;
+ Desc.IsFieldMutable = false;
+ Desc.IsConst = false;
+ Desc.IsInitialized = false;
+
// Register the local.
unsigned Off = Locals.size();
Locals.insert({Off, std::move(Memory)});
@@ -123,7 +134,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
const Pointer &FP = Ptr.atField(F.Offset);
QualType FieldTy = F.Decl->getType();
if (FP.isActive()) {
- if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
+ if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
} else {
Ok &= Composite(FieldTy, FP, Value);
@@ -145,7 +156,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
const Pointer &FP = Ptr.atField(FD->Offset);
APValue &Value = R.getStructField(I);
- if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
+ if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
} else {
Ok &= Composite(FieldTy, FP, Value);
@@ -177,7 +188,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
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)) {
+ if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
TYPE_SWITCH(*T, Ok &= ReturnValue<T>(EP.deref<T>(), Slot));
} else {
Ok &= Composite(ElemTy, EP.narrow(), Slot);
@@ -199,7 +210,8 @@ bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
auto It = Locals.find(I);
assert(It != Locals.end() && "Missing local variable");
- S.Stk.push<Pointer>(reinterpret_cast<Block *>(It->second.get()));
+ Block *B = reinterpret_cast<Block *>(It->second.get());
+ S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
return true;
}
@@ -213,7 +225,7 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
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));
+ S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
return true;
}
@@ -227,7 +239,10 @@ bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
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>();
+ *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>();
+ InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
+ Desc.IsInitialized = true;
+
return true;
}
diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h
index eec2ff8ee753..6b6d0d621901 100644
--- a/clang/lib/AST/Interp/EvalEmitter.h
+++ b/clang/lib/AST/Interp/EvalEmitter.h
@@ -23,7 +23,6 @@
#include "llvm/Support/Error.h"
namespace clang {
-class FunctionDecl;
namespace interp {
class Context;
class Function;
@@ -71,7 +70,7 @@ protected:
Local createLocal(Descriptor *D);
/// Returns the source location of the current opcode.
- SourceInfo getSource(Function *F, CodePtr PC) const override {
+ SourceInfo getSource(const Function *F, CodePtr PC) const override {
return F ? F->getSource(PC) : CurrentSource;
}
@@ -97,7 +96,7 @@ private:
// value which is mapped to the location of the opcode being evaluated.
CodePtr OpPC;
/// Location of a failure.
- llvm::Optional<SourceLocation> BailLocation;
+ std::optional<SourceLocation> BailLocation;
/// Location of the current instruction.
SourceInfo CurrentSource;
@@ -110,12 +109,7 @@ private:
/// 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);
+ bool isActive() const { return CurrentLabel == ActiveLabel; }
protected:
#define GET_EVAL_PROTO
diff --git a/clang/lib/AST/Interp/Function.cpp b/clang/lib/AST/Interp/Function.cpp
index 6ba97df1cd30..40001faad411 100644
--- a/clang/lib/AST/Interp/Function.cpp
+++ b/clang/lib/AST/Interp/Function.cpp
@@ -17,13 +17,11 @@ using namespace clang::interp;
Function::Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
llvm::SmallVector<PrimType, 8> &&ParamTypes,
- llvm::DenseMap<unsigned, ParamDescriptor> &&Params)
+ llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
+ bool HasThisPointer, bool HasRVO)
: 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(); }
+ ParamTypes(std::move(ParamTypes)), Params(std::move(Params)),
+ HasThisPointer(HasThisPointer), HasRVO(HasRVO) {}
Function::ParamDescriptor Function::getParamDescriptor(unsigned Offset) const {
auto It = Params.find(Offset);
@@ -32,11 +30,12 @@ Function::ParamDescriptor Function::getParamDescriptor(unsigned Offset) const {
}
SourceInfo Function::getSource(CodePtr PC) const {
+ assert(PC >= getCodeBegin() && "PC does not belong to this function");
+ assert(PC <= getCodeEnd() && "PC Does not belong to this function");
unsigned Offset = PC - getCodeBegin();
using Elem = std::pair<unsigned, SourceInfo>;
auto It = llvm::lower_bound(SrcMap, Elem{Offset, {}}, llvm::less_first());
- if (It == SrcMap.end() || It->first != Offset)
- llvm::report_fatal_error("missing source location");
+ assert(It != SrcMap.end());
return It->second;
}
diff --git a/clang/lib/AST/Interp/Function.h b/clang/lib/AST/Interp/Function.h
index ac1dffea1160..5b2a77f1a12d 100644
--- a/clang/lib/AST/Interp/Function.h
+++ b/clang/lib/AST/Interp/Function.h
@@ -29,7 +29,7 @@ enum PrimType : uint32_t;
/// Describes a scope block.
///
/// The block gathers all the descriptors of the locals defined in this block.
-class Scope {
+class Scope final {
public:
/// Information about a local's storage.
struct Local {
@@ -43,7 +43,7 @@ public:
Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
- llvm::iterator_range<LocalVectorTy::iterator> locals() {
+ llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
return llvm::make_range(Descriptors.begin(), Descriptors.end());
}
@@ -56,23 +56,42 @@ private:
///
/// Contains links to the bytecode of the function, as well as metadata
/// describing all arguments and stack-local variables.
-class Function {
+///
+/// # Calling Convention
+///
+/// When calling a function, all argument values must be on the stack.
+///
+/// If the function has a This pointer (i.e. hasThisPointer() returns true,
+/// the argument values need to be preceeded by a Pointer for the This object.
+///
+/// If the function uses Return Value Optimization, the arguments (and
+/// potentially the This pointer) need to be proceeded by a Pointer pointing
+/// to the location to construct the returned value.
+///
+/// After the function has been called, it will remove all arguments,
+/// including RVO and This pointer, from the stack.
+///
+class Function final {
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
+ /// Returns the size of the argument stack.
unsigned getArgSize() const { return ArgSize; }
/// Returns a pointer to the start of the code.
- CodePtr getCodeBegin() const;
+ CodePtr getCodeBegin() const { return Code.data(); }
/// Returns a pointer to the end of the code.
- CodePtr getCodeEnd() const;
+ CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
/// Returns the original FunctionDecl.
const FunctionDecl *getDecl() const { return F; }
+ /// Returns the name of the function decl this code
+ /// was generated for.
+ const std::string getName() const { return F->getNameInfo().getAsString(); }
+
/// Returns the location.
SourceLocation getLoc() const { return Loc; }
@@ -80,21 +99,24 @@ public:
ParamDescriptor getParamDescriptor(unsigned Offset) const;
/// Checks if the first argument is a RVO pointer.
- bool hasRVO() const { return ParamTypes.size() != Params.size(); }
+ bool hasRVO() const { return HasRVO; }
/// Range over the scope blocks.
- llvm::iterator_range<llvm::SmallVector<Scope, 2>::iterator> scopes() {
+ llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
+ scopes() const {
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());
+ using arg_reverse_iterator =
+ SmallVectorImpl<PrimType>::const_reverse_iterator;
+ llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
+ return llvm::reverse(ParamTypes);
}
/// Returns a specific scope.
Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
+ const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; }
/// Returns the source information at a given PC.
SourceInfo getSource(CodePtr PC) const;
@@ -108,11 +130,22 @@ public:
/// Checks if the function is a constructor.
bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
+ /// Checks if the function is fully done compiling.
+ bool isFullyCompiled() const { return IsFullyCompiled; }
+
+ bool hasThisPointer() const { return HasThisPointer; }
+
+ // Checks if the funtion already has a body attached.
+ bool hasBody() const { return HasBody; }
+
+ unsigned getNumParams() const { return ParamTypes.size(); }
+
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);
+ llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
+ bool HasThisPointer, bool HasRVO);
/// Sets the code of a function.
void setCode(unsigned NewFrameSize, std::vector<char> &&NewCode, SourceMap &&NewSrcMap,
@@ -122,8 +155,11 @@ private:
SrcMap = std::move(NewSrcMap);
Scopes = std::move(NewScopes);
IsValid = true;
+ HasBody = true;
}
+ void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
+
private:
friend class Program;
friend class ByteCodeEmitter;
@@ -135,7 +171,7 @@ private:
/// Declaration this function was compiled from.
const FunctionDecl *F;
/// Local area size: storage + metadata.
- unsigned FrameSize;
+ unsigned FrameSize = 0;
/// Size of the argument stack.
unsigned ArgSize;
/// Program code.
@@ -150,6 +186,18 @@ private:
llvm::DenseMap<unsigned, ParamDescriptor> Params;
/// Flag to indicate if the function is valid.
bool IsValid = false;
+ /// Flag to indicate if the function is done being
+ /// compiled to bytecode.
+ bool IsFullyCompiled = false;
+ /// Flag indicating if this function takes the this pointer
+ /// as the first implicit argument
+ bool HasThisPointer = false;
+ /// Whether this function has Return Value Optimization, i.e.
+ /// the return value is constructed in the caller's stack frame.
+ /// This is done for functions that return non-primive values.
+ bool HasRVO = false;
+ /// If we've already compiled the function's body.
+ bool HasBody = false;
public:
/// Dumps the disassembled bytecode to \c llvm::errs().
diff --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h
index 46cd611ee389..8a742333ae57 100644
--- a/clang/lib/AST/Interp/Integral.h
+++ b/clang/lib/AST/Interp/Integral.h
@@ -53,17 +53,17 @@ template <> struct Repr<64, true> { using Type = int64_t; };
/// 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 {
+template <unsigned Bits, bool Signed> class Integral final {
private:
template <unsigned OtherBits, bool OtherSigned> friend class Integral;
// The primitive representing the integral.
- using T = typename Repr<Bits, Signed>::Type;
- T V;
+ using ReprT = typename Repr<Bits, Signed>::Type;
+ ReprT V;
/// Primitive representing limits.
- static const auto Min = std::numeric_limits<T>::min();
- static const auto Max = std::numeric_limits<T>::max();
+ static const auto Min = std::numeric_limits<ReprT>::min();
+ static const auto Max = std::numeric_limits<ReprT>::max();
/// Construct an integral from anything that is convertible to storage.
template <typename T> explicit Integral(T V) : V(V) {}
@@ -107,7 +107,7 @@ public:
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
}
APSInt toAPSInt(unsigned NumBits) const {
- if (Signed)
+ if constexpr (Signed)
return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
else
return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
@@ -124,25 +124,27 @@ public:
bool isMin() const { return *this == min(bitWidth()); }
- bool isMinusOne() const { return Signed && V == T(-1); }
+ bool isMinusOne() const { return Signed && V == ReprT(-1); }
constexpr static bool isSigned() { return Signed; }
- bool isNegative() const { return V < T(0); }
+ bool isNegative() const { return V < ReprT(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); }
+ unsigned countLeadingZeros() const {
+ return llvm::countLeadingZeros<ReprT>(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;
+ const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
+ const ReprT SignBit = ReprT(1) << (TruncBits - 1);
+ const ReprT ExtMask = ~BitMask;
return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
}
@@ -155,9 +157,11 @@ public:
return Integral(Max);
}
- template <typename T>
- static std::enable_if_t<std::is_integral<T>::value, Integral> from(T Value) {
- return Integral(Value);
+ template <typename ValT> static Integral from(ValT Value) {
+ if constexpr (std::is_integral<ValT>::value)
+ return Integral(Value);
+ else
+ return Integral::from(static_cast<Integral::ReprT>(Value));
}
template <unsigned SrcBits, bool SrcSign>
@@ -167,7 +171,7 @@ public:
}
template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) {
- if (SrcSign)
+ if constexpr (SrcSign)
return Integral(Value.V.getSExtValue());
else
return Integral(Value.V.getZExtValue());
@@ -180,15 +184,15 @@ public:
}
static bool inRange(int64_t Value, unsigned NumBits) {
- return CheckRange<T, Min, Max>(Value);
+ return CheckRange<ReprT, Min, Max>(Value);
}
static bool increment(Integral A, Integral *R) {
- return add(A, Integral(T(1)), A.bitWidth(), R);
+ return add(A, Integral(ReprT(1)), A.bitWidth(), R);
}
static bool decrement(Integral A, Integral *R) {
- return sub(A, Integral(T(1)), A.bitWidth(), R);
+ return sub(A, Integral(ReprT(1)), A.bitWidth(), R);
}
static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
@@ -203,56 +207,74 @@ public:
return CheckMulUB(A.V, B.V, R->V);
}
-private:
- template <typename T>
- static std::enable_if_t<std::is_signed<T>::value, bool> CheckAddUB(T A, T B,
- T &R) {
- return llvm::AddOverflow<T>(A, B, R);
+ static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V % B.V);
+ return false;
+ }
+
+ static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V / B.V);
+ return false;
}
- template <typename T>
- static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckAddUB(T A, T B,
- T &R) {
- R = A + B;
+ static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V & B.V);
return false;
}
- template <typename T>
- static std::enable_if_t<std::is_signed<T>::value, bool> CheckSubUB(T A, T B,
- T &R) {
- return llvm::SubOverflow<T>(A, B, R);
+ static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V | B.V);
+ return false;
}
- template <typename T>
- static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckSubUB(T A, T B,
- T &R) {
- R = A - B;
+ static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V ^ B.V);
return false;
}
- template <typename T>
- static std::enable_if_t<std::is_signed<T>::value, bool> CheckMulUB(T A, T B,
- T &R) {
- return llvm::MulOverflow<T>(A, B, R);
+ static bool neg(Integral A, Integral *R) {
+ *R = -A;
+ return false;
}
- template <typename T>
- static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckMulUB(T A, T B,
- T &R) {
- R = A * B;
+ static bool comp(Integral A, Integral *R) {
+ *R = Integral(~A.V);
return false;
}
- template <typename T, T Min, T Max>
- static std::enable_if_t<std::is_signed<T>::value, bool>
- CheckRange(int64_t V) {
- return Min <= V && V <= Max;
+private:
+ template <typename T> static bool CheckAddUB(T A, T B, T &R) {
+ if constexpr (std::is_signed_v<T>) {
+ return llvm::AddOverflow<T>(A, B, R);
+ } else {
+ R = A + B;
+ return false;
+ }
}
- template <typename T, T Min, T Max>
- static std::enable_if_t<std::is_unsigned<T>::value, bool>
- CheckRange(int64_t V) {
- return V >= 0 && static_cast<uint64_t>(V) <= Max;
+ template <typename T> static bool CheckSubUB(T A, T B, T &R) {
+ if constexpr (std::is_signed_v<T>) {
+ return llvm::SubOverflow<T>(A, B, R);
+ } else {
+ R = A - B;
+ return false;
+ }
+ }
+
+ template <typename T> static bool CheckMulUB(T A, T B, T &R) {
+ if constexpr (std::is_signed_v<T>) {
+ return llvm::MulOverflow<T>(A, B, R);
+ } else {
+ R = A * B;
+ return false;
+ }
+ }
+ template <typename T, T Min, T Max> static bool CheckRange(int64_t V) {
+ if constexpr (std::is_signed_v<T>) {
+ return Min <= V && V <= Max;
+ } else {
+ return V >= 0 && static_cast<uint64_t>(V) <= Max;
+ }
}
};
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index cec3f6d6160e..6a600b306bad 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -1,4 +1,4 @@
-//===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
+//===------- Interp.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.
@@ -201,8 +201,8 @@ bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
- const auto &Src = S.Current->getSource(OpPC);
if (Ptr.isZero()) {
+ const auto &Src = S.Current->getSource(OpPC);
if (Ptr.isField())
S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
@@ -213,6 +213,7 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
}
if (!Ptr.isLive()) {
+ const auto &Src = S.Current->getSource(OpPC);
bool IsTemp = Ptr.isTemporary();
S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
@@ -330,17 +331,18 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return true;
}
-bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) {
- const SourceLocation &Loc = S.Current->getLocation(OpPC);
+bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
if (F->isVirtual()) {
if (!S.getLangOpts().CPlusPlus20) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
return false;
}
}
if (!F->isConstexpr()) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
if (S.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = F->getDecl();
@@ -398,9 +400,92 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
S.Note(MD->getLocation(), diag::note_declared_at);
return false;
}
+
+static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI,
+ QualType SubObjType,
+ SourceLocation SubObjLoc) {
+ S.FFDiag(SI, diag::note_constexpr_uninitialized) << true << SubObjType;
+ if (SubObjLoc.isValid())
+ S.Note(SubObjLoc, diag::note_constexpr_subobject_declared_here);
+}
+
+static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr, const Record *R);
+
+static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr,
+ const ConstantArrayType *CAT) {
+ bool Result = true;
+ size_t NumElems = CAT->getSize().getZExtValue();
+ QualType ElemType = CAT->getElementType();
+
+ if (isa<RecordType>(ElemType.getTypePtr())) {
+ const Record *R = BasePtr.getElemRecord();
+ for (size_t I = 0; I != NumElems; ++I) {
+ Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+ Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R);
+ }
+ } else if (auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
+ for (size_t I = 0; I != NumElems; ++I) {
+ Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+ Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT);
+ }
+ } else {
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!BasePtr.atIndex(I).isInitialized()) {
+ DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), ElemType,
+ BasePtr.getFieldDesc()->getLocation());
+ Result = false;
+ }
+ }
+ }
+
+ return Result;
+}
+
+static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr, const Record *R) {
+ assert(R);
+ bool Result = true;
+ // Check all fields of this record are initialized.
+ for (const Record::Field &F : R->fields()) {
+ Pointer FieldPtr = BasePtr.atField(F.Offset);
+ QualType FieldType = F.Decl->getType();
+
+ if (FieldType->isRecordType()) {
+ Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
+ } else if (FieldType->isArrayType()) {
+ const auto *CAT =
+ cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
+ Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT);
+ } else if (!FieldPtr.isInitialized()) {
+ DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC),
+ F.Decl->getType(), F.Decl->getLocation());
+ Result = false;
+ }
+ }
+ return Result;
+}
+
+bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) {
+ assert(!This.isZero());
+ const Record *R = This.getRecord();
+ return CheckFieldsInitialized(S, OpPC, This, R);
+}
+
bool Interpret(InterpState &S, APValue &Result) {
+ // The current stack frame when we started Interpret().
+ // This is being used by the ops to determine wheter
+ // to return from this function and thus terminate
+ // interpretation.
+ const InterpFrame *StartFrame = S.Current;
+ assert(!S.Current->isRoot());
CodePtr PC = S.Current->getPC();
+ // Empty program.
+ if (!PC)
+ return true;
+
for (;;) {
auto Op = PC.read<Opcode>();
CodePtr OpPC = PC;
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index a1d90f26ba46..ed3accd98a90 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
#define LLVM_CLANG_AST_INTERP_INTERP_H
+#include "Boolean.h"
#include "Function.h"
#include "InterpFrame.h"
#include "InterpStack.h"
@@ -30,7 +31,6 @@
#include "llvm/Support/Endian.h"
#include <limits>
#include <type_traits>
-#include <vector>
namespace clang {
namespace interp {
@@ -84,7 +84,7 @@ bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
/// Checks if a method can be called.
-bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F);
+bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
/// Checks the 'this' pointer.
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
@@ -92,7 +92,53 @@ 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(); }
+/// Checks that all fields are initialized after a constructor call.
+bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
+
+/// Checks if the shift operation is legal.
+template <typename RT>
+bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) {
+ if (RHS.isNegative()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
+ return false;
+ }
+
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of
+ // the shifted type.
+ if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ const APSInt Val = RHS.toAPSInt();
+ QualType Ty = E->getType();
+ S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
+ return false;
+ }
+ return true;
+}
+
+/// Checks if Div/Rem operation on LHS and RHS is valid.
+template <typename T>
+bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
+ if (RHS.isZero()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_expr_divide_by_zero);
+ return false;
+ }
+
+ if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
+ APSInt LHSInt = LHS.toAPSInt();
+ SmallString<32> Trunc;
+ (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ const Expr *E = S.Current->getExpr(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
+ return false;
+ }
+ return true;
+}
+
+/// Interpreter entry point.
+bool Interpret(InterpState &S, APValue &Result);
//===----------------------------------------------------------------------===//
// Add, Sub, Mul
@@ -154,6 +200,240 @@ bool Mul(InterpState &S, CodePtr OpPC) {
return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
}
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS & RHS' on the stack
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool BitAnd(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ unsigned Bits = RHS.bitWidth();
+ T Result;
+ if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS | RHS' on the stack
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool BitOr(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ unsigned Bits = RHS.bitWidth();
+ T Result;
+ if (!T::bitOr(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS ^ RHS' on the stack
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool BitXor(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ unsigned Bits = RHS.bitWidth();
+ T Result;
+ if (!T::bitXor(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Rem(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ if (!CheckDivRem(S, OpPC, LHS, RHS))
+ return false;
+
+ const unsigned Bits = RHS.bitWidth() * 2;
+ T Result;
+ if (!T::rem(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS / RHS' on the stack
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Div(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ if (!CheckDivRem(S, OpPC, LHS, RHS))
+ return false;
+
+ const unsigned Bits = RHS.bitWidth() * 2;
+ T Result;
+ if (!T::div(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Inv
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Inv(InterpState &S, CodePtr OpPC) {
+ using BoolT = PrimConv<PT_Bool>::T;
+ const T &Val = S.Stk.pop<T>();
+ const unsigned Bits = Val.bitWidth();
+ Boolean R;
+ Boolean::inv(BoolT::from(Val, Bits), &R);
+
+ S.Stk.push<BoolT>(R);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Neg
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Neg(InterpState &S, CodePtr OpPC) {
+ const T &Val = S.Stk.pop<T>();
+ T Result;
+ T::neg(Val, &Result);
+
+ S.Stk.push<T>(Result);
+ return true;
+}
+
+enum class PushVal : bool {
+ No,
+ Yes,
+};
+enum class IncDecOp {
+ Inc,
+ Dec,
+};
+
+template <typename T, IncDecOp Op, PushVal DoPush>
+bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ T Value = Ptr.deref<T>();
+ T Result;
+
+ if constexpr (DoPush == PushVal::Yes)
+ S.Stk.push<T>(Result);
+
+ if constexpr (Op == IncDecOp::Inc) {
+ if (!T::increment(Value, &Result)) {
+ Ptr.deref<T>() = Result;
+ return true;
+ }
+ } else {
+ if (!T::decrement(Value, &Result)) {
+ Ptr.deref<T>() = Result;
+ return true;
+ }
+ }
+
+ // Something went wrong with the previous operation. Compute the
+ // result with another bit of precision.
+ unsigned Bits = Value.bitWidth() + 1;
+ APSInt APResult;
+ if constexpr (Op == IncDecOp::Inc)
+ APResult = ++Value.toAPSInt(Bits);
+ else
+ APResult = --Value.toAPSInt(Bits);
+
+ // Report undefined behaviour, stopping if required.
+ const Expr *E = S.Current->getExpr(OpPC);
+ QualType Type = E->getType();
+ if (S.checkingForUndefinedBehavior()) {
+ SmallString<32> Trunc;
+ APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
+ auto Loc = E->getExprLoc();
+ S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
+ return true;
+ }
+
+ S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
+ return S.noteUndefinedBehavior();
+}
+
+/// 1) Pops a pointer from the stack
+/// 2) Load the value from the pointer
+/// 3) Writes the value increased by one back to the pointer
+/// 4) Pushes the original (pre-inc) value on the stack.
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Inc(InterpState &S, CodePtr OpPC) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
+}
+
+/// 1) Pops a pointer from the stack
+/// 2) Load the value from the pointer
+/// 3) Writes the value increased by one back to the pointer
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool IncPop(InterpState &S, CodePtr OpPC) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
+}
+
+/// 1) Pops a pointer from the stack
+/// 2) Load the value from the pointer
+/// 3) Writes the value decreased by one back to the pointer
+/// 4) Pushes the original (pre-dec) value on the stack.
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Dec(InterpState &S, CodePtr OpPC) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
+}
+
+/// 1) Pops a pointer from the stack
+/// 2) Load the value from the pointer
+/// 3) Writes the value decreased by one back to the pointer
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool DecPop(InterpState &S, CodePtr OpPC) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
+}
+
+/// 1) Pops the value from the stack.
+/// 2) Pushes the bitwise complemented value on the stack (~V).
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Comp(InterpState &S, CodePtr OpPC) {
+ const T &Val = S.Stk.pop<T>();
+ T Result;
+ if (!T::comp(Val, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// EQ, NE, GT, GE, LT, LE
//===----------------------------------------------------------------------===//
@@ -209,6 +489,16 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
} else {
unsigned VL = LHS.getByteOffset();
unsigned VR = RHS.getByteOffset();
+
+ // In our Pointer class, a pointer to an array and a pointer to the first
+ // element in the same array are NOT equal. They have the same Base value,
+ // but a different Offset. This is a pretty rare case, so we fix this here
+ // by comparing pointers to the first elements.
+ if (LHS.inArray() && LHS.isRoot())
+ VL = LHS.atIndex(0).getByteOffset();
+ if (RHS.inArray() && RHS.isRoot())
+ VR = RHS.atIndex(0).getByteOffset();
+
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
return true;
}
@@ -304,7 +594,10 @@ bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
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));
+ const Pointer &Ptr = S.Current->getLocalPointer(I);
+ if (!CheckLoad(S, OpPC, Ptr))
+ return false;
+ S.Stk.push<T>(Ptr.deref<T>());
return true;
}
@@ -329,6 +622,8 @@ bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
+/// 1) Peeks a pointer on the stack
+/// 2) Pushes the value of the pointer's field on the stack
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>();
@@ -358,6 +653,8 @@ bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
+/// 1) Pops a pointer from the stack
+/// 2) Pushes the value of the pointer's field on the stack
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>();
@@ -463,10 +760,13 @@ bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
+/// 1) Pops the value from the stack
+/// 2) Peeks a pointer from the stack
+/// 3) Pushes the value to field I of the pointer on the stack
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);
+ const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
Field.deref<T>() = Value;
Field.activate();
Field.initialize();
@@ -516,6 +816,8 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
+/// 1) Pops a Pointer from the stack
+/// 2) Pushes Pointer.atField(Off) on the stack
inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckNull(S, OpPC, Ptr, CSK_Field))
@@ -638,6 +940,8 @@ bool Store(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckStore(S, OpPC, Ptr))
return false;
+ if (!Ptr.isRoot())
+ Ptr.initialize();
Ptr.deref<T>() = Value;
return true;
}
@@ -648,6 +952,8 @@ bool StorePop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckStore(S, OpPC, Ptr))
return false;
+ if (!Ptr.isRoot())
+ Ptr.initialize();
Ptr.deref<T>() = Value;
return true;
}
@@ -658,6 +964,8 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckStore(S, OpPC, Ptr))
return false;
+ if (!Ptr.isRoot())
+ Ptr.initialize();
if (auto *FD = Ptr.getField()) {
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
} else {
@@ -672,6 +980,8 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckStore(S, OpPC, Ptr))
return false;
+ if (!Ptr.isRoot())
+ Ptr.initialize();
if (auto *FD = Ptr.getField()) {
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
} else {
@@ -691,6 +1001,9 @@ bool InitPop(InterpState &S, CodePtr OpPC) {
return true;
}
+/// 1) Pops the value from the stack
+/// 2) Peeks a pointer and gets its index \Idx
+/// 3) Sets the value on the pointer, leaving the pointer on the stack.
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>();
@@ -702,6 +1015,7 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
return true;
}
+/// The same as InitElem, but pops the pointer as well.
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>();
@@ -721,23 +1035,25 @@ 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.
+ // A zero offset does not change the pointer.
if (Offset.isZero()) {
- S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr);
+ S.Stk.push<Pointer>(Ptr);
return true;
}
+
+ if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
+ return false;
+
// Arrays of unknown bounds cannot have pointers into them.
if (!CheckArray(S, OpPC, Ptr))
return false;
+ // Get a version of the index comparable to the type.
+ T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
// Compute the largest index into the array.
unsigned MaxIndex = Ptr.getNumElems();
@@ -754,23 +1070,34 @@ template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
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();
+ if constexpr (Add) {
+ // If the new offset would be negative, bail out.
+ if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
+ return InvalidOffset();
+
+ // If the new offset would be out of bounds, bail out.
+ if (Offset.isPositive() && Offset > MaxOffset)
+ return InvalidOffset();
+ } else {
+ // If the new offset would be negative, bail out.
+ if (Offset.isPositive() && Index < Offset)
+ return InvalidOffset();
+
+ // If the new offset would be out of bounds, bail out.
+ if (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);
+ int64_t Result;
+ if constexpr (Add)
+ Result = WideIndex + WideOffset;
+ else
+ Result = WideIndex - WideOffset;
+
S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
return true;
}
@@ -785,6 +1112,23 @@ bool SubOffset(InterpState &S, CodePtr OpPC) {
return OffsetHelper<T, false>(S, OpPC);
}
+/// 1) Pops a Pointer from the stack.
+/// 2) Pops another Pointer from the stack.
+/// 3) Pushes the different of the indices of the two pointers on the stack.
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+inline bool SubPtr(InterpState &S, CodePtr OpPC) {
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+
+ if (!Pointer::hasSameArray(LHS, RHS)) {
+ // TODO: Diagnose.
+ return false;
+ }
+
+ T A = T::from(LHS.getIndex());
+ T B = T::from(RHS.getIndex());
+ return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
+}
//===----------------------------------------------------------------------===//
// Destroy
@@ -840,88 +1184,47 @@ inline bool This(InterpState &S, CodePtr OpPC) {
return true;
}
+inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
+ assert(S.Current->getFunction()->hasRVO());
+ S.Stk.push<Pointer>(S.Current->getRVOPtr());
+ 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 NameL, PrimType NameR>
+inline bool Shr(InterpState &S, CodePtr OpPC) {
+ using LT = typename PrimConv<NameL>::T;
+ using RT = typename PrimConv<NameR>::T;
+ const auto &RHS = S.Stk.pop<RT>();
+ const auto &LHS = S.Stk.pop<LT>();
+ const unsigned Bits = LHS.bitWidth();
-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().CPlusPlus20) {
- // 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 (!CheckShift<RT>(S, OpPC, RHS, Bits))
+ return false;
- 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()));
- }
+ unsigned URHS = static_cast<unsigned>(RHS);
+ S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.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>();
+template <PrimType NameL, PrimType NameR>
+inline bool Shl(InterpState &S, CodePtr OpPC) {
+ using LT = typename PrimConv<NameL>::T;
+ using RT = typename PrimConv<NameR>::T;
+ const auto &RHS = S.Stk.pop<RT>();
+ const auto &LHS = S.Stk.pop<LT>();
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));
- }
-}
+ if (!CheckShift<RT>(S, OpPC, RHS, Bits))
+ return false;
-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();
+ unsigned URHS = static_cast<unsigned>(RHS);
+ S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, 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));
- }
+ return true;
}
//===----------------------------------------------------------------------===//
@@ -950,26 +1253,56 @@ inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
return true;
}
+inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
+ auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
+ Pointer ThisPtr;
+ if (Func->hasThisPointer()) {
+ ThisPtr = NewFrame->getThis();
+ if (!CheckInvoke(S, PC, ThisPtr)) {
+ return false;
+ }
+ }
+
+ if (!CheckCallable(S, PC, Func))
+ return false;
+
+ InterpFrame *FrameBefore = S.Current;
+ S.Current = NewFrame.get();
+
+ APValue CallResult;
+ // Note that we cannot assert(CallResult.hasValue()) here since
+ // Ret() above only sets the APValue if the curent frame doesn't
+ // have a caller set.
+ if (Interpret(S, CallResult)) {
+ NewFrame.release(); // Frame was delete'd already.
+ assert(S.Current == FrameBefore);
+
+ // For constructors, check that all fields have been initialized.
+ if (Func->isConstructor() && !CheckCtorCall(S, PC, ThisPtr))
+ return false;
+
+ return true;
+ }
+
+ // Interpreting the function failed somehow. Reset to
+ // previous state.
+ S.Current = FrameBefore;
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
-template <typename T>
-inline std::enable_if_t<!std::is_pointer<T>::value, T> ReadArg(InterpState &S,
- CodePtr OpPC) {
- return OpPC.read<T>();
-}
-
-template <typename T>
-inline std::enable_if_t<std::is_pointer<T>::value, T> ReadArg(InterpState &S,
- CodePtr OpPC) {
- uint32_t ID = OpPC.read<uint32_t>();
- return reinterpret_cast<T>(S.P.getNativePointer(ID));
+template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
+ if constexpr (std::is_pointer<T>::value) {
+ uint32_t ID = OpPC.read<uint32_t>();
+ return reinterpret_cast<T>(S.P.getNativePointer(ID));
+ } else {
+ return OpPC.read<T>();
+ }
}
-/// Interpreter entry point.
-bool Interpret(InterpState &S, APValue &Result);
-
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h
index 2d5386e60b8c..f790c50a9123 100644
--- a/clang/lib/AST/Interp/InterpBlock.h
+++ b/clang/lib/AST/Interp/InterpBlock.h
@@ -31,11 +31,25 @@ 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 {
+/// The storage described by the block is immediately followed by
+/// optional metadata, which is followed by the actual data.
+///
+/// Block* rawData() data()
+/// │ │ │
+/// │ │ │
+/// ▼ ▼ ▼
+/// ┌───────────────┬─────────────────────────┬─────────────────┐
+/// │ Block │ Metadata │ Data │
+/// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │
+/// └───────────────┴─────────────────────────┴─────────────────┘
+///
+/// Desc->getAllocSize() describes the size after the Block, i.e.
+/// the data size and the metadata size.
+///
+class Block final {
public:
// Creates a new block.
- Block(const llvm::Optional<unsigned> &DeclID, Descriptor *Desc,
+ Block(const std::optional<unsigned> &DeclID, Descriptor *Desc,
bool IsStatic = false, bool IsExtern = false)
: DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
@@ -56,10 +70,27 @@ public:
/// Returns the size of the block.
InterpSize getSize() const { return Desc->getAllocSize(); }
/// Returns the declaration ID.
- llvm::Optional<unsigned> getDeclID() const { return DeclID; }
+ std::optional<unsigned> getDeclID() const { return DeclID; }
/// Returns a pointer to the stored data.
- char *data() { return reinterpret_cast<char *>(this + 1); }
+ /// You are allowed to read Desc->getSize() bytes from this address.
+ char *data() {
+ // rawData might contain metadata as well.
+ size_t DataOffset = Desc->getMetadataSize();
+ return rawData() + DataOffset;
+ }
+ const char *data() const {
+ // rawData might contain metadata as well.
+ size_t DataOffset = Desc->getMetadataSize();
+ return rawData() + DataOffset;
+ }
+
+ /// Returns a pointer to the raw data, including metadata.
+ /// You are allowed to read Desc->getAllocSize() bytes from this address.
+ char *rawData() { return reinterpret_cast<char *>(this) + sizeof(Block); }
+ const char *rawData() const {
+ return reinterpret_cast<const char *>(this) + sizeof(Block);
+ }
/// Returns a view over the data.
template <typename T>
@@ -67,12 +98,18 @@ public:
/// Invokes the constructor.
void invokeCtor() {
- std::memset(data(), 0, getSize());
+ std::memset(rawData(), 0, Desc->getAllocSize());
if (Desc->CtorFn)
Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
/*isActive=*/true, Desc);
}
+ // Invokes the Destructor.
+ void invokeDtor() {
+ if (Desc->DtorFn)
+ Desc->DtorFn(this, data(), Desc);
+ }
+
protected:
friend class Pointer;
friend class DeadBlock;
@@ -92,7 +129,7 @@ protected:
/// Start of the chain of pointers.
Pointer *Pointers = nullptr;
/// Unique identifier of the declaration.
- llvm::Optional<unsigned> DeclID;
+ std::optional<unsigned> DeclID;
/// Flag indicating if the block has static storage duration.
bool IsStatic = false;
/// Flag indicating if the block is an extern.
@@ -107,7 +144,7 @@ protected:
///
/// Dead blocks are chained in a double-linked list to deallocate them
/// whenever pointers become dead.
-class DeadBlock {
+class DeadBlock final {
public:
/// Copies the block.
DeadBlock(DeadBlock *&Root, Block *Blk);
diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp
index 9d01bf0333fe..40644c538c6a 100644
--- a/clang/lib/AST/Interp/InterpFrame.cpp
+++ b/clang/lib/AST/Interp/InterpFrame.cpp
@@ -7,37 +7,68 @@
//===----------------------------------------------------------------------===//
#include "InterpFrame.h"
+#include "Boolean.h"
#include "Function.h"
-#include "Interp.h"
#include "InterpStack.h"
+#include "InterpState.h"
+#include "Pointer.h"
#include "PrimType.h"
#include "Program.h"
+#include "clang/AST/ASTContext.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),
+InterpFrame::InterpFrame(InterpState &S, const Function *Func,
+ InterpFrame *Caller, CodePtr RetPC)
+ : Caller(Caller), S(S), Func(Func), 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();
- }
- }
+ if (!Func)
+ return;
+
+ unsigned FrameSize = Func->getFrameSize();
+ if (FrameSize == 0)
+ return;
+
+ 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();
+ InlineDescriptor *ID = localInlineDesc(Local.Offset);
+ ID->Desc = Local.Desc;
+ ID->IsActive = true;
+ ID->Offset = sizeof(InlineDescriptor);
+ ID->IsBase = false;
+ ID->IsFieldMutable = false;
+ ID->IsConst = false;
+ ID->IsInitialized = false;
}
}
}
+InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC)
+ : InterpFrame(S, Func, S.Current, RetPC) {
+ // As per our calling convention, the this pointer is
+ // part of the ArgSize.
+ // If the function has RVO, the RVO pointer is first.
+ // If the fuction has a This pointer, that one is next.
+ // Then follow the actual arguments (but those are handled
+ // in getParamPointer()).
+ if (Func->hasRVO())
+ RVOPtr = stackRef<Pointer>(0);
+
+ if (Func->hasThisPointer()) {
+ if (Func->hasRVO())
+ This = stackRef<Pointer>(sizeof(Pointer));
+ else
+ This = stackRef<Pointer>(0);
+ }
+}
+
InterpFrame::~InterpFrame() {
- if (Func && Func->isConstructor() && This.isBaseClass())
- This.initialize();
for (auto &Param : Params)
S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
}
@@ -95,17 +126,17 @@ void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
}
printDesc(P.getDeclDesc());
- for (auto It = Levels.rbegin(); It != Levels.rend(); ++It) {
- if (It->inArray()) {
- OS << "[" << It->expand().getIndex() << "]";
+ for (const auto &It : Levels) {
+ if (It.inArray()) {
+ OS << "[" << It.expand().getIndex() << "]";
continue;
}
- if (auto Index = It->getIndex()) {
+ if (auto Index = It.getIndex()) {
OS << " + " << Index;
continue;
}
OS << ".";
- printDesc(It->getFieldDesc());
+ printDesc(It.getFieldDesc());
}
}
@@ -117,16 +148,15 @@ void InterpFrame::describe(llvm::raw_ostream &OS) {
OS << "->";
}
OS << *F << "(";
- unsigned Off = Func->hasRVO() ? primSize(PT_Ptr) : 0;
+ unsigned Off = 0;
+
+ Off += Func->hasRVO() ? primSize(PT_Ptr) : 0;
+ Off += Func->hasThisPointer() ? 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;
- }
+ PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr);
TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
Off += align(primSize(PrimTy));
@@ -152,10 +182,10 @@ const FunctionDecl *InterpFrame::getCallee() const {
return Func->getDecl();
}
-Pointer InterpFrame::getLocalPointer(unsigned Offset) {
+Pointer InterpFrame::getLocalPointer(unsigned Offset) const {
assert(Offset < Func->getFrameSize() && "Invalid local offset.");
- return Pointer(
- reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block)));
+ return Pointer(reinterpret_cast<Block *>(localBlock(Offset)),
+ sizeof(InlineDescriptor));
}
Pointer InterpFrame::getParamPointer(unsigned Off) {
diff --git a/clang/lib/AST/Interp/InterpFrame.h b/clang/lib/AST/Interp/InterpFrame.h
index 304e2ad66537..bfa02c90ebec 100644
--- a/clang/lib/AST/Interp/InterpFrame.h
+++ b/clang/lib/AST/Interp/InterpFrame.h
@@ -14,7 +14,6 @@
#define LLVM_CLANG_AST_INTERP_INTERPFRAME_H
#include "Frame.h"
-#include "Pointer.h"
#include "Program.h"
#include "State.h"
#include <cstdint>
@@ -24,6 +23,7 @@ namespace clang {
namespace interp {
class Function;
class InterpState;
+class Pointer;
/// Frame storing local variables.
class InterpFrame final : public Frame {
@@ -32,8 +32,14 @@ public:
InterpFrame *Caller;
/// Creates a new frame for a method call.
- InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
- CodePtr RetPC, Pointer &&This);
+ InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller,
+ CodePtr RetPC);
+
+ /// Creates a new frame with the values that make sense.
+ /// I.e., the caller is the current frame of S,
+ /// the This() pointer is the current Pointer on the top of S's stack,
+ /// and the RVO pointer is before that.
+ InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC);
/// Destroys the frame, killing all live pointers to stack slots.
~InterpFrame();
@@ -57,26 +63,27 @@ public:
const FunctionDecl *getCallee() const override;
/// Returns the current function.
- Function *getFunction() const { return Func; }
+ const 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) {
+ template <typename T> const T &getLocal(unsigned Offset) const {
return localRef<T>(Offset);
}
/// Mutates a local variable.
template <typename T> void setLocal(unsigned Offset, const T &Value) {
localRef<T>(Offset) = Value;
+ localInlineDesc(Offset)->IsInitialized = true;
}
/// Returns a pointer to a local variables.
- Pointer getLocalPointer(unsigned Offset);
+ Pointer getLocalPointer(unsigned Offset) const;
/// Returns the value of an argument.
- template <typename T> const T &getParam(unsigned Offset) {
+ template <typename T> const T &getParam(unsigned Offset) const {
auto Pt = Params.find(Offset);
if (Pt == Params.end()) {
return stackRef<T>(Offset);
@@ -96,6 +103,9 @@ public:
/// Returns the 'this' pointer.
const Pointer &getThis() const { return This; }
+ /// Returns the RVO pointer, if the Function has one.
+ const Pointer &getRVOPtr() const { return RVOPtr; }
+
/// Checks if the frame is a root frame - return should quit the interpreter.
bool isRoot() const { return !Func; }
@@ -112,27 +122,35 @@ public:
private:
/// Returns an original argument from the stack.
- template <typename T> const T &stackRef(unsigned Offset) {
+ template <typename T> const T &stackRef(unsigned Offset) const {
+ assert(Args);
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);
+ template <typename T> T &localRef(unsigned Offset) const {
+ return getLocalPointer(Offset).deref<T>();
}
/// Returns a pointer to a local's block.
- void *localBlock(unsigned Offset) {
+ void *localBlock(unsigned Offset) const {
return Locals.get() + Offset - sizeof(Block);
}
+ // Returns the inline descriptor of the local.
+ InlineDescriptor *localInlineDesc(unsigned Offset) const {
+ return reinterpret_cast<InlineDescriptor *>(Locals.get() + Offset);
+ }
+
private:
/// Reference to the interpreter state.
InterpState &S;
/// Reference to the function being executed.
- Function *Func;
+ const Function *Func;
/// Current object pointer for methods.
Pointer This;
+ /// Pointer the non-primitive return value gets constructed in.
+ Pointer RVOPtr;
/// Return address.
CodePtr RetPC;
/// The size of all the arguments.
diff --git a/clang/lib/AST/Interp/InterpStack.cpp b/clang/lib/AST/Interp/InterpStack.cpp
index 5c803f3d9424..7fe678e62192 100644
--- a/clang/lib/AST/Interp/InterpStack.cpp
+++ b/clang/lib/AST/Interp/InterpStack.cpp
@@ -46,7 +46,7 @@ void *InterpStack::grow(size_t Size) {
return Object;
}
-void *InterpStack::peek(size_t Size) {
+void *InterpStack::peek(size_t Size) const {
assert(Chunk && "Stack is empty!");
StackChunk *Ptr = Chunk;
diff --git a/clang/lib/AST/Interp/InterpStack.h b/clang/lib/AST/Interp/InterpStack.h
index b02d3c6a34b0..3adaad96515e 100644
--- a/clang/lib/AST/Interp/InterpStack.h
+++ b/clang/lib/AST/Interp/InterpStack.h
@@ -13,7 +13,9 @@
#ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
+#include "PrimType.h"
#include <memory>
+#include <vector>
namespace clang {
namespace interp {
@@ -29,10 +31,18 @@ public:
/// 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)...);
+#ifndef NDEBUG
+ ItemTypes.push_back(toPrimType<T>());
+#endif
}
/// Returns the value from the top of the stack and removes it.
template <typename T> T pop() {
+#ifndef NDEBUG
+ assert(!ItemTypes.empty());
+ assert(ItemTypes.back() == toPrimType<T>());
+ ItemTypes.pop_back();
+#endif
auto *Ptr = &peek<T>();
auto Value = std::move(*Ptr);
Ptr->~T();
@@ -42,18 +52,22 @@ public:
/// Discards the top value from the stack.
template <typename T> void discard() {
+#ifndef NDEBUG
+ assert(ItemTypes.back() == toPrimType<T>());
+ ItemTypes.pop_back();
+#endif
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() {
+ template <typename T> T &peek() const {
return *reinterpret_cast<T *>(peek(aligned_size<T>()));
}
/// Returns a pointer to the top object.
- void *top() { return Chunk ? peek(0) : nullptr; }
+ void *top() const { return Chunk ? peek(0) : nullptr; }
/// Returns the size of the stack in bytes.
size_t size() const { return StackSize; }
@@ -61,6 +75,9 @@ public:
/// Clears the stack without calling any destructors.
void clear();
+ // Returns whether the stack is empty.
+ bool empty() const { return StackSize == 0; }
+
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.
@@ -72,7 +89,7 @@ private:
/// Grows the stack to accommodate 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);
+ void *peek(size_t Size) const;
/// Shrinks the stack.
void shrink(size_t Size);
@@ -94,10 +111,13 @@ private:
: 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(); }
+ size_t size() const { return End - start(); }
/// Returns a pointer to the start of the data region.
char *start() { return reinterpret_cast<char *>(this + 1); }
+ const char *start() const {
+ return reinterpret_cast<const char *>(this + 1);
+ }
};
static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size");
@@ -105,6 +125,45 @@ private:
StackChunk *Chunk = nullptr;
/// Total size of the stack.
size_t StackSize = 0;
+
+#ifndef NDEBUG
+ /// vector recording the type of data we pushed into the stack.
+ std::vector<PrimType> ItemTypes;
+
+ template <typename T> static constexpr PrimType toPrimType() {
+ if constexpr (std::is_same_v<T, Pointer>)
+ return PT_Ptr;
+ else if constexpr (std::is_same_v<T, bool> ||
+ std::is_same_v<T, Boolean>)
+ return PT_Bool;
+ else if constexpr (std::is_same_v<T, int8_t> ||
+ std::is_same_v<T, Integral<8, true>>)
+ return PT_Sint8;
+ else if constexpr (std::is_same_v<T, uint8_t> ||
+ std::is_same_v<T, Integral<8, false>>)
+ return PT_Uint8;
+ else if constexpr (std::is_same_v<T, int16_t> ||
+ std::is_same_v<T, Integral<16, true>>)
+ return PT_Sint16;
+ else if constexpr (std::is_same_v<T, uint16_t> ||
+ std::is_same_v<T, Integral<16, false>>)
+ return PT_Uint16;
+ else if constexpr (std::is_same_v<T, int32_t> ||
+ std::is_same_v<T, Integral<32, true>>)
+ return PT_Sint32;
+ else if constexpr (std::is_same_v<T, uint32_t> ||
+ std::is_same_v<T, Integral<32, false>>)
+ return PT_Uint32;
+ else if constexpr (std::is_same_v<T, int64_t> ||
+ std::is_same_v<T, Integral<64, true>>)
+ return PT_Sint64;
+ else if constexpr (std::is_same_v<T, uint64_t> ||
+ std::is_same_v<T, Integral<64, false>>)
+ return PT_Uint64;
+
+ llvm_unreachable("unknown type push()'ed into InterpStack");
+ }
+#endif
};
} // namespace interp
diff --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h
index 57e36c4c63ea..033080637385 100644
--- a/clang/lib/AST/Interp/InterpState.h
+++ b/clang/lib/AST/Interp/InterpState.h
@@ -65,6 +65,7 @@ public:
bool noteUndefinedBehavior() override {
return Parent.noteUndefinedBehavior();
}
+ bool inConstantContext() const { return Parent.InConstantContext; }
bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
void setActiveDiagnostic(bool Flag) override {
Parent.setActiveDiagnostic(Flag);
@@ -81,7 +82,7 @@ public:
void deallocate(Block *B);
/// Delegates source mapping to the mapper.
- SourceInfo getSource(Function *F, CodePtr PC) const override {
+ SourceInfo getSource(const Function *F, CodePtr PC) const override {
return M ? M->getSource(F, PC) : F->getSource(PC);
}
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 638d5b3d2357..058475b2d399 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -42,18 +42,8 @@ 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 ArgFunction : ArgType { let Name = "const Function *"; }
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 *"; }
//===----------------------------------------------------------------------===//
@@ -64,15 +54,28 @@ class TypeClass {
list<Type> Types;
}
-def AluTypeClass : TypeClass {
+def NumberTypeClass : TypeClass {
+ let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
+ Uint32, Sint64, Uint64];
+}
+
+def IntegerTypeClass : TypeClass {
let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
- Uint32, Sint64, Uint64, Bool];
+ Uint32, Sint64, Uint64];
+}
+
+def AluTypeClass : TypeClass {
+ let Types = !listconcat(NumberTypeClass.Types, [Bool]);
}
def PtrTypeClass : TypeClass {
let Types = [Ptr];
}
+def BoolTypeClass : TypeClass {
+ let Types = [Bool];
+}
+
def AllTypeClass : TypeClass {
let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types);
}
@@ -105,6 +108,11 @@ class AluOpcode : Opcode {
let HasGroup = 1;
}
+class IntegerOpcode : Opcode {
+ let Types = [IntegerTypeClass];
+ let HasGroup = 1;
+}
+
//===----------------------------------------------------------------------===//
// Jump opcodes
//===----------------------------------------------------------------------===//
@@ -149,6 +157,13 @@ def RetValue : Opcode {
// [] -> EXIT
def NoRet : Opcode {}
+
+def Call : Opcode {
+ let Args = [ArgFunction];
+ let Types = [];
+ let ChangesPC = 1;
+}
+
//===----------------------------------------------------------------------===//
// Frame management
//===----------------------------------------------------------------------===//
@@ -183,6 +198,7 @@ def ConstBool : ConstOpcode<Bool, ArgBool>;
// [] -> [Integer]
def Zero : Opcode {
let Types = [AluTypeClass];
+ let HasGroup = 1;
}
// [] -> [Pointer]
@@ -253,6 +269,9 @@ def GetPtrThisVirtBase : Opcode {
// [] -> [Pointer]
def This : Opcode;
+// [] -> [Pointer]
+def RVOPtr : Opcode;
+
// [Pointer] -> [Pointer]
def NarrowPtr : Opcode;
// [Pointer] -> [Pointer]
@@ -374,6 +393,12 @@ def AddOffset : AluOpcode;
// [Pointer, Integral] -> [Pointer]
def SubOffset : AluOpcode;
+// Pointer, Pointer] - [Integral]
+def SubPtr : Opcode {
+ let Types = [IntegerTypeClass];
+ let HasGroup = 1;
+}
+
//===----------------------------------------------------------------------===//
// Binary operators.
//===----------------------------------------------------------------------===//
@@ -382,6 +407,73 @@ def SubOffset : AluOpcode;
def Sub : AluOpcode;
def Add : AluOpcode;
def Mul : AluOpcode;
+def Rem : Opcode {
+ let Types = [NumberTypeClass];
+ let HasGroup = 1;
+}
+
+def Shl : Opcode {
+ let Types = [IntegerTypeClass, IntegerTypeClass];
+ let HasGroup = 1;
+}
+
+def Shr : Opcode {
+ let Types = [IntegerTypeClass, IntegerTypeClass];
+ let HasGroup = 1;
+}
+
+def BitAnd : IntegerOpcode;
+def BitOr : IntegerOpcode;
+def Div : Opcode {
+ let Types = [NumberTypeClass];
+ let HasGroup = 1;
+}
+def BitXor : IntegerOpcode;
+
+//===----------------------------------------------------------------------===//
+// Unary operators.
+//===----------------------------------------------------------------------===//
+
+// [Real] -> [Real]
+def Inv: Opcode {
+ let Types = [BoolTypeClass];
+ let HasGroup = 1;
+}
+
+def Inc: IntegerOpcode;
+def IncPop : IntegerOpcode;
+def Dec: IntegerOpcode;
+def DecPop: IntegerOpcode;
+
+// [Real] -> [Real]
+def Neg: Opcode {
+ let Types = [AluTypeClass];
+ let HasGroup = 1;
+}
+
+// [Real] -> [Real]
+def Comp: Opcode {
+ let Types = [NumberTypeClass];
+ let HasGroup = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Cast.
+//===----------------------------------------------------------------------===//
+// TODO: Expand this to handle casts between more types.
+
+def FromCastTypeClass : TypeClass {
+ let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+}
+
+def ToCastTypeClass : TypeClass {
+ let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+}
+
+def Cast: Opcode {
+ let Types = [FromCastTypeClass, ToCastTypeClass];
+ let HasGroup = 1;
+}
//===----------------------------------------------------------------------===//
// Comparison opcodes.
diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp
index ef2638e2a36b..fd8c98fae039 100644
--- a/clang/lib/AST/Interp/Pointer.cpp
+++ b/clang/lib/AST/Interp/Pointer.cpp
@@ -16,6 +16,9 @@ using namespace clang::interp;
Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
+Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
+ : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
+
Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
Pointer::Pointer(Pointer &&P)
@@ -106,7 +109,7 @@ APValue Pointer::toAPValue() const {
// Build the path into the object.
Pointer Ptr = *this;
- while (Ptr.isField()) {
+ while (Ptr.isField() || Ptr.isArrayElement()) {
if (Ptr.isArrayElement()) {
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
Ptr = Ptr.getArray();
@@ -129,14 +132,21 @@ APValue Pointer::toAPValue() const {
}
}
+ // We assemble the LValuePath starting from the innermost pointer to the
+ // outermost one. SO in a.b.c, the first element in Path will refer to
+ // the field 'c', while later code expects it to refer to 'a'.
+ // Just invert the order of the elements.
+ std::reverse(Path.begin(), Path.end());
+
return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
}
bool Pointer::isInitialized() const {
assert(Pointee && "Cannot check if null pointer was initialized");
Descriptor *Desc = getFieldDesc();
+ assert(Desc);
if (Desc->isPrimitiveArray()) {
- if (Pointee->IsStatic)
+ if (isStatic() && Base == 0)
return true;
// Primitive array field are stored in a bitset.
InitMap *Map = getInitMap();
@@ -154,8 +164,14 @@ bool Pointer::isInitialized() const {
void Pointer::initialize() const {
assert(Pointee && "Cannot initialize null pointer");
Descriptor *Desc = getFieldDesc();
- if (Desc->isPrimitiveArray()) {
- if (!Pointee->IsStatic) {
+
+ assert(Desc);
+ if (Desc->isArray()) {
+ if (Desc->isPrimitiveArray()) {
+ // Primitive global arrays don't have an initmap.
+ if (isStatic() && Base == 0)
+ return;
+
// Primitive array initializer.
InitMap *&Map = getInitMap();
if (Map == (InitMap *)-1)
@@ -189,5 +205,5 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
}
bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
- return A.Base == B.Base && A.getFieldDesc()->IsArray;
+ return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
}
diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index 587531aec82a..1462d01c2412 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -33,14 +33,40 @@ enum PrimType : unsigned;
///
/// 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.
+///
+/// In the simplest form, a Pointer has a Block* (the pointee) and both Base
+/// and Offset are 0, which means it will point to raw data.
+///
+/// The Base field is used to access metadata about the data. For primitive
+/// arrays, the Base is followed by an InitMap. In a variety of cases, the
+/// Base is preceded by an InlineDescriptor, which is used to track the
+/// initialization state, among other things.
+///
+/// The Offset field is used to access the actual data. In other words, the
+/// data the pointer decribes can be found at
+/// Pointee->rawData() + Pointer.Offset.
+///
+///
+/// Pointee Offset
+/// │ │
+/// │ │
+/// ▼ ▼
+/// ┌───────┬────────────┬─────────┬────────────────────────────┐
+/// │ Block │ InlineDesc │ InitMap │ Actual Data │
+/// └───────┴────────────┴─────────┴────────────────────────────┘
+/// ▲
+/// │
+/// │
+/// Base
class Pointer {
private:
- static constexpr unsigned PastEndMark = (unsigned)-1;
- static constexpr unsigned RootPtrMark = (unsigned)-1;
+ static constexpr unsigned PastEndMark = ~0u;
+ static constexpr unsigned RootPtrMark = ~0u;
public:
Pointer() {}
Pointer(Block *B);
+ Pointer(Block *B, unsigned BaseAndOffset);
Pointer(const Pointer &P);
Pointer(Pointer &&P);
~Pointer();
@@ -216,6 +242,8 @@ public:
/// Returns the record descriptor of a class.
Record *getRecord() const { return getFieldDesc()->ElemRecord; }
+ // Returns the element record type, if this is a non-primive array.
+ Record *getElemRecord() const { return getFieldDesc()->ElemDesc->ElemRecord; }
/// Returns the field information.
const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
@@ -232,7 +260,9 @@ public:
bool isStaticTemporary() const { return isStatic() && isTemporary(); }
/// Checks if the field is mutable.
- bool isMutable() const { return Base != 0 && getInlineDesc()->IsMutable; }
+ bool isMutable() const {
+ return Base != 0 && getInlineDesc()->IsFieldMutable;
+ }
/// Checks if an object was initialized.
bool isInitialized() const;
/// Checks if the object is active.
@@ -246,7 +276,7 @@ public:
}
/// Returns the declaration ID.
- llvm::Optional<unsigned> getDeclID() const { return Pointee->getDeclID(); }
+ std::optional<unsigned> getDeclID() const { return Pointee->getDeclID(); }
/// Returns the byte offset from the start.
unsigned getByteOffset() const {
@@ -276,12 +306,12 @@ public:
/// Dereferences the pointer, if it's live.
template <typename T> T &deref() const {
assert(isLive() && "Invalid pointer");
- return *reinterpret_cast<T *>(Pointee->data() + Offset);
+ return *reinterpret_cast<T *>(Pointee->rawData() + Offset);
}
/// Dereferences a primitive element.
template <typename T> T &elem(unsigned I) const {
- return reinterpret_cast<T *>(Pointee->data())[I];
+ return reinterpret_cast<T *>(Pointee->rawData())[I];
}
/// Initializes a field.
@@ -298,7 +328,7 @@ public:
/// Prints the pointer.
void print(llvm::raw_ostream &OS) const {
- OS << "{" << Base << ", " << Offset << ", ";
+ OS << Pointee << " {" << Base << ", " << Offset << ", ";
if (Pointee)
OS << Pointee->getSize();
else
@@ -318,12 +348,13 @@ private:
/// 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;
+ return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) -
+ 1;
}
/// Returns a reference to the pointer which stores the initialization map.
InitMap *&getInitMap() const {
- return *reinterpret_cast<InitMap **>(Pointee->data() + Base);
+ return *reinterpret_cast<InitMap **>(Pointee->rawData() + Base);
}
/// The block the pointer is pointing to.
diff --git a/clang/lib/AST/Interp/PrimType.cpp b/clang/lib/AST/Interp/PrimType.cpp
index 082bfaf3c207..eda90e1c36c2 100644
--- a/clang/lib/AST/Interp/PrimType.cpp
+++ b/clang/lib/AST/Interp/PrimType.cpp
@@ -1,4 +1,4 @@
-//===--- Type.cpp - Types for the constexpr VM ------------------*- C++ -*-===//
+//===--- PrimType.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.
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "PrimType.h"
+#include "Boolean.h"
+#include "Pointer.h"
using namespace clang;
using namespace clang::interp;
diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h
index de4bf9bf802e..c8f2a600fb3c 100644
--- a/clang/lib/AST/Interp/PrimType.h
+++ b/clang/lib/AST/Interp/PrimType.h
@@ -13,16 +13,17 @@
#ifndef LLVM_CLANG_AST_INTERP_TYPE_H
#define LLVM_CLANG_AST_INTERP_TYPE_H
+#include "Integral.h"
#include <climits>
#include <cstddef>
#include <cstdint>
-#include "Boolean.h"
-#include "Integral.h"
-#include "Pointer.h"
namespace clang {
namespace interp {
+class Pointer;
+class Boolean;
+
/// Enumeration of the primitive types of the VM.
enum PrimType : unsigned {
PT_Sint8,
@@ -58,6 +59,13 @@ constexpr size_t align(size_t Size) {
return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *);
}
+constexpr bool aligned(uintptr_t Value) { return Value == align(Value); }
+static_assert(aligned(sizeof(void *)));
+
+static inline bool aligned(const void *P) {
+ return aligned(reinterpret_cast<uintptr_t>(P));
+}
+
inline bool isPrimitiveIntegral(PrimType Type) {
switch (Type) {
case PT_Bool:
diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp
index e310c9678140..5305ddd8de18 100644
--- a/clang/lib/AST/Interp/Program.cpp
+++ b/clang/lib/AST/Interp/Program.cpp
@@ -53,10 +53,11 @@ unsigned Program::createGlobalString(const StringLiteral *S) {
}
// Create a descriptor for the string.
- Descriptor *Desc = allocateDescriptor(S, CharType, S->getLength() + 1,
- /*isConst=*/true,
- /*isTemporary=*/false,
- /*isMutable=*/false);
+ Descriptor *Desc =
+ allocateDescriptor(S, CharType, std::nullopt, S->getLength() + 1,
+ /*isConst=*/true,
+ /*isTemporary=*/false,
+ /*isMutable=*/false);
// Allocate storage for the string.
// The byte length does not include the null terminator.
@@ -64,6 +65,7 @@ unsigned Program::createGlobalString(const StringLiteral *S) {
unsigned Sz = Desc->getAllocSize();
auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
/*isExtern=*/false);
+ G->block()->invokeCtor();
Globals.push_back(G);
// Construct the string in storage.
@@ -99,13 +101,13 @@ Pointer Program::getPtrGlobal(unsigned Idx) {
return Pointer(Globals[Idx]->block());
}
-llvm::Optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
+std::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 already evaluated.
- llvm::Optional<unsigned> Index;
+ std::optional<unsigned> Index;
for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
auto It = GlobalIndices.find(P);
if (It != GlobalIndices.end()) {
@@ -123,18 +125,19 @@ llvm::Optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
return Index;
}
-llvm::Optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD) {
+std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
+ const Expr *Init) {
if (auto Idx = getGlobal(VD))
return Idx;
- if (auto Idx = createGlobal(VD)) {
+ if (auto Idx = createGlobal(VD, Init)) {
GlobalIndices[VD] = *Idx;
return Idx;
}
return {};
}
-llvm::Optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
+std::optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
auto &ASTCtx = Ctx.getASTContext();
// Create a pointer to an incomplete array of the specified elements.
@@ -153,7 +156,9 @@ llvm::Optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
return {};
}
-llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
+std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
+ const Expr *Init) {
+ assert(!getGlobal(VD));
bool IsStatic, IsExtern;
if (auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = !Var->hasLocalStorage();
@@ -162,7 +167,7 @@ llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
IsStatic = false;
IsExtern = true;
}
- if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern)) {
+ if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) {
for (const Decl *P = VD; P; P = P->getPreviousDecl())
GlobalIndices[P] = *Idx;
return *Idx;
@@ -170,20 +175,22 @@ llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
return {};
}
-llvm::Optional<unsigned> Program::createGlobal(const Expr *E) {
+std::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) {
+std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern,
+ const Expr *Init) {
// 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);
+ Desc = createDescriptor(D, *T, std::nullopt, IsConst, IsTemporary);
} else {
- Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary);
+ Desc = createDescriptor(D, Ty.getTypePtr(), std::nullopt, IsConst,
+ IsTemporary);
}
if (!Desc)
return {};
@@ -201,24 +208,12 @@ llvm::Optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
}
Function *Program::getFunction(const FunctionDecl *F) {
- F = F->getDefinition();
+ F = F->getCanonicalDecl();
+ assert(F);
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();
@@ -231,8 +226,13 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
return It->second;
}
+ // We insert nullptr now and replace that later, so recursive calls
+ // to this function with the same RecordDecl don't run into
+ // infinite recursion.
+ Records.insert({RD, nullptr});
+
// Number of bytes required by fields and base classes.
- unsigned Size = 0;
+ unsigned BaseSize = 0;
// Number of bytes required by virtual base.
unsigned VirtSize = 0;
@@ -240,7 +240,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
if (!BR)
return nullptr;
- return allocateDescriptor(BD, BR, /*isConst=*/false,
+ return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false,
/*isTemporary=*/false,
/*isMutable=*/false);
};
@@ -256,9 +256,9 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
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());
+ BaseSize += align(sizeof(InlineDescriptor));
+ Bases.push_back({BD, BaseSize, Desc, BR});
+ BaseSize += align(BR->getSize());
continue;
}
return nullptr;
@@ -282,39 +282,41 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
Record::FieldList Fields;
for (const FieldDecl *FD : RD->fields()) {
// Reserve space for the field's descriptor and the offset.
- Size += align(sizeof(InlineDescriptor));
+ BaseSize += 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);
+ if (std::optional<PrimType> T = Ctx.classify(FT)) {
+ Desc = createDescriptor(FD, *T, std::nullopt, IsConst,
+ /*isTemporary=*/false, IsMutable);
} else {
- Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
+ Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,
/*isTemporary=*/false, IsMutable);
}
if (!Desc)
return nullptr;
- Fields.push_back({FD, Size, Desc});
- Size += align(Desc->getAllocSize());
+ Fields.push_back({FD, BaseSize, Desc});
+ BaseSize += align(Desc->getAllocSize());
}
Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
- std::move(VirtBases), VirtSize, Size);
- Records.insert({RD, R});
+ std::move(VirtBases), VirtSize, BaseSize);
+ Records[RD] = R;
return R;
}
Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
+ Descriptor::MetadataSize MDSize,
bool IsConst, bool IsTemporary,
- bool IsMutable) {
+ bool IsMutable, const Expr *Init) {
// Classes and structures.
if (auto *RT = Ty->getAs<RecordType>()) {
if (auto *Record = getOrCreateRecord(RT->getDecl()))
- return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable);
+ return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
+ IsMutable);
}
// Arrays.
@@ -323,38 +325,39 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
// 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)) {
+ if (std::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,
+ return allocateDescriptor(D, *T, MDSize, 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)
+ Descriptor *ElemDesc = createDescriptor(
+ D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
+ if (!ElemDesc)
return nullptr;
- InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
+ InterpSize ElemSize =
+ ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
return {};
- return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
- IsMutable);
+ return allocateDescriptor(D, ElemDesc, MDSize, 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)) {
+ if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
return allocateDescriptor(D, *T, IsTemporary,
Descriptor::UnknownSize{});
} else {
- Descriptor *Desc =
- createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
+ Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), MDSize,
+ IsConst, IsTemporary);
if (!Desc)
return nullptr;
return allocateDescriptor(D, Desc, IsTemporary,
@@ -366,13 +369,15 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
// Atomic types.
if (auto *AT = Ty->getAs<AtomicType>()) {
const Type *InnerTy = AT->getValueType().getTypePtr();
- return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
+ return createDescriptor(D, InnerTy, MDSize, 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 allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary,
+ IsMutable);
}
return nullptr;
diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h
index ca985af8ad30..5a80dd1ed748 100644
--- a/clang/lib/AST/Interp/Program.h
+++ b/clang/lib/AST/Interp/Program.h
@@ -37,10 +37,26 @@ class Context;
class Record;
/// The program contains and links the bytecode for all functions.
-class Program {
+class Program final {
public:
Program(Context &Ctx) : Ctx(Ctx) {}
+ ~Program() {
+ // Manually destroy all the blocks. They are almost all harmless,
+ // but primitive arrays might have an InitMap* heap allocated and
+ // that needs to be freed.
+ for (Global *G : Globals)
+ G->block()->invokeDtor();
+
+ // Records might actually allocate memory themselves, but they
+ // are allocated using a BumpPtrAllocator. Call their desctructors
+ // here manually so they are properly freeing their resources.
+ for (auto RecordPair : Records) {
+ if (Record *R = RecordPair.second)
+ R->~Record();
+ }
+ }
+
/// Marshals a native pointer to an ID for embedding in bytecode.
unsigned getOrCreateNativePointer(const void *Ptr);
@@ -60,23 +76,25 @@ public:
}
/// Finds a global's index.
- llvm::Optional<unsigned> getGlobal(const ValueDecl *VD);
+ std::optional<unsigned> getGlobal(const ValueDecl *VD);
/// Returns or creates a global an creates an index to it.
- llvm::Optional<unsigned> getOrCreateGlobal(const ValueDecl *VD);
+ std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
+ const Expr *Init = nullptr);
/// Returns or creates a dummy value for parameters.
- llvm::Optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
+ std::optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
/// Creates a global and returns its index.
- llvm::Optional<unsigned> createGlobal(const ValueDecl *VD);
+ std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *E);
/// Creates a global from a lifetime-extended temporary.
- llvm::Optional<unsigned> createGlobal(const Expr *E);
+ std::optional<unsigned> createGlobal(const Expr *E);
/// Creates a new function from a code range.
template <typename... Ts>
Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
+ Def = Def->getCanonicalDecl();
auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
Funcs.insert({Def, std::unique_ptr<Function>(Func)});
return Func;
@@ -92,26 +110,23 @@ public:
/// 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,
+ Descriptor::MetadataSize MDSize = std::nullopt,
+ bool IsConst = false, bool IsTemporary = false,
bool IsMutable = false) {
- return allocateDescriptor(D, Type, IsConst, IsTemporary, IsMutable);
+ return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
}
/// Creates a descriptor for a composite type.
Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
+ Descriptor::MetadataSize MDSize = std::nullopt,
bool IsConst = false, bool IsTemporary = false,
- bool IsMutable = false);
+ bool IsMutable = false,
+ const Expr *Init = nullptr);
/// Context to manage declaration lifetimes.
class DeclScope {
@@ -124,17 +139,18 @@ public:
};
/// Returns the current declaration ID.
- llvm::Optional<unsigned> getCurrentDecl() const {
+ std::optional<unsigned> getCurrentDecl() const {
if (CurrentDeclaration == NoDeclaration)
- return llvm::Optional<unsigned>{};
+ return std::optional<unsigned>{};
return LastDeclaration;
}
private:
friend class DeclScope;
- llvm::Optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
- bool IsStatic, bool IsExtern);
+ std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern,
+ const Expr *Init = nullptr);
/// Reference to the VM context.
Context &Ctx;
diff --git a/clang/lib/AST/Interp/Record.h b/clang/lib/AST/Interp/Record.h
index 9cdee9003752..1742cb1cc4ee 100644
--- a/clang/lib/AST/Interp/Record.h
+++ b/clang/lib/AST/Interp/Record.h
@@ -13,14 +13,16 @@
#ifndef LLVM_CLANG_AST_INTERP_RECORD_H
#define LLVM_CLANG_AST_INTERP_RECORD_H
-#include "Pointer.h"
+#include "Descriptor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
namespace clang {
namespace interp {
class Program;
/// Structure/Class descriptor.
-class Record {
+class Record final {
public:
/// Describes a record field.
struct Field {
@@ -47,6 +49,8 @@ public:
public:
/// Returns the underlying declaration.
const RecordDecl *getDecl() const { return Decl; }
+ /// Returns the name of the underlying declaration.
+ const std::string getName() const { return Decl->getNameAsString(); }
/// Checks if the record is a union.
bool isUnion() const { return getDecl()->isUnion(); }
/// Returns the size of the record.
@@ -59,13 +63,20 @@ public:
const Base *getBase(const RecordDecl *FD) const;
/// Returns a virtual base descriptor.
const Base *getVirtualBase(const RecordDecl *RD) const;
+ // Returns the destructor of the record, if any.
+ const CXXDestructorDecl *getDestructor() const {
+ if (const auto *CXXDecl = dyn_cast<CXXRecordDecl>(Decl))
+ return CXXDecl->getDestructor();
+ return nullptr;
+ }
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(); }
+ unsigned getNumFields() const { return Fields.size(); }
+ const Field *getField(unsigned I) const { return &Fields[I]; }
Field *getField(unsigned I) { return &Fields[I]; }
using const_base_iter = BaseList::const_iterator;
@@ -73,7 +84,7 @@ public:
return llvm::make_range(Bases.begin(), Bases.end());
}
- unsigned getNumBases() { return Bases.size(); }
+ unsigned getNumBases() const { return Bases.size(); }
Base *getBase(unsigned I) { return &Bases[I]; }
using const_virtual_iter = VirtualBaseList::const_iterator;
@@ -81,7 +92,7 @@ public:
return llvm::make_range(VirtualBases.begin(), VirtualBases.end());
}
- unsigned getNumVirtualBases() { return VirtualBases.size(); }
+ unsigned getNumVirtualBases() const { return VirtualBases.size(); }
Base *getVirtualBase(unsigned I) { return &VirtualBases[I]; }
private:
@@ -108,7 +119,6 @@ private:
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.
diff --git a/clang/lib/AST/Interp/Source.cpp b/clang/lib/AST/Interp/Source.cpp
index 4bec87812638..467cde116843 100644
--- a/clang/lib/AST/Interp/Source.cpp
+++ b/clang/lib/AST/Interp/Source.cpp
@@ -28,12 +28,12 @@ const Expr *SourceInfo::asExpr() const {
return nullptr;
}
-const Expr *SourceMapper::getExpr(Function *F, CodePtr PC) const {
+const Expr *SourceMapper::getExpr(const 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 {
+SourceLocation SourceMapper::getLocation(const Function *F, CodePtr PC) const {
return getSource(F, PC).getLoc();
}
diff --git a/clang/lib/AST/Interp/Source.h b/clang/lib/AST/Interp/Source.h
index 6acaf406b47a..99ffce34c12f 100644
--- a/clang/lib/AST/Interp/Source.h
+++ b/clang/lib/AST/Interp/Source.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_INTERP_SOURCE_H
#define LLVM_CLANG_AST_INTERP_SOURCE_H
+#include "PrimType.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "llvm/Support/Endian.h"
@@ -22,7 +23,7 @@ namespace interp {
class Function;
/// Pointer into the code segment.
-class CodePtr {
+class CodePtr final {
public:
CodePtr() : Ptr(nullptr) {}
@@ -43,11 +44,14 @@ public:
bool operator!=(const CodePtr &RHS) const { return Ptr != RHS.Ptr; }
+ operator bool() const { return Ptr; }
+
/// Reads data and advances the pointer.
template <typename T> std::enable_if_t<!std::is_pointer<T>::value, T> read() {
+ assert(aligned(Ptr));
using namespace llvm::support;
T Value = endian::read<T, endianness::native, 1>(Ptr);
- Ptr += sizeof(T);
+ Ptr += align(sizeof(T));
return Value;
}
@@ -63,7 +67,7 @@ private:
};
/// Describes the statement/declaration an opcode was generated from.
-class SourceInfo {
+class SourceInfo final {
public:
SourceInfo() {}
SourceInfo(const Stmt *E) : Source(E) {}
@@ -89,12 +93,12 @@ public:
virtual ~SourceMapper() {}
/// Returns source information for a given PC in a function.
- virtual SourceInfo getSource(Function *F, CodePtr PC) const = 0;
+ virtual SourceInfo getSource(const 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;
+ const Expr *getExpr(const Function *F, CodePtr PC) const;
/// Returns the location from which an opcode originates.
- SourceLocation getLocation(Function *F, CodePtr PC) const;
+ SourceLocation getLocation(const Function *F, CodePtr PC) const;
};
} // namespace interp
diff --git a/clang/lib/AST/Interp/State.h b/clang/lib/AST/Interp/State.h
index d9a645a3eb3e..131fbcf3cffc 100644
--- a/clang/lib/AST/Interp/State.h
+++ b/clang/lib/AST/Interp/State.h
@@ -71,6 +71,7 @@ public:
virtual unsigned getCallStackDepth() = 0;
public:
+ State() : InConstantContext(false) {}
// Diagnose that the evaluation could not be folded (FF => FoldFailure)
OptionalDiagnostic
FFDiag(SourceLocation Loc,
@@ -118,6 +119,10 @@ public:
const LangOptions &getLangOpts() const;
+ /// Whether or not we're in a context where the front end requires a
+ /// constant value.
+ bool InConstantContext;
+
private:
void addCallStack(unsigned Limit);
diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp
index e99c21dcff73..c9aadce73141 100644
--- a/clang/lib/AST/ItaniumCXXABI.cpp
+++ b/clang/lib/AST/ItaniumCXXABI.cpp
@@ -26,6 +26,7 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/iterator.h"
+#include <optional>
using namespace clang;
@@ -84,8 +85,8 @@ template<typename T> bool isDenseMapKeyTombstone(T V) {
V, llvm::DenseMapInfo<T>::getTombstoneKey());
}
-template<typename T>
-Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
+template <typename T>
+std::optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
bool LHSEmpty = isDenseMapKeyEmpty(LHS);
bool RHSEmpty = isDenseMapKeyEmpty(RHS);
if (LHSEmpty || RHSEmpty)
@@ -96,7 +97,7 @@ Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
if (LHSTombstone || RHSTombstone)
return LHSTombstone && RHSTombstone;
- return None;
+ return std::nullopt;
}
template<>
@@ -113,8 +114,8 @@ struct DenseMapInfo<DecompositionDeclName> {
return llvm::hash_combine_range(Key.begin(), Key.end());
}
static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {
- if (Optional<bool> Result = areDenseMapKeysEqualSpecialValues(
- LHS.Bindings, RHS.Bindings))
+ if (std::optional<bool> Result =
+ areDenseMapKeysEqualSpecialValues(LHS.Bindings, RHS.Bindings))
return *Result;
return LHS.Bindings.size() == RHS.Bindings.size() &&
@@ -224,7 +225,7 @@ public:
MemberPointerInfo
getMemberPointerInfo(const MemberPointerType *MPT) const override {
const TargetInfo &Target = Context.getTargetInfo();
- TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
+ TargetInfo::IntType PtrDiff = Target.getPtrDiffType(LangAS::Default);
MemberPointerInfo MPI;
MPI.Width = Target.getTypeWidth(PtrDiff);
MPI.Align = Target.getTypeAlign(PtrDiff);
@@ -251,8 +252,8 @@ public:
return false;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- CharUnits PointerSize =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits PointerSize = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerWidth(LangAS::Default));
return Layout.getNonVirtualSize() == PointerSize;
}
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 91f41778ee68..b23bc5f8d881 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -35,6 +35,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
@@ -118,9 +119,9 @@ public:
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &Out) override;
- void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ void mangleSEHFilterExpression(GlobalDecl EnclosingDecl,
raw_ostream &Out) override;
- void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+ void mangleSEHFinallyBlock(GlobalDecl EnclosingDecl,
raw_ostream &Out) override;
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
void mangleItaniumThreadLocalWrapper(const VarDecl *D,
@@ -484,8 +485,7 @@ private:
const AbiTagList *AdditionalAbiTags);
void mangleModuleName(const NamedDecl *ND);
void mangleTemplateName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
+ ArrayRef<TemplateArgument> Args);
void mangleUnqualifiedName(GlobalDecl GD, const DeclContext *DC,
const AbiTagList *AdditionalAbiTags) {
mangleUnqualifiedName(GD, cast<NamedDecl>(GD.getDecl())->getDeclName(), DC,
@@ -513,8 +513,7 @@ private:
const AbiTagList *AdditionalAbiTags,
bool NoFunction=false);
void mangleNestedName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
+ ArrayRef<TemplateArgument> Args);
void mangleNestedNameWithClosurePrefix(GlobalDecl GD,
const NamedDecl *PrefixND,
const AbiTagList *AdditionalAbiTags);
@@ -578,8 +577,7 @@ private:
void mangleTemplateArgs(TemplateName TN,
const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleTemplateArgs(TemplateName TN, const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
+ void mangleTemplateArgs(TemplateName TN, ArrayRef<TemplateArgument> Args);
void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL);
void mangleTemplateArg(TemplateArgument A, bool NeedExactType);
void mangleTemplateArgExpr(const Expr *E);
@@ -605,9 +603,9 @@ NamespaceDecl *ItaniumMangleContextImpl::getStdNamespace() {
if (!StdNamespace) {
StdNamespace = NamespaceDecl::Create(
getASTContext(), getASTContext().getTranslationUnitDecl(),
- /*Inline*/ false, SourceLocation(), SourceLocation(),
+ /*Inline=*/false, SourceLocation(), SourceLocation(),
&getASTContext().Idents.get("std"),
- /*PrevDecl*/ nullptr);
+ /*PrevDecl=*/nullptr, /*Nested=*/false);
StdNamespace->setImplicit();
}
return StdNamespace;
@@ -1087,15 +1085,14 @@ void CXXNameMangler::mangleModuleNamePrefix(StringRef Name, bool IsPartition) {
}
void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+ ArrayRef<TemplateArgument> Args) {
const DeclContext *DC = Context.getEffectiveDeclContext(TD);
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD, DC, nullptr);
- mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), Args);
} else {
- mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
+ mangleNestedName(TD, Args);
}
}
@@ -1244,8 +1241,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
- TST->getNumArgs());
+ mangleTemplateArgs(TST->getTemplateName(), TST->template_arguments());
addSubstitution(QualType(TST, 0));
}
} else if (const auto *DTST =
@@ -1258,7 +1254,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
+ mangleTemplateArgs(Template, DTST->template_arguments());
addSubstitution(QualType(DTST, 0));
}
} else {
@@ -1558,7 +1554,7 @@ void CXXNameMangler::mangleUnqualifiedName(
// <lambda-sig> ::= <template-param-decl>* <parameter-type>+
// # Parameter types or 'v' for 'void'.
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
- llvm::Optional<unsigned> DeviceNumber =
+ std::optional<unsigned> DeviceNumber =
Context.getDiscriminatorOverride()(Context.getASTContext(), Record);
// If we have a device-number via the discriminator, use that to mangle
@@ -1588,7 +1584,9 @@ void CXXNameMangler::mangleUnqualifiedName(
// Get a unique id for the anonymous struct. If it is not a real output
// ID doesn't matter so use fake one.
- unsigned AnonStructId = NullOut ? 0 : Context.getAnonymousStructId(TD);
+ unsigned AnonStructId =
+ NullOut ? 0
+ : Context.getAnonymousStructId(TD, dyn_cast<FunctionDecl>(DC));
// Mangle it as a source name in the form
// [n] $_<id>
@@ -1659,7 +1657,7 @@ void CXXNameMangler::mangleUnqualifiedName(
if (!MD->isStatic())
Arity++;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXLiteralOperatorName:
mangleOperatorName(Name, Arity);
@@ -1730,14 +1728,13 @@ void CXXNameMangler::mangleNestedName(GlobalDecl GD,
Out << 'E';
}
void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+ ArrayRef<TemplateArgument> Args) {
// <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
Out << 'N';
mangleTemplatePrefix(TD);
- mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), Args);
Out << 'E';
}
@@ -2006,7 +2003,7 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// if the host-side CXX ABI has different numbering for lambda. In such case,
// if the mangle context is that device-side one, use the device-side lambda
// mangling number for this lambda.
- llvm::Optional<unsigned> DeviceNumber =
+ std::optional<unsigned> DeviceNumber =
Context.getDiscriminatorOverride()(Context.getASTContext(), Lambda);
unsigned Number =
DeviceNumber ? *DeviceNumber : Lambda->getLambdaManglingNumber();
@@ -2416,7 +2413,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
// conversions to the corresponding template parameter.
// FIXME: Other compilers mangle partially-resolved template arguments in
// unresolved-qualifier-levels.
- mangleTemplateArgs(TemplateName(), TST->getArgs(), TST->getNumArgs());
+ mangleTemplateArgs(TemplateName(), TST->template_arguments());
break;
}
@@ -2435,7 +2432,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
TemplateName Template = getASTContext().getDependentTemplateName(
DTST->getQualifier(), DTST->getIdentifier());
mangleSourceName(DTST->getIdentifier());
- mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
+ mangleTemplateArgs(Template, DTST->template_arguments());
break;
}
@@ -3874,7 +3871,7 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
- mangleTemplateName(TD, T->getArgs(), T->getNumArgs());
+ mangleTemplateName(TD, T->template_arguments());
} else {
if (mangleSubstitution(QualType(T, 0)))
return;
@@ -3884,7 +3881,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(T->getTemplateName(), T->template_arguments());
addSubstitution(QualType(T, 0));
}
}
@@ -3936,7 +3933,7 @@ void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(Prefix, T->template_arguments());
Out << 'E';
}
@@ -3980,16 +3977,22 @@ void CXXNameMangler::mangleType(const UnaryTransformType *T) {
// If this is dependent, we need to record that. If not, we simply
// mangle it as the underlying type since they are equivalent.
if (T->isDependentType()) {
- Out << 'U';
+ Out << "u";
+ StringRef BuiltinName;
switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- Out << "3eut";
- break;
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ case UnaryTransformType::Enum: \
+ BuiltinName = "__" #Trait; \
+ break;
+#include "clang/Basic/TransformTypeTraits.def"
}
+ Out << BuiltinName.size() << BuiltinName;
}
+ Out << "I";
mangleType(T->getBaseType());
+ Out << "E";
}
void CXXNameMangler::mangleType(const AutoType *T) {
@@ -4247,6 +4250,7 @@ recurse:
case Expr::OMPArrayShapingExprClass:
case Expr::OMPIteratorExprClass:
case Expr::CXXInheritedCtorInitExprClass:
+ case Expr::CXXParenListInitExprClass:
llvm_unreachable("unexpected statement kind");
case Expr::ConstantExprClass:
@@ -4671,7 +4675,7 @@ recurse:
Out << 'E';
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case UETT_AlignOf:
Out << 'a';
MangleAlignofSizeofArg();
@@ -4886,9 +4890,7 @@ recurse:
// <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());
+ mangleTemplateName(CSE->getNamedConcept(), CSE->getTemplateArguments());
Out << 'E';
break;
}
@@ -5345,13 +5347,12 @@ void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
}
void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+ ArrayRef<TemplateArgument> Args) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
TemplateArgManglingInfo Info(TN);
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(TemplateArgs[i], Info.needExactType(i, TemplateArgs[i]));
+ for (unsigned i = 0; i != Args.size(); ++i)
+ mangleTemplateArg(Args[i], Info.needExactType(i, Args[i]));
Out << 'E';
}
@@ -6431,23 +6432,25 @@ void ItaniumMangleContextImpl::mangleDynamicStermFinalizer(const VarDecl *D,
}
void ItaniumMangleContextImpl::mangleSEHFilterExpression(
- const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ GlobalDecl EnclosingDecl, raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "__filt_";
- if (shouldMangleDeclName(EnclosingDecl))
+ auto *EnclosingFD = cast<FunctionDecl>(EnclosingDecl.getDecl());
+ if (shouldMangleDeclName(EnclosingFD))
Mangler.mangle(EnclosingDecl);
else
- Mangler.getStream() << EnclosingDecl->getName();
+ Mangler.getStream() << EnclosingFD->getName();
}
void ItaniumMangleContextImpl::mangleSEHFinallyBlock(
- const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ GlobalDecl EnclosingDecl, raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "__fin_";
- if (shouldMangleDeclName(EnclosingDecl))
+ auto *EnclosingFD = cast<FunctionDecl>(EnclosingDecl.getDecl());
+ if (shouldMangleDeclName(EnclosingFD))
Mangler.mangle(EnclosingDecl);
else
- Mangler.getStream() << EnclosingDecl->getName();
+ Mangler.getStream() << EnclosingFD->getName();
}
void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
@@ -6558,8 +6561,8 @@ ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context,
bool IsAux) {
return new ItaniumMangleContextImpl(
Context, Diags,
- [](ASTContext &, const NamedDecl *) -> llvm::Optional<unsigned> {
- return llvm::None;
+ [](ASTContext &, const NamedDecl *) -> std::optional<unsigned> {
+ return std::nullopt;
},
IsAux);
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 87e4255c2b93..83b097daf8ab 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1,8 +1,9 @@
#include "clang/AST/JSONNodeDumper.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/StringSwitch.h"
+#include <optional>
using namespace clang;
@@ -530,6 +531,14 @@ JSONNodeDumper::createCXXBaseSpecifier(const CXXBaseSpecifier &BS) {
void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) {
JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
+ if (!TT->typeMatchesDecl())
+ JOS.attribute("type", createQualType(TT->desugar()));
+}
+
+void JSONNodeDumper::VisitUsingType(const UsingType *TT) {
+ JOS.attribute("decl", createBareDeclRef(TT->getFoundDecl()));
+ if (!TT->typeMatchesDecl())
+ JOS.attribute("type", createQualType(TT->desugar()));
}
void JSONNodeDumper::VisitFunctionType(const FunctionType *T) {
@@ -662,9 +671,11 @@ void JSONNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *UUT) {
void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) {
switch (UTT->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- JOS.attribute("transformKind", "underlying_type");
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ case UnaryTransformType::Enum: \
+ JOS.attribute("transformKind", #Trait); \
break;
+#include "clang/Basic/TransformTypeTraits.def"
}
}
@@ -680,6 +691,18 @@ void JSONNodeDumper::VisitTemplateTypeParmType(
JOS.attribute("decl", createBareDeclRef(TTPT->getDecl()));
}
+void JSONNodeDumper::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *STTPT) {
+ JOS.attribute("index", STTPT->getIndex());
+ if (auto PackIndex = STTPT->getPackIndex())
+ JOS.attribute("pack_index", *PackIndex);
+}
+
+void JSONNodeDumper::VisitSubstTemplateTypeParmPackType(
+ const SubstTemplateTypeParmPackType *T) {
+ JOS.attribute("index", T->getIndex());
+}
+
void JSONNodeDumper::VisitAutoType(const AutoType *AT) {
JOS.attribute("undeduced", !AT->isDeduced());
switch (AT->getKeyword()) {
@@ -715,7 +738,7 @@ void JSONNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *OIT) {
}
void JSONNodeDumper::VisitPackExpansionType(const PackExpansionType *PET) {
- if (llvm::Optional<unsigned> N = PET->getNumExpansions())
+ if (std::optional<unsigned> N = PET->getNumExpansions())
JOS.attribute("numExpansions", *N);
}
@@ -772,6 +795,7 @@ void JSONNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *TAD) {
void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) {
VisitNamedDecl(ND);
attributeOnlyIfTrue("isInline", ND->isInline());
+ attributeOnlyIfTrue("isNested", ND->isNested());
if (!ND->isOriginalNamespace())
JOS.attribute("originalNamespace",
createBareDeclRef(ND->getOriginalNamespace()));
@@ -827,6 +851,9 @@ void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
case VarDecl::CInit: JOS.attribute("init", "c"); break;
case VarDecl::CallInit: JOS.attribute("init", "call"); break;
case VarDecl::ListInit: JOS.attribute("init", "list"); break;
+ case VarDecl::ParenListInit:
+ JOS.attribute("init", "paren-list");
+ break;
}
}
attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
@@ -893,6 +920,11 @@ void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) {
}
}
+void JSONNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("bufferKind", D->isCBuffer() ? "cbuffer" : "tbuffer");
+}
+
void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
VisitNamedDecl(D);
JOS.attribute("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class");
diff --git a/clang/lib/AST/Linkage.h b/clang/lib/AST/Linkage.h
index cd50d138790a..31f384eb75d0 100644
--- a/clang/lib/AST/Linkage.h
+++ b/clang/lib/AST/Linkage.h
@@ -19,8 +19,8 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
+#include <optional>
namespace clang {
/// Kinds of LV computation. The linkage side of the computation is
@@ -91,11 +91,11 @@ class LinkageComputer {
return QueryType(ND, Kind.toBits());
}
- llvm::Optional<LinkageInfo> lookup(const NamedDecl *ND,
- LVComputationKind Kind) const {
+ std::optional<LinkageInfo> lookup(const NamedDecl *ND,
+ LVComputationKind Kind) const {
auto Iter = CachedLinkageInfo.find(makeCacheKey(ND, Kind));
if (Iter == CachedLinkageInfo.end())
- return None;
+ return std::nullopt;
return Iter->second;
}
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 7ea569c63d9e..31cdad4c8fdd 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -223,6 +223,7 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (!MD->isStatic())
++ArgWords;
+ uint64_t DefaultPtrWidth = TI.getPointerWidth(LangAS::Default);
for (const auto &AT : Proto->param_types()) {
// If an argument type is incomplete there is no way to get its size to
// correctly encode into the mangling scheme.
@@ -230,11 +231,10 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (AT->isIncompleteType())
break;
// Size should be aligned to pointer size.
- ArgWords +=
- llvm::alignTo(ASTContext.getTypeSize(AT), TI.getPointerWidth(0)) /
- TI.getPointerWidth(0);
+ ArgWords += llvm::alignTo(ASTContext.getTypeSize(AT), DefaultPtrWidth) /
+ DefaultPtrWidth;
}
- Out << ((TI.getPointerWidth(0) / 8) * ArgWords);
+ Out << ((DefaultPtrWidth / 8) * ArgWords);
}
void MangleContext::mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream &Out) {
diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp
index 7f4a7b2b9381..263e263eba7c 100644
--- a/clang/lib/AST/MicrosoftCXXABI.cpp
+++ b/clang/lib/AST/MicrosoftCXXABI.cpp
@@ -303,7 +303,7 @@ CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(
// The nominal struct is laid out with pointers followed by ints and aligned
// to a pointer width if any are present and an int width otherwise.
const TargetInfo &Target = Context.getTargetInfo();
- unsigned PtrSize = Target.getPointerWidth(0);
+ unsigned PtrSize = Target.getPointerWidth(LangAS::Default);
unsigned IntSize = Target.getIntWidth();
unsigned Ptrs, Ints;
@@ -318,7 +318,7 @@ CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(
if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit())
MPI.Align = 64;
else if (Ptrs)
- MPI.Align = Target.getPointerAlign(0);
+ MPI.Align = Target.getPointerAlign(LangAS::Default);
else
MPI.Align = Target.getIntAlign();
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 09075e60142a..cdd2c93c4b14 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -35,6 +35,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/xxhash.h"
+#include <optional>
using namespace clang;
@@ -142,8 +143,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
- llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
- llvm::DenseMap<const NamedDecl *, unsigned> SEHFinallyIds;
+ llvm::DenseMap<GlobalDecl, unsigned> SEHFilterIds;
+ llvm::DenseMap<GlobalDecl, unsigned> SEHFinallyIds;
SmallString<16> AnonymousNamespaceHash;
public:
@@ -201,9 +202,9 @@ public:
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
- void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ void mangleSEHFilterExpression(GlobalDecl EnclosingDecl,
raw_ostream &Out) override;
- void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+ void mangleSEHFinallyBlock(GlobalDecl EnclosingDecl,
raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
@@ -340,22 +341,22 @@ public:
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_)
: Context(C), Out(Out_), Structor(nullptr), StructorType(-1),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) {}
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
+ LangAS::Default) == 64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) {}
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
+ LangAS::Default) == 64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) {}
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
+ LangAS::Default) == 64) {}
raw_ostream &getStream() const { return Out; }
@@ -376,7 +377,7 @@ public:
void mangleBits(llvm::APInt Number);
void mangleTagTypeKind(TagTypeKind TK);
void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName,
- ArrayRef<StringRef> NestedNames = None);
+ ArrayRef<StringRef> NestedNames = std::nullopt);
void mangleAddressSpaceType(QualType T, Qualifiers Quals, SourceRange Range);
void mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM = QMM_Mangle);
@@ -776,7 +777,7 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk(
const CXXMethodDecl *MD, const MethodVFTableLocation &ML) {
// Get the vftable offset.
CharUnits PointerWidth = getASTContext().toCharUnitsFromBits(
- getASTContext().getTargetInfo().getPointerWidth(0));
+ getASTContext().getTargetInfo().getPointerWidth(LangAS::Default));
uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity();
Out << "?_9";
@@ -838,6 +839,9 @@ void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) {
case APFloat::S_x87DoubleExtended: Out << 'X'; break;
case APFloat::S_IEEEquad: Out << 'Y'; break;
case APFloat::S_PPCDoubleDouble: Out << 'Z'; break;
+ case APFloat::S_Float8E5M2:
+ case APFloat::S_Float8E4M3FN:
+ llvm_unreachable("Tried to mangle unexpected APFloat semantics");
}
mangleBits(Number.bitcastToAPInt());
@@ -1505,7 +1509,7 @@ void MicrosoftCXXNameMangler::mangleIntegerLiteral(
void MicrosoftCXXNameMangler::mangleExpression(
const Expr *E, const NonTypeTemplateParmDecl *PD) {
// See if this is a constant expression.
- if (Optional<llvm::APSInt> Value =
+ if (std::optional<llvm::APSInt> Value =
E->getIntegerConstantExpr(Context.getASTContext())) {
mangleIntegerLiteral(*Value, PD, E->getType());
return;
@@ -2469,6 +2473,10 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
Out << "$halff@";
break;
+ case BuiltinType::BFloat16:
+ mangleArtificialTagType(TTK_Struct, "__bf16", {"__clang"});
+ break;
+
#define SVE_TYPE(Name, Id, SingletonId) \
case BuiltinType::Id:
#include "clang/Basic/AArch64SVEACLETypes.def"
@@ -2501,7 +2509,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
case BuiltinType::SatUShortFract:
case BuiltinType::SatUFract:
case BuiltinType::SatULongFract:
- case BuiltinType::BFloat16:
case BuiltinType::Ibm128:
case BuiltinType::Float128: {
DiagnosticsEngine &Diags = Context.getDiags();
@@ -3070,14 +3077,17 @@ bool MicrosoftCXXNameMangler::isArtificialTagType(QualType T) const {
void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
SourceRange Range) {
- const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>();
- assert(ET && "vectors with non-builtin elements are unsupported");
+ QualType EltTy = T->getElementType();
+ const BuiltinType *ET = EltTy->getAs<BuiltinType>();
+ const BitIntType *BitIntTy = EltTy->getAs<BitIntType>();
+ assert((ET || BitIntTy) &&
+ "vectors with non-builtin/_BitInt elements are unsupported");
uint64_t Width = getASTContext().getTypeSize(T);
// Pattern match exactly the typedefs in our intrinsic headers. Anything that
// doesn't match the Intel types uses a custom mangling below.
size_t OutSizeBefore = Out.tell();
if (!isa<ExtVectorType>(T)) {
- if (getASTContext().getTargetInfo().getTriple().isX86()) {
+ if (getASTContext().getTargetInfo().getTriple().isX86() && ET) {
if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
mangleArtificialTagType(TTK_Union, "__m64");
} else if (Width >= 128) {
@@ -3102,7 +3112,8 @@ void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
Extra.mangleSourceName("__vector");
- Extra.mangleType(QualType(ET, 0), Range, QMM_Escape);
+ Extra.mangleType(QualType(ET ? static_cast<const Type *>(ET) : BitIntTy, 0),
+ Range, QMM_Escape);
Extra.mangleIntegerLiteral(llvm::APSInt::getUnsigned(T->getNumElements()));
mangleArtificialTagType(TTK_Union, TemplateMangling, {"__clang"});
@@ -3720,7 +3731,7 @@ void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
}
void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
- const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ GlobalDecl EnclosingDecl, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
// The function body is in the same comdat as the function with the handler,
@@ -3732,7 +3743,7 @@ void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
}
void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
- const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ GlobalDecl EnclosingDecl, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
// The function body is in the same comdat as the function with the handler,
diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp
index db7878e18c42..3621a2eaa573 100644
--- a/clang/lib/AST/NSAPI.cpp
+++ b/clang/lib/AST/NSAPI.cpp
@@ -11,6 +11,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "llvm/ADT/StringSwitch.h"
+#include <optional>
using namespace clang;
@@ -142,14 +143,15 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
return NSArraySelectors[MK];
}
-Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
+std::optional<NSAPI::NSArrayMethodKind>
+NSAPI::getNSArrayMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
NSArrayMethodKind MK = NSArrayMethodKind(i);
if (Sel == getNSArraySelector(MK))
return MK;
}
- return None;
+ return std::nullopt;
}
Selector NSAPI::getNSDictionarySelector(
@@ -243,7 +245,7 @@ Selector NSAPI::getNSDictionarySelector(
return NSDictionarySelectors[MK];
}
-Optional<NSAPI::NSDictionaryMethodKind>
+std::optional<NSAPI::NSDictionaryMethodKind>
NSAPI::getNSDictionaryMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
@@ -251,7 +253,7 @@ NSAPI::getNSDictionaryMethodKind(Selector Sel) {
return MK;
}
- return None;
+ return std::nullopt;
}
Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
@@ -300,15 +302,14 @@ Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
return NSSetSelectors[MK];
}
-Optional<NSAPI::NSSetMethodKind>
-NSAPI::getNSSetMethodKind(Selector Sel) {
+std::optional<NSAPI::NSSetMethodKind> NSAPI::getNSSetMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSSetMethods; ++i) {
NSSetMethodKind MK = NSSetMethodKind(i);
if (Sel == getNSSetSelector(MK))
return MK;
}
- return None;
+ return std::nullopt;
}
Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
@@ -363,7 +364,7 @@ Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
return Sels[MK];
}
-Optional<NSAPI::NSNumberLiteralMethodKind>
+std::optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
@@ -371,14 +372,14 @@ NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
return MK;
}
- return None;
+ return std::nullopt;
}
-Optional<NSAPI::NSNumberLiteralMethodKind>
+std::optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
const BuiltinType *BT = T->getAs<BuiltinType>();
if (!BT)
- return None;
+ return std::nullopt;
const TypedefType *TDT = T->getAs<TypedefType>();
if (TDT) {
@@ -496,7 +497,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
break;
}
- return None;
+ return std::nullopt;
}
/// Returns true if \param T is a typedef of "BOOL" in objective-c.
diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp
index 8f19d80cbdc5..36f2c47b3000 100644
--- a/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/clang/lib/AST/NestedNameSpecifier.cpp
@@ -280,14 +280,14 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
case TypeSpecWithTemplate:
OS << "template ";
// Fall through to print the type.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case TypeSpec: {
const auto *Record =
dyn_cast_or_null<ClassTemplateSpecializationDecl>(getAsRecordDecl());
if (ResolveTemplateArguments && Record) {
// Print the type trait with resolved template parameters.
- Record->printName(OS);
+ Record->printName(OS, Policy);
printTemplateArgumentList(
OS, Record->getTemplateArgs().asArray(), Policy,
Record->getSpecializedTemplate()->getTemplateParameters());
diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp
new file mode 100644
index 000000000000..b3fe070889c5
--- /dev/null
+++ b/clang/lib/AST/ODRDiagsEmitter.cpp
@@ -0,0 +1,2206 @@
+//===-- ODRDiagsEmitter.cpp - Diagnostics for ODR mismatches ----*- 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/AST/ODRDiagsEmitter.h"
+#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ODRHash.h"
+#include "clang/Basic/DiagnosticAST.h"
+#include "clang/Basic/Module.h"
+
+using namespace clang;
+
+static unsigned computeODRHash(QualType Ty) {
+ ODRHash Hasher;
+ Hasher.AddQualType(Ty);
+ return Hasher.CalculateHash();
+}
+
+static unsigned computeODRHash(const Stmt *S) {
+ ODRHash Hasher;
+ Hasher.AddStmt(S);
+ return Hasher.CalculateHash();
+}
+
+static unsigned computeODRHash(const Decl *D) {
+ assert(D);
+ ODRHash Hasher;
+ Hasher.AddSubDecl(D);
+ return Hasher.CalculateHash();
+}
+
+static unsigned computeODRHash(const TemplateArgument &TA) {
+ ODRHash Hasher;
+ Hasher.AddTemplateArgument(TA);
+ return Hasher.CalculateHash();
+}
+
+std::string ODRDiagsEmitter::getOwningModuleNameForDiagnostic(const Decl *D) {
+ // If we know the owning module, use it.
+ if (Module *M = D->getImportedOwningModule())
+ return M->getFullModuleName();
+
+ // Not from a module.
+ return {};
+}
+
+template <typename MethodT>
+static bool diagnoseSubMismatchMethodParameters(DiagnosticsEngine &Diags,
+ const NamedDecl *FirstContainer,
+ StringRef FirstModule,
+ StringRef SecondModule,
+ const MethodT *FirstMethod,
+ const MethodT *SecondMethod) {
+ enum DiagMethodType {
+ DiagMethod,
+ DiagConstructor,
+ DiagDestructor,
+ };
+ auto GetDiagMethodType = [](const NamedDecl *D) {
+ if (isa<CXXConstructorDecl>(D))
+ return DiagConstructor;
+ if (isa<CXXDestructorDecl>(D))
+ return DiagDestructor;
+ return DiagMethod;
+ };
+
+ enum ODRMethodParametersDifference {
+ NumberParameters,
+ ParameterType,
+ ParameterName,
+ };
+ auto DiagError = [&Diags, &GetDiagMethodType, FirstContainer, FirstModule,
+ FirstMethod](ODRMethodParametersDifference DiffType) {
+ DeclarationName FirstName = FirstMethod->getDeclName();
+ DiagMethodType FirstMethodType = GetDiagMethodType(FirstMethod);
+ return Diags.Report(FirstMethod->getLocation(),
+ diag::err_module_odr_violation_method_params)
+ << FirstContainer << FirstModule.empty() << FirstModule
+ << FirstMethod->getSourceRange() << DiffType << FirstMethodType
+ << FirstName;
+ };
+ auto DiagNote = [&Diags, &GetDiagMethodType, SecondModule,
+ SecondMethod](ODRMethodParametersDifference DiffType) {
+ DeclarationName SecondName = SecondMethod->getDeclName();
+ DiagMethodType SecondMethodType = GetDiagMethodType(SecondMethod);
+ return Diags.Report(SecondMethod->getLocation(),
+ diag::note_module_odr_violation_method_params)
+ << SecondModule.empty() << SecondModule
+ << SecondMethod->getSourceRange() << DiffType << SecondMethodType
+ << SecondName;
+ };
+
+ const unsigned FirstNumParameters = FirstMethod->param_size();
+ const unsigned SecondNumParameters = SecondMethod->param_size();
+ if (FirstNumParameters != SecondNumParameters) {
+ DiagError(NumberParameters) << FirstNumParameters;
+ DiagNote(NumberParameters) << SecondNumParameters;
+ return true;
+ }
+
+ for (unsigned I = 0; I < FirstNumParameters; ++I) {
+ const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
+
+ QualType FirstParamType = FirstParam->getType();
+ QualType SecondParamType = SecondParam->getType();
+ if (FirstParamType != SecondParamType &&
+ computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
+ if (const DecayedType *ParamDecayedType =
+ FirstParamType->getAs<DecayedType>()) {
+ DiagError(ParameterType) << (I + 1) << FirstParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagError(ParameterType) << (I + 1) << FirstParamType << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ DiagNote(ParameterType) << (I + 1) << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagNote(ParameterType) << (I + 1) << SecondParamType << false;
+ }
+ return true;
+ }
+
+ DeclarationName FirstParamName = FirstParam->getDeclName();
+ DeclarationName SecondParamName = SecondParam->getDeclName();
+ if (FirstParamName != SecondParamName) {
+ DiagError(ParameterName) << (I + 1) << FirstParamName;
+ DiagNote(ParameterName) << (I + 1) << SecondParamName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchField(
+ const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule,
+ const FieldDecl *FirstField, const FieldDecl *SecondField) const {
+ enum ODRFieldDifference {
+ FieldName,
+ FieldTypeName,
+ FieldSingleBitField,
+ FieldDifferentWidthBitField,
+ FieldSingleMutable,
+ FieldSingleInitializer,
+ FieldDifferentInitializers,
+ };
+
+ auto DiagError = [FirstRecord, FirstField, FirstModule,
+ this](ODRFieldDifference DiffType) {
+ return Diag(FirstField->getLocation(), diag::err_module_odr_violation_field)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstField->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondField, SecondModule,
+ this](ODRFieldDifference DiffType) {
+ return Diag(SecondField->getLocation(),
+ diag::note_module_odr_violation_field)
+ << SecondModule.empty() << SecondModule << SecondField->getSourceRange() << DiffType;
+ };
+
+ IdentifierInfo *FirstII = FirstField->getIdentifier();
+ IdentifierInfo *SecondII = SecondField->getIdentifier();
+ if (FirstII->getName() != SecondII->getName()) {
+ DiagError(FieldName) << FirstII;
+ DiagNote(FieldName) << SecondII;
+ return true;
+ }
+
+ QualType FirstType = FirstField->getType();
+ QualType SecondType = SecondField->getType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagError(FieldTypeName) << FirstII << FirstType;
+ DiagNote(FieldTypeName) << SecondII << SecondType;
+ return true;
+ }
+
+ assert(Context.hasSameType(FirstField->getType(), SecondField->getType()));
+ (void)Context;
+
+ const bool IsFirstBitField = FirstField->isBitField();
+ const bool IsSecondBitField = SecondField->isBitField();
+ if (IsFirstBitField != IsSecondBitField) {
+ DiagError(FieldSingleBitField) << FirstII << IsFirstBitField;
+ DiagNote(FieldSingleBitField) << SecondII << IsSecondBitField;
+ return true;
+ }
+
+ if (IsFirstBitField && IsSecondBitField) {
+ unsigned FirstBitWidthHash = computeODRHash(FirstField->getBitWidth());
+ unsigned SecondBitWidthHash = computeODRHash(SecondField->getBitWidth());
+ if (FirstBitWidthHash != SecondBitWidthHash) {
+ DiagError(FieldDifferentWidthBitField)
+ << FirstII << FirstField->getBitWidth()->getSourceRange();
+ DiagNote(FieldDifferentWidthBitField)
+ << SecondII << SecondField->getBitWidth()->getSourceRange();
+ return true;
+ }
+ }
+
+ if (!LangOpts.CPlusPlus)
+ return false;
+
+ const bool IsFirstMutable = FirstField->isMutable();
+ const bool IsSecondMutable = SecondField->isMutable();
+ if (IsFirstMutable != IsSecondMutable) {
+ DiagError(FieldSingleMutable) << FirstII << IsFirstMutable;
+ DiagNote(FieldSingleMutable) << SecondII << IsSecondMutable;
+ return true;
+ }
+
+ const Expr *FirstInitializer = FirstField->getInClassInitializer();
+ const Expr *SecondInitializer = SecondField->getInClassInitializer();
+ if ((!FirstInitializer && SecondInitializer) ||
+ (FirstInitializer && !SecondInitializer)) {
+ DiagError(FieldSingleInitializer)
+ << FirstII << (FirstInitializer != nullptr);
+ DiagNote(FieldSingleInitializer)
+ << SecondII << (SecondInitializer != nullptr);
+ return true;
+ }
+
+ if (FirstInitializer && SecondInitializer) {
+ unsigned FirstInitHash = computeODRHash(FirstInitializer);
+ unsigned SecondInitHash = computeODRHash(SecondInitializer);
+ if (FirstInitHash != SecondInitHash) {
+ DiagError(FieldDifferentInitializers)
+ << FirstII << FirstInitializer->getSourceRange();
+ DiagNote(FieldDifferentInitializers)
+ << SecondII << SecondInitializer->getSourceRange();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchTypedef(
+ const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule,
+ const TypedefNameDecl *FirstTD, const TypedefNameDecl *SecondTD,
+ bool IsTypeAlias) const {
+ enum ODRTypedefDifference {
+ TypedefName,
+ TypedefType,
+ };
+
+ auto DiagError = [FirstRecord, FirstTD, FirstModule,
+ this](ODRTypedefDifference DiffType) {
+ return Diag(FirstTD->getLocation(), diag::err_module_odr_violation_typedef)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstTD->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondTD, SecondModule,
+ this](ODRTypedefDifference DiffType) {
+ return Diag(SecondTD->getLocation(),
+ diag::note_module_odr_violation_typedef)
+ << SecondModule << SecondTD->getSourceRange() << DiffType;
+ };
+
+ DeclarationName FirstName = FirstTD->getDeclName();
+ DeclarationName SecondName = SecondTD->getDeclName();
+ if (FirstName != SecondName) {
+ DiagError(TypedefName) << IsTypeAlias << FirstName;
+ DiagNote(TypedefName) << IsTypeAlias << SecondName;
+ return true;
+ }
+
+ QualType FirstType = FirstTD->getUnderlyingType();
+ QualType SecondType = SecondTD->getUnderlyingType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagError(TypedefType) << IsTypeAlias << FirstName << FirstType;
+ DiagNote(TypedefType) << IsTypeAlias << SecondName << SecondType;
+ return true;
+ }
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchVar(const NamedDecl *FirstRecord,
+ StringRef FirstModule,
+ StringRef SecondModule,
+ const VarDecl *FirstVD,
+ const VarDecl *SecondVD) const {
+ enum ODRVarDifference {
+ VarName,
+ VarType,
+ VarSingleInitializer,
+ VarDifferentInitializer,
+ VarConstexpr,
+ };
+
+ auto DiagError = [FirstRecord, FirstVD, FirstModule,
+ this](ODRVarDifference DiffType) {
+ return Diag(FirstVD->getLocation(), diag::err_module_odr_violation_variable)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstVD->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondVD, SecondModule, this](ODRVarDifference DiffType) {
+ return Diag(SecondVD->getLocation(),
+ diag::note_module_odr_violation_variable)
+ << SecondModule << SecondVD->getSourceRange() << DiffType;
+ };
+
+ DeclarationName FirstName = FirstVD->getDeclName();
+ DeclarationName SecondName = SecondVD->getDeclName();
+ if (FirstName != SecondName) {
+ DiagError(VarName) << FirstName;
+ DiagNote(VarName) << SecondName;
+ return true;
+ }
+
+ QualType FirstType = FirstVD->getType();
+ QualType SecondType = SecondVD->getType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagError(VarType) << FirstName << FirstType;
+ DiagNote(VarType) << SecondName << SecondType;
+ return true;
+ }
+
+ if (!LangOpts.CPlusPlus)
+ return false;
+
+ const Expr *FirstInit = FirstVD->getInit();
+ const Expr *SecondInit = SecondVD->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ DiagError(VarSingleInitializer)
+ << FirstName << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ DiagNote(VarSingleInitializer)
+ << SecondName << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ return true;
+ }
+
+ if (FirstInit && SecondInit &&
+ computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
+ DiagError(VarDifferentInitializer)
+ << FirstName << FirstInit->getSourceRange();
+ DiagNote(VarDifferentInitializer)
+ << SecondName << SecondInit->getSourceRange();
+ return true;
+ }
+
+ const bool FirstIsConstexpr = FirstVD->isConstexpr();
+ const bool SecondIsConstexpr = SecondVD->isConstexpr();
+ if (FirstIsConstexpr != SecondIsConstexpr) {
+ DiagError(VarConstexpr) << FirstName << FirstIsConstexpr;
+ DiagNote(VarConstexpr) << SecondName << SecondIsConstexpr;
+ return true;
+ }
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchProtocols(
+ const ObjCProtocolList &FirstProtocols,
+ const ObjCContainerDecl *FirstContainer, StringRef FirstModule,
+ const ObjCProtocolList &SecondProtocols,
+ const ObjCContainerDecl *SecondContainer, StringRef SecondModule) const {
+ // Keep in sync with err_module_odr_violation_referenced_protocols.
+ enum ODRReferencedProtocolDifference {
+ NumProtocols,
+ ProtocolType,
+ };
+ auto DiagRefProtocolError = [FirstContainer, FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRReferencedProtocolDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_referenced_protocols)
+ << FirstContainer << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagRefProtocolNote = [SecondModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRReferencedProtocolDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_referenced_protocols)
+ << SecondModule.empty() << SecondModule << Range << DiffType;
+ };
+ auto GetProtoListSourceRange = [](const ObjCProtocolList &PL) {
+ if (PL.empty())
+ return SourceRange();
+ return SourceRange(*PL.loc_begin(), *std::prev(PL.loc_end()));
+ };
+
+ if (FirstProtocols.size() != SecondProtocols.size()) {
+ DiagRefProtocolError(FirstContainer->getLocation(),
+ GetProtoListSourceRange(FirstProtocols), NumProtocols)
+ << FirstProtocols.size();
+ DiagRefProtocolNote(SecondContainer->getLocation(),
+ GetProtoListSourceRange(SecondProtocols), NumProtocols)
+ << SecondProtocols.size();
+ return true;
+ }
+
+ for (unsigned I = 0, E = FirstProtocols.size(); I != E; ++I) {
+ const ObjCProtocolDecl *FirstProtocol = FirstProtocols[I];
+ const ObjCProtocolDecl *SecondProtocol = SecondProtocols[I];
+ DeclarationName FirstProtocolName = FirstProtocol->getDeclName();
+ DeclarationName SecondProtocolName = SecondProtocol->getDeclName();
+ if (FirstProtocolName != SecondProtocolName) {
+ SourceLocation FirstLoc = *(FirstProtocols.loc_begin() + I);
+ SourceLocation SecondLoc = *(SecondProtocols.loc_begin() + I);
+ SourceRange EmptyRange;
+ DiagRefProtocolError(FirstLoc, EmptyRange, ProtocolType)
+ << (I + 1) << FirstProtocolName;
+ DiagRefProtocolNote(SecondLoc, EmptyRange, ProtocolType)
+ << (I + 1) << SecondProtocolName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchObjCMethod(
+ const NamedDecl *FirstObjCContainer, StringRef FirstModule,
+ StringRef SecondModule, const ObjCMethodDecl *FirstMethod,
+ const ObjCMethodDecl *SecondMethod) const {
+ enum ODRMethodDifference {
+ ReturnType,
+ InstanceOrClass,
+ ControlLevel, // optional/required
+ DesignatedInitializer,
+ Directness,
+ Name,
+ };
+
+ auto DiagError = [FirstObjCContainer, FirstModule, FirstMethod,
+ this](ODRMethodDifference DiffType) {
+ return Diag(FirstMethod->getLocation(),
+ diag::err_module_odr_violation_objc_method)
+ << FirstObjCContainer << FirstModule.empty() << FirstModule
+ << FirstMethod->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondModule, SecondMethod,
+ this](ODRMethodDifference DiffType) {
+ return Diag(SecondMethod->getLocation(),
+ diag::note_module_odr_violation_objc_method)
+ << SecondModule.empty() << SecondModule
+ << SecondMethod->getSourceRange() << DiffType;
+ };
+
+ if (computeODRHash(FirstMethod->getReturnType()) !=
+ computeODRHash(SecondMethod->getReturnType())) {
+ DiagError(ReturnType) << FirstMethod << FirstMethod->getReturnType();
+ DiagNote(ReturnType) << SecondMethod << SecondMethod->getReturnType();
+ return true;
+ }
+
+ if (FirstMethod->isInstanceMethod() != SecondMethod->isInstanceMethod()) {
+ DiagError(InstanceOrClass)
+ << FirstMethod << FirstMethod->isInstanceMethod();
+ DiagNote(InstanceOrClass)
+ << SecondMethod << SecondMethod->isInstanceMethod();
+ return true;
+ }
+ if (FirstMethod->getImplementationControl() !=
+ SecondMethod->getImplementationControl()) {
+ DiagError(ControlLevel) << FirstMethod->getImplementationControl();
+ DiagNote(ControlLevel) << SecondMethod->getImplementationControl();
+ return true;
+ }
+ if (FirstMethod->isThisDeclarationADesignatedInitializer() !=
+ SecondMethod->isThisDeclarationADesignatedInitializer()) {
+ DiagError(DesignatedInitializer)
+ << FirstMethod
+ << FirstMethod->isThisDeclarationADesignatedInitializer();
+ DiagNote(DesignatedInitializer)
+ << SecondMethod
+ << SecondMethod->isThisDeclarationADesignatedInitializer();
+ return true;
+ }
+ if (FirstMethod->isDirectMethod() != SecondMethod->isDirectMethod()) {
+ DiagError(Directness) << FirstMethod << FirstMethod->isDirectMethod();
+ DiagNote(Directness) << SecondMethod << SecondMethod->isDirectMethod();
+ return true;
+ }
+ if (diagnoseSubMismatchMethodParameters(Diags, FirstObjCContainer,
+ FirstModule, SecondModule,
+ FirstMethod, SecondMethod))
+ return true;
+
+ // Check method name *after* looking at the parameters otherwise we get a
+ // less ideal diagnostics: a ObjCMethodName mismatch given that selectors
+ // for different parameters are likely to be different.
+ DeclarationName FirstName = FirstMethod->getDeclName();
+ DeclarationName SecondName = SecondMethod->getDeclName();
+ if (FirstName != SecondName) {
+ DiagError(Name) << FirstName;
+ DiagNote(Name) << SecondName;
+ return true;
+ }
+
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchObjCProperty(
+ const NamedDecl *FirstObjCContainer, StringRef FirstModule,
+ StringRef SecondModule, const ObjCPropertyDecl *FirstProp,
+ const ObjCPropertyDecl *SecondProp) const {
+ enum ODRPropertyDifference {
+ Name,
+ Type,
+ ControlLevel, // optional/required
+ Attribute,
+ };
+
+ auto DiagError = [FirstObjCContainer, FirstModule, FirstProp,
+ this](SourceLocation Loc, ODRPropertyDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_objc_property)
+ << FirstObjCContainer << FirstModule.empty() << FirstModule
+ << FirstProp->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondModule, SecondProp,
+ this](SourceLocation Loc, ODRPropertyDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_objc_property)
+ << SecondModule.empty() << SecondModule
+ << SecondProp->getSourceRange() << DiffType;
+ };
+
+ IdentifierInfo *FirstII = FirstProp->getIdentifier();
+ IdentifierInfo *SecondII = SecondProp->getIdentifier();
+ if (FirstII->getName() != SecondII->getName()) {
+ DiagError(FirstProp->getLocation(), Name) << FirstII;
+ DiagNote(SecondProp->getLocation(), Name) << SecondII;
+ return true;
+ }
+ if (computeODRHash(FirstProp->getType()) !=
+ computeODRHash(SecondProp->getType())) {
+ DiagError(FirstProp->getLocation(), Type)
+ << FirstII << FirstProp->getType();
+ DiagNote(SecondProp->getLocation(), Type)
+ << SecondII << SecondProp->getType();
+ return true;
+ }
+ if (FirstProp->getPropertyImplementation() !=
+ SecondProp->getPropertyImplementation()) {
+ DiagError(FirstProp->getLocation(), ControlLevel)
+ << FirstProp->getPropertyImplementation();
+ DiagNote(SecondProp->getLocation(), ControlLevel)
+ << SecondProp->getPropertyImplementation();
+ return true;
+ }
+
+ // Go over the property attributes and stop at the first mismatch.
+ unsigned FirstAttrs = (unsigned)FirstProp->getPropertyAttributes();
+ unsigned SecondAttrs = (unsigned)SecondProp->getPropertyAttributes();
+ if (FirstAttrs != SecondAttrs) {
+ for (unsigned I = 0; I < NumObjCPropertyAttrsBits; ++I) {
+ unsigned CheckedAttr = (1 << I);
+ if ((FirstAttrs & CheckedAttr) == (SecondAttrs & CheckedAttr))
+ continue;
+
+ bool IsFirstWritten =
+ (unsigned)FirstProp->getPropertyAttributesAsWritten() & CheckedAttr;
+ bool IsSecondWritten =
+ (unsigned)SecondProp->getPropertyAttributesAsWritten() & CheckedAttr;
+ DiagError(IsFirstWritten ? FirstProp->getLParenLoc()
+ : FirstProp->getLocation(),
+ Attribute)
+ << FirstII << (I + 1) << IsFirstWritten;
+ DiagNote(IsSecondWritten ? SecondProp->getLParenLoc()
+ : SecondProp->getLocation(),
+ Attribute)
+ << SecondII << (I + 1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+ODRDiagsEmitter::DiffResult
+ODRDiagsEmitter::FindTypeDiffs(DeclHashes &FirstHashes,
+ DeclHashes &SecondHashes) {
+ auto DifferenceSelector = [](const Decl *D) {
+ assert(D && "valid Decl required");
+ switch (D->getKind()) {
+ default:
+ return Other;
+ case Decl::AccessSpec:
+ switch (D->getAccess()) {
+ case AS_public:
+ return PublicSpecifer;
+ case AS_private:
+ return PrivateSpecifer;
+ case AS_protected:
+ return ProtectedSpecifer;
+ case AS_none:
+ break;
+ }
+ llvm_unreachable("Invalid access specifier");
+ case Decl::StaticAssert:
+ return StaticAssert;
+ case Decl::Field:
+ return Field;
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ return CXXMethod;
+ case Decl::TypeAlias:
+ return TypeAlias;
+ case Decl::Typedef:
+ return TypeDef;
+ case Decl::Var:
+ return Var;
+ case Decl::Friend:
+ return Friend;
+ case Decl::FunctionTemplate:
+ return FunctionTemplate;
+ case Decl::ObjCMethod:
+ return ObjCMethod;
+ case Decl::ObjCIvar:
+ return ObjCIvar;
+ case Decl::ObjCProperty:
+ return ObjCProperty;
+ }
+ };
+
+ DiffResult DR;
+ auto FirstIt = FirstHashes.begin();
+ auto SecondIt = SecondHashes.begin();
+ while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) {
+ if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() &&
+ FirstIt->second == SecondIt->second) {
+ ++FirstIt;
+ ++SecondIt;
+ continue;
+ }
+
+ DR.FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first;
+ DR.SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first;
+
+ DR.FirstDiffType =
+ DR.FirstDecl ? DifferenceSelector(DR.FirstDecl) : EndOfClass;
+ DR.SecondDiffType =
+ DR.SecondDecl ? DifferenceSelector(DR.SecondDecl) : EndOfClass;
+ return DR;
+ }
+ return DR;
+}
+
+void ODRDiagsEmitter::diagnoseSubMismatchUnexpected(
+ DiffResult &DR, const NamedDecl *FirstRecord, StringRef FirstModule,
+ const NamedDecl *SecondRecord, StringRef SecondModule) const {
+ Diag(FirstRecord->getLocation(),
+ diag::err_module_odr_violation_different_definitions)
+ << FirstRecord << FirstModule.empty() << FirstModule;
+
+ if (DR.FirstDecl) {
+ Diag(DR.FirstDecl->getLocation(), diag::note_first_module_difference)
+ << FirstRecord << DR.FirstDecl->getSourceRange();
+ }
+
+ Diag(SecondRecord->getLocation(),
+ diag::note_module_odr_violation_different_definitions)
+ << SecondModule;
+
+ if (DR.SecondDecl) {
+ Diag(DR.SecondDecl->getLocation(), diag::note_second_module_difference)
+ << DR.SecondDecl->getSourceRange();
+ }
+}
+
+void ODRDiagsEmitter::diagnoseSubMismatchDifferentDeclKinds(
+ DiffResult &DR, const NamedDecl *FirstRecord, StringRef FirstModule,
+ const NamedDecl *SecondRecord, StringRef SecondModule) const {
+ auto GetMismatchedDeclLoc = [](const NamedDecl *Container,
+ ODRMismatchDecl DiffType, const Decl *D) {
+ SourceLocation Loc;
+ SourceRange Range;
+ if (DiffType == EndOfClass) {
+ if (auto *Tag = dyn_cast<TagDecl>(Container))
+ Loc = Tag->getBraceRange().getEnd();
+ else if (auto *IF = dyn_cast<ObjCInterfaceDecl>(Container))
+ Loc = IF->getAtEndRange().getBegin();
+ else
+ Loc = Container->getEndLoc();
+ } else {
+ Loc = D->getLocation();
+ Range = D->getSourceRange();
+ }
+ return std::make_pair(Loc, Range);
+ };
+
+ auto FirstDiagInfo =
+ GetMismatchedDeclLoc(FirstRecord, DR.FirstDiffType, DR.FirstDecl);
+ Diag(FirstDiagInfo.first, diag::err_module_odr_violation_mismatch_decl)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstDiagInfo.second << DR.FirstDiffType;
+
+ auto SecondDiagInfo =
+ GetMismatchedDeclLoc(SecondRecord, DR.SecondDiffType, DR.SecondDecl);
+ Diag(SecondDiagInfo.first, diag::note_module_odr_violation_mismatch_decl)
+ << SecondModule.empty() << SecondModule << SecondDiagInfo.second
+ << DR.SecondDiffType;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const CXXRecordDecl *FirstRecord, const CXXRecordDecl *SecondRecord,
+ const struct CXXRecordDecl::DefinitionData *SecondDD) const {
+ // Multiple different declarations got merged together; tell the user
+ // where they came from.
+ if (FirstRecord == SecondRecord)
+ return false;
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
+
+ const struct CXXRecordDecl::DefinitionData *FirstDD =
+ FirstRecord->DefinitionData;
+ assert(FirstDD && SecondDD && "Definitions without DefinitionData");
+
+ // Diagnostics from DefinitionData are emitted here.
+ if (FirstDD != SecondDD) {
+ // Keep in sync with err_module_odr_violation_definition_data.
+ enum ODRDefinitionDataDifference {
+ NumBases,
+ NumVBases,
+ BaseType,
+ BaseVirtual,
+ BaseAccess,
+ };
+ auto DiagBaseError = [FirstRecord, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRDefinitionDataDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_definition_data)
+ << FirstRecord << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagBaseNote = [&SecondModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRDefinitionDataDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_definition_data)
+ << SecondModule << Range << DiffType;
+ };
+ auto GetSourceRange = [](const struct CXXRecordDecl::DefinitionData *DD) {
+ unsigned NumBases = DD->NumBases;
+ if (NumBases == 0)
+ return SourceRange();
+ ArrayRef<CXXBaseSpecifier> bases = DD->bases();
+ return SourceRange(bases[0].getBeginLoc(),
+ bases[NumBases - 1].getEndLoc());
+ };
+
+ unsigned FirstNumBases = FirstDD->NumBases;
+ unsigned FirstNumVBases = FirstDD->NumVBases;
+ unsigned SecondNumBases = SecondDD->NumBases;
+ unsigned SecondNumVBases = SecondDD->NumVBases;
+ if (FirstNumBases != SecondNumBases) {
+ DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ NumBases)
+ << FirstNumBases;
+ DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ NumBases)
+ << SecondNumBases;
+ return true;
+ }
+
+ if (FirstNumVBases != SecondNumVBases) {
+ DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ NumVBases)
+ << FirstNumVBases;
+ DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ NumVBases)
+ << SecondNumVBases;
+ return true;
+ }
+
+ ArrayRef<CXXBaseSpecifier> FirstBases = FirstDD->bases();
+ ArrayRef<CXXBaseSpecifier> SecondBases = SecondDD->bases();
+ for (unsigned I = 0; I < FirstNumBases; ++I) {
+ const CXXBaseSpecifier FirstBase = FirstBases[I];
+ const CXXBaseSpecifier SecondBase = SecondBases[I];
+ if (computeODRHash(FirstBase.getType()) !=
+ computeODRHash(SecondBase.getType())) {
+ DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseType)
+ << (I + 1) << FirstBase.getType();
+ DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
+ BaseType)
+ << (I + 1) << SecondBase.getType();
+ return true;
+ }
+
+ if (FirstBase.isVirtual() != SecondBase.isVirtual()) {
+ DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseVirtual)
+ << (I + 1) << FirstBase.isVirtual() << FirstBase.getType();
+ DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
+ BaseVirtual)
+ << (I + 1) << SecondBase.isVirtual() << SecondBase.getType();
+ return true;
+ }
+
+ if (FirstBase.getAccessSpecifierAsWritten() !=
+ SecondBase.getAccessSpecifierAsWritten()) {
+ DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseAccess)
+ << (I + 1) << FirstBase.getType()
+ << (int)FirstBase.getAccessSpecifierAsWritten();
+ DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
+ BaseAccess)
+ << (I + 1) << SecondBase.getType()
+ << (int)SecondBase.getAccessSpecifierAsWritten();
+ return true;
+ }
+ }
+ }
+
+ const ClassTemplateDecl *FirstTemplate =
+ FirstRecord->getDescribedClassTemplate();
+ const ClassTemplateDecl *SecondTemplate =
+ SecondRecord->getDescribedClassTemplate();
+
+ assert(!FirstTemplate == !SecondTemplate &&
+ "Both pointers should be null or non-null");
+
+ if (FirstTemplate && SecondTemplate) {
+ ArrayRef<const NamedDecl *> FirstTemplateParams =
+ FirstTemplate->getTemplateParameters()->asArray();
+ ArrayRef<const NamedDecl *> SecondTemplateParams =
+ SecondTemplate->getTemplateParameters()->asArray();
+ assert(FirstTemplateParams.size() == SecondTemplateParams.size() &&
+ "Number of template parameters should be equal.");
+ for (auto Pair : llvm::zip(FirstTemplateParams, SecondTemplateParams)) {
+ const NamedDecl *FirstDecl = std::get<0>(Pair);
+ const NamedDecl *SecondDecl = std::get<1>(Pair);
+ if (computeODRHash(FirstDecl) == computeODRHash(SecondDecl))
+ continue;
+
+ assert(FirstDecl->getKind() == SecondDecl->getKind() &&
+ "Parameter Decl's should be the same kind.");
+
+ enum ODRTemplateDifference {
+ ParamEmptyName,
+ ParamName,
+ ParamSingleDefaultArgument,
+ ParamDifferentDefaultArgument,
+ };
+
+ auto hasDefaultArg = [](const NamedDecl *D) {
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
+ return TTP->hasDefaultArgument() &&
+ !TTP->defaultArgumentWasInherited();
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
+ return NTTP->hasDefaultArgument() &&
+ !NTTP->defaultArgumentWasInherited();
+ auto *TTP = cast<TemplateTemplateParmDecl>(D);
+ return TTP->hasDefaultArgument() && !TTP->defaultArgumentWasInherited();
+ };
+ bool hasFirstArg = hasDefaultArg(FirstDecl);
+ bool hasSecondArg = hasDefaultArg(SecondDecl);
+
+ ODRTemplateDifference ErrDiffType;
+ ODRTemplateDifference NoteDiffType;
+
+ DeclarationName FirstName = FirstDecl->getDeclName();
+ DeclarationName SecondName = SecondDecl->getDeclName();
+
+ if (FirstName != SecondName) {
+ bool FirstNameEmpty =
+ FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo();
+ bool SecondNameEmpty =
+ SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo();
+ ErrDiffType = FirstNameEmpty ? ParamEmptyName : ParamName;
+ NoteDiffType = SecondNameEmpty ? ParamEmptyName : ParamName;
+ } else if (hasFirstArg == hasSecondArg)
+ ErrDiffType = NoteDiffType = ParamDifferentDefaultArgument;
+ else
+ ErrDiffType = NoteDiffType = ParamSingleDefaultArgument;
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_template_parameter)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstDecl->getSourceRange() << ErrDiffType << hasFirstArg
+ << FirstName;
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_template_parameter)
+ << SecondModule << SecondDecl->getSourceRange() << NoteDiffType
+ << hasSecondArg << SecondName;
+ return true;
+ }
+ }
+
+ auto PopulateHashes = [](DeclHashes &Hashes, const RecordDecl *Record,
+ const DeclContext *DC) {
+ for (const Decl *D : Record->decls()) {
+ if (!ODRHash::isSubDeclToBeProcessed(D, DC))
+ continue;
+ Hashes.emplace_back(D, computeODRHash(D));
+ }
+ };
+
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ const DeclContext *DC = FirstRecord;
+ PopulateHashes(FirstHashes, FirstRecord, DC);
+ PopulateHashes(SecondHashes, SecondRecord, DC);
+
+ DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
+ ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+ ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+ const Decl *FirstDecl = DR.FirstDecl;
+ const Decl *SecondDecl = DR.SecondDecl;
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ diagnoseSubMismatchUnexpected(DR, FirstRecord, FirstModule, SecondRecord,
+ SecondModule);
+ return true;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord, FirstModule,
+ SecondRecord, SecondModule);
+ return true;
+ }
+
+ // Used with err_module_odr_violation_record and
+ // note_module_odr_violation_record
+ enum ODRCXXRecordDifference {
+ StaticAssertCondition,
+ StaticAssertMessage,
+ StaticAssertOnlyMessage,
+ MethodName,
+ MethodDeleted,
+ MethodDefaulted,
+ MethodVirtual,
+ MethodStatic,
+ MethodVolatile,
+ MethodConst,
+ MethodInline,
+ MethodParameterSingleDefaultArgument,
+ MethodParameterDifferentDefaultArgument,
+ MethodNoTemplateArguments,
+ MethodDifferentNumberTemplateArguments,
+ MethodDifferentTemplateArgument,
+ MethodSingleBody,
+ MethodDifferentBody,
+ FriendTypeFunction,
+ FriendType,
+ FriendFunction,
+ FunctionTemplateDifferentNumberParameters,
+ FunctionTemplateParameterDifferentKind,
+ FunctionTemplateParameterName,
+ FunctionTemplateParameterSingleDefaultArgument,
+ FunctionTemplateParameterDifferentDefaultArgument,
+ FunctionTemplateParameterDifferentType,
+ FunctionTemplatePackParameter,
+ };
+ auto DiagError = [FirstRecord, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRCXXRecordDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_record)
+ << FirstRecord << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
+ ODRCXXRecordDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_record)
+ << SecondModule << Range << DiffType;
+ };
+
+ assert(FirstDiffType == SecondDiffType);
+ switch (FirstDiffType) {
+ case Other:
+ case EndOfClass:
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ case ObjCMethod:
+ case ObjCIvar:
+ case ObjCProperty:
+ llvm_unreachable("Invalid diff type");
+
+ case StaticAssert: {
+ const StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl);
+ const StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl);
+
+ const Expr *FirstExpr = FirstSA->getAssertExpr();
+ const Expr *SecondExpr = SecondSA->getAssertExpr();
+ unsigned FirstODRHash = computeODRHash(FirstExpr);
+ unsigned SecondODRHash = computeODRHash(SecondExpr);
+ if (FirstODRHash != SecondODRHash) {
+ DiagError(FirstExpr->getBeginLoc(), FirstExpr->getSourceRange(),
+ StaticAssertCondition);
+ DiagNote(SecondExpr->getBeginLoc(), SecondExpr->getSourceRange(),
+ StaticAssertCondition);
+ return true;
+ }
+
+ const StringLiteral *FirstStr = FirstSA->getMessage();
+ const StringLiteral *SecondStr = SecondSA->getMessage();
+ assert((FirstStr || SecondStr) && "Both messages cannot be empty");
+ if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) {
+ SourceLocation FirstLoc, SecondLoc;
+ SourceRange FirstRange, SecondRange;
+ if (FirstStr) {
+ FirstLoc = FirstStr->getBeginLoc();
+ FirstRange = FirstStr->getSourceRange();
+ } else {
+ FirstLoc = FirstSA->getBeginLoc();
+ FirstRange = FirstSA->getSourceRange();
+ }
+ if (SecondStr) {
+ SecondLoc = SecondStr->getBeginLoc();
+ SecondRange = SecondStr->getSourceRange();
+ } else {
+ SecondLoc = SecondSA->getBeginLoc();
+ SecondRange = SecondSA->getSourceRange();
+ }
+ DiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage)
+ << (FirstStr == nullptr);
+ DiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage)
+ << (SecondStr == nullptr);
+ return true;
+ }
+
+ if (FirstStr && SecondStr &&
+ FirstStr->getString() != SecondStr->getString()) {
+ DiagError(FirstStr->getBeginLoc(), FirstStr->getSourceRange(),
+ StaticAssertMessage);
+ DiagNote(SecondStr->getBeginLoc(), SecondStr->getSourceRange(),
+ StaticAssertMessage);
+ return true;
+ }
+ break;
+ }
+
+ case Field: {
+ if (diagnoseSubMismatchField(FirstRecord, FirstModule, SecondModule,
+ cast<FieldDecl>(FirstDecl),
+ cast<FieldDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+
+ case CXXMethod: {
+ enum {
+ DiagMethod,
+ DiagConstructor,
+ DiagDestructor,
+ } FirstMethodType,
+ SecondMethodType;
+ auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl *D) {
+ if (isa<CXXConstructorDecl>(D))
+ return DiagConstructor;
+ if (isa<CXXDestructorDecl>(D))
+ return DiagDestructor;
+ return DiagMethod;
+ };
+ const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl);
+ const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl);
+ FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod);
+ SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod);
+ DeclarationName FirstName = FirstMethod->getDeclName();
+ DeclarationName SecondName = SecondMethod->getDeclName();
+ auto DiagMethodError = [&DiagError, FirstMethod, FirstMethodType,
+ FirstName](ODRCXXRecordDifference DiffType) {
+ return DiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), DiffType)
+ << FirstMethodType << FirstName;
+ };
+ auto DiagMethodNote = [&DiagNote, SecondMethod, SecondMethodType,
+ SecondName](ODRCXXRecordDifference DiffType) {
+ return DiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), DiffType)
+ << SecondMethodType << SecondName;
+ };
+
+ if (FirstMethodType != SecondMethodType || FirstName != SecondName) {
+ DiagMethodError(MethodName);
+ DiagMethodNote(MethodName);
+ return true;
+ }
+
+ const bool FirstDeleted = FirstMethod->isDeletedAsWritten();
+ const bool SecondDeleted = SecondMethod->isDeletedAsWritten();
+ if (FirstDeleted != SecondDeleted) {
+ DiagMethodError(MethodDeleted) << FirstDeleted;
+ DiagMethodNote(MethodDeleted) << SecondDeleted;
+ return true;
+ }
+
+ const bool FirstDefaulted = FirstMethod->isExplicitlyDefaulted();
+ const bool SecondDefaulted = SecondMethod->isExplicitlyDefaulted();
+ if (FirstDefaulted != SecondDefaulted) {
+ DiagMethodError(MethodDefaulted) << FirstDefaulted;
+ DiagMethodNote(MethodDefaulted) << SecondDefaulted;
+ return true;
+ }
+
+ const bool FirstVirtual = FirstMethod->isVirtualAsWritten();
+ const bool SecondVirtual = SecondMethod->isVirtualAsWritten();
+ const bool FirstPure = FirstMethod->isPure();
+ const bool SecondPure = SecondMethod->isPure();
+ if ((FirstVirtual || SecondVirtual) &&
+ (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) {
+ DiagMethodError(MethodVirtual) << FirstPure << FirstVirtual;
+ DiagMethodNote(MethodVirtual) << SecondPure << SecondVirtual;
+ return true;
+ }
+
+ // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging,
+ // FirstDecl is the canonical Decl of SecondDecl, so the storage
+ // class needs to be checked instead.
+ StorageClass FirstStorage = FirstMethod->getStorageClass();
+ StorageClass SecondStorage = SecondMethod->getStorageClass();
+ const bool FirstStatic = FirstStorage == SC_Static;
+ const bool SecondStatic = SecondStorage == SC_Static;
+ if (FirstStatic != SecondStatic) {
+ DiagMethodError(MethodStatic) << FirstStatic;
+ DiagMethodNote(MethodStatic) << SecondStatic;
+ return true;
+ }
+
+ const bool FirstVolatile = FirstMethod->isVolatile();
+ const bool SecondVolatile = SecondMethod->isVolatile();
+ if (FirstVolatile != SecondVolatile) {
+ DiagMethodError(MethodVolatile) << FirstVolatile;
+ DiagMethodNote(MethodVolatile) << SecondVolatile;
+ return true;
+ }
+
+ const bool FirstConst = FirstMethod->isConst();
+ const bool SecondConst = SecondMethod->isConst();
+ if (FirstConst != SecondConst) {
+ DiagMethodError(MethodConst) << FirstConst;
+ DiagMethodNote(MethodConst) << SecondConst;
+ return true;
+ }
+
+ const bool FirstInline = FirstMethod->isInlineSpecified();
+ const bool SecondInline = SecondMethod->isInlineSpecified();
+ if (FirstInline != SecondInline) {
+ DiagMethodError(MethodInline) << FirstInline;
+ DiagMethodNote(MethodInline) << SecondInline;
+ return true;
+ }
+
+ if (diagnoseSubMismatchMethodParameters(Diags, FirstRecord,
+ FirstModule, SecondModule,
+ FirstMethod, SecondMethod))
+ return true;
+
+ for (unsigned I = 0, N = FirstMethod->param_size(); I < N; ++I) {
+ const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
+
+ const Expr *FirstInit = FirstParam->getInit();
+ const Expr *SecondInit = SecondParam->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ DiagMethodError(MethodParameterSingleDefaultArgument)
+ << (I + 1) << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ DiagMethodNote(MethodParameterSingleDefaultArgument)
+ << (I + 1) << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ return true;
+ }
+
+ if (FirstInit && SecondInit &&
+ computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
+ DiagMethodError(MethodParameterDifferentDefaultArgument)
+ << (I + 1) << FirstInit->getSourceRange();
+ DiagMethodNote(MethodParameterDifferentDefaultArgument)
+ << (I + 1) << SecondInit->getSourceRange();
+ return true;
+ }
+ }
+
+ const TemplateArgumentList *FirstTemplateArgs =
+ FirstMethod->getTemplateSpecializationArgs();
+ const TemplateArgumentList *SecondTemplateArgs =
+ SecondMethod->getTemplateSpecializationArgs();
+
+ if ((FirstTemplateArgs && !SecondTemplateArgs) ||
+ (!FirstTemplateArgs && SecondTemplateArgs)) {
+ DiagMethodError(MethodNoTemplateArguments)
+ << (FirstTemplateArgs != nullptr);
+ DiagMethodNote(MethodNoTemplateArguments)
+ << (SecondTemplateArgs != nullptr);
+ return true;
+ }
+
+ if (FirstTemplateArgs && SecondTemplateArgs) {
+ // Remove pack expansions from argument list.
+ auto ExpandTemplateArgumentList = [](const TemplateArgumentList *TAL) {
+ llvm::SmallVector<const TemplateArgument *, 8> ExpandedList;
+ for (const TemplateArgument &TA : TAL->asArray()) {
+ if (TA.getKind() != TemplateArgument::Pack) {
+ ExpandedList.push_back(&TA);
+ continue;
+ }
+ llvm::append_range(ExpandedList,
+ llvm::make_pointer_range(TA.getPackAsArray()));
+ }
+ return ExpandedList;
+ };
+ llvm::SmallVector<const TemplateArgument *, 8> FirstExpandedList =
+ ExpandTemplateArgumentList(FirstTemplateArgs);
+ llvm::SmallVector<const TemplateArgument *, 8> SecondExpandedList =
+ ExpandTemplateArgumentList(SecondTemplateArgs);
+
+ if (FirstExpandedList.size() != SecondExpandedList.size()) {
+ DiagMethodError(MethodDifferentNumberTemplateArguments)
+ << (unsigned)FirstExpandedList.size();
+ DiagMethodNote(MethodDifferentNumberTemplateArguments)
+ << (unsigned)SecondExpandedList.size();
+ return true;
+ }
+
+ for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) {
+ const TemplateArgument &FirstTA = *FirstExpandedList[i],
+ &SecondTA = *SecondExpandedList[i];
+ if (computeODRHash(FirstTA) == computeODRHash(SecondTA))
+ continue;
+
+ DiagMethodError(MethodDifferentTemplateArgument) << FirstTA << i + 1;
+ DiagMethodNote(MethodDifferentTemplateArgument) << SecondTA << i + 1;
+ return true;
+ }
+ }
+
+ // Compute the hash of the method as if it has no body.
+ auto ComputeCXXMethodODRHash = [](const CXXMethodDecl *D) {
+ ODRHash Hasher;
+ Hasher.AddFunctionDecl(D, true /*SkipBody*/);
+ return Hasher.CalculateHash();
+ };
+
+ // Compare the hash generated to the hash stored. A difference means
+ // that a body was present in the original source. Due to merging,
+ // the standard way of detecting a body will not work.
+ const bool HasFirstBody =
+ ComputeCXXMethodODRHash(FirstMethod) != FirstMethod->getODRHash();
+ const bool HasSecondBody =
+ ComputeCXXMethodODRHash(SecondMethod) != SecondMethod->getODRHash();
+
+ if (HasFirstBody != HasSecondBody) {
+ DiagMethodError(MethodSingleBody) << HasFirstBody;
+ DiagMethodNote(MethodSingleBody) << HasSecondBody;
+ return true;
+ }
+
+ if (HasFirstBody && HasSecondBody) {
+ DiagMethodError(MethodDifferentBody);
+ DiagMethodNote(MethodDifferentBody);
+ return true;
+ }
+
+ break;
+ }
+
+ case TypeAlias:
+ case TypeDef: {
+ if (diagnoseSubMismatchTypedef(FirstRecord, FirstModule, SecondModule,
+ cast<TypedefNameDecl>(FirstDecl),
+ cast<TypedefNameDecl>(SecondDecl),
+ FirstDiffType == TypeAlias))
+ return true;
+ break;
+ }
+ case Var: {
+ if (diagnoseSubMismatchVar(FirstRecord, FirstModule, SecondModule,
+ cast<VarDecl>(FirstDecl),
+ cast<VarDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ case Friend: {
+ const FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl);
+ const FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl);
+
+ const NamedDecl *FirstND = FirstFriend->getFriendDecl();
+ const NamedDecl *SecondND = SecondFriend->getFriendDecl();
+
+ TypeSourceInfo *FirstTSI = FirstFriend->getFriendType();
+ TypeSourceInfo *SecondTSI = SecondFriend->getFriendType();
+
+ if (FirstND && SecondND) {
+ DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendFunction)
+ << FirstND;
+ DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
+ FriendFunction)
+ << SecondND;
+ return true;
+ }
+
+ if (FirstTSI && SecondTSI) {
+ QualType FirstFriendType = FirstTSI->getType();
+ QualType SecondFriendType = SecondTSI->getType();
+ assert(computeODRHash(FirstFriendType) !=
+ computeODRHash(SecondFriendType));
+ DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendType)
+ << FirstFriendType;
+ DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
+ FriendType)
+ << SecondFriendType;
+ return true;
+ }
+
+ DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendTypeFunction)
+ << (FirstTSI == nullptr);
+ DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
+ FriendTypeFunction)
+ << (SecondTSI == nullptr);
+ return true;
+ }
+ case FunctionTemplate: {
+ const FunctionTemplateDecl *FirstTemplate =
+ cast<FunctionTemplateDecl>(FirstDecl);
+ const FunctionTemplateDecl *SecondTemplate =
+ cast<FunctionTemplateDecl>(SecondDecl);
+
+ TemplateParameterList *FirstTPL = FirstTemplate->getTemplateParameters();
+ TemplateParameterList *SecondTPL = SecondTemplate->getTemplateParameters();
+
+ auto DiagTemplateError = [&DiagError,
+ FirstTemplate](ODRCXXRecordDifference DiffType) {
+ return DiagError(FirstTemplate->getLocation(),
+ FirstTemplate->getSourceRange(), DiffType)
+ << FirstTemplate;
+ };
+ auto DiagTemplateNote = [&DiagNote,
+ SecondTemplate](ODRCXXRecordDifference DiffType) {
+ return DiagNote(SecondTemplate->getLocation(),
+ SecondTemplate->getSourceRange(), DiffType)
+ << SecondTemplate;
+ };
+
+ if (FirstTPL->size() != SecondTPL->size()) {
+ DiagTemplateError(FunctionTemplateDifferentNumberParameters)
+ << FirstTPL->size();
+ DiagTemplateNote(FunctionTemplateDifferentNumberParameters)
+ << SecondTPL->size();
+ return true;
+ }
+
+ for (unsigned i = 0, e = FirstTPL->size(); i != e; ++i) {
+ NamedDecl *FirstParam = FirstTPL->getParam(i);
+ NamedDecl *SecondParam = SecondTPL->getParam(i);
+
+ if (FirstParam->getKind() != SecondParam->getKind()) {
+ enum {
+ TemplateTypeParameter,
+ NonTypeTemplateParameter,
+ TemplateTemplateParameter,
+ };
+ auto GetParamType = [](NamedDecl *D) {
+ switch (D->getKind()) {
+ default:
+ llvm_unreachable("Unexpected template parameter type");
+ case Decl::TemplateTypeParm:
+ return TemplateTypeParameter;
+ case Decl::NonTypeTemplateParm:
+ return NonTypeTemplateParameter;
+ case Decl::TemplateTemplateParm:
+ return TemplateTemplateParameter;
+ }
+ };
+
+ DiagTemplateError(FunctionTemplateParameterDifferentKind)
+ << (i + 1) << GetParamType(FirstParam);
+ DiagTemplateNote(FunctionTemplateParameterDifferentKind)
+ << (i + 1) << GetParamType(SecondParam);
+ return true;
+ }
+
+ if (FirstParam->getName() != SecondParam->getName()) {
+ DiagTemplateError(FunctionTemplateParameterName)
+ << (i + 1) << (bool)FirstParam->getIdentifier() << FirstParam;
+ DiagTemplateNote(FunctionTemplateParameterName)
+ << (i + 1) << (bool)SecondParam->getIdentifier() << SecondParam;
+ return true;
+ }
+
+ if (isa<TemplateTypeParmDecl>(FirstParam) &&
+ isa<TemplateTypeParmDecl>(SecondParam)) {
+ TemplateTypeParmDecl *FirstTTPD =
+ cast<TemplateTypeParmDecl>(FirstParam);
+ TemplateTypeParmDecl *SecondTTPD =
+ cast<TemplateTypeParmDecl>(SecondParam);
+ bool HasFirstDefaultArgument =
+ FirstTTPD->hasDefaultArgument() &&
+ !FirstTTPD->defaultArgumentWasInherited();
+ bool HasSecondDefaultArgument =
+ SecondTTPD->hasDefaultArgument() &&
+ !SecondTTPD->defaultArgumentWasInherited();
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasFirstDefaultArgument;
+ DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasSecondDefaultArgument;
+ return true;
+ }
+
+ if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
+ QualType FirstType = FirstTTPD->getDefaultArgument();
+ QualType SecondType = SecondTTPD->getDefaultArgument();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << FirstType;
+ DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << SecondType;
+ return true;
+ }
+ }
+
+ if (FirstTTPD->isParameterPack() != SecondTTPD->isParameterPack()) {
+ DiagTemplateError(FunctionTemplatePackParameter)
+ << (i + 1) << FirstTTPD->isParameterPack();
+ DiagTemplateNote(FunctionTemplatePackParameter)
+ << (i + 1) << SecondTTPD->isParameterPack();
+ return true;
+ }
+ }
+
+ if (isa<TemplateTemplateParmDecl>(FirstParam) &&
+ isa<TemplateTemplateParmDecl>(SecondParam)) {
+ TemplateTemplateParmDecl *FirstTTPD =
+ cast<TemplateTemplateParmDecl>(FirstParam);
+ TemplateTemplateParmDecl *SecondTTPD =
+ cast<TemplateTemplateParmDecl>(SecondParam);
+
+ TemplateParameterList *FirstTPL = FirstTTPD->getTemplateParameters();
+ TemplateParameterList *SecondTPL = SecondTTPD->getTemplateParameters();
+
+ auto ComputeTemplateParameterListODRHash =
+ [](const TemplateParameterList *TPL) {
+ assert(TPL);
+ ODRHash Hasher;
+ Hasher.AddTemplateParameterList(TPL);
+ return Hasher.CalculateHash();
+ };
+
+ if (ComputeTemplateParameterListODRHash(FirstTPL) !=
+ ComputeTemplateParameterListODRHash(SecondTPL)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1);
+ DiagTemplateNote(FunctionTemplateParameterDifferentType) << (i + 1);
+ return true;
+ }
+
+ bool HasFirstDefaultArgument =
+ FirstTTPD->hasDefaultArgument() &&
+ !FirstTTPD->defaultArgumentWasInherited();
+ bool HasSecondDefaultArgument =
+ SecondTTPD->hasDefaultArgument() &&
+ !SecondTTPD->defaultArgumentWasInherited();
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasFirstDefaultArgument;
+ DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasSecondDefaultArgument;
+ return true;
+ }
+
+ if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
+ TemplateArgument FirstTA =
+ FirstTTPD->getDefaultArgument().getArgument();
+ TemplateArgument SecondTA =
+ SecondTTPD->getDefaultArgument().getArgument();
+ if (computeODRHash(FirstTA) != computeODRHash(SecondTA)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << FirstTA;
+ DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << SecondTA;
+ return true;
+ }
+ }
+
+ if (FirstTTPD->isParameterPack() != SecondTTPD->isParameterPack()) {
+ DiagTemplateError(FunctionTemplatePackParameter)
+ << (i + 1) << FirstTTPD->isParameterPack();
+ DiagTemplateNote(FunctionTemplatePackParameter)
+ << (i + 1) << SecondTTPD->isParameterPack();
+ return true;
+ }
+ }
+
+ if (isa<NonTypeTemplateParmDecl>(FirstParam) &&
+ isa<NonTypeTemplateParmDecl>(SecondParam)) {
+ NonTypeTemplateParmDecl *FirstNTTPD =
+ cast<NonTypeTemplateParmDecl>(FirstParam);
+ NonTypeTemplateParmDecl *SecondNTTPD =
+ cast<NonTypeTemplateParmDecl>(SecondParam);
+
+ QualType FirstType = FirstNTTPD->getType();
+ QualType SecondType = SecondNTTPD->getType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1);
+ DiagTemplateNote(FunctionTemplateParameterDifferentType) << (i + 1);
+ return true;
+ }
+
+ bool HasFirstDefaultArgument =
+ FirstNTTPD->hasDefaultArgument() &&
+ !FirstNTTPD->defaultArgumentWasInherited();
+ bool HasSecondDefaultArgument =
+ SecondNTTPD->hasDefaultArgument() &&
+ !SecondNTTPD->defaultArgumentWasInherited();
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasFirstDefaultArgument;
+ DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasSecondDefaultArgument;
+ return true;
+ }
+
+ if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
+ Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument();
+ Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument();
+ if (computeODRHash(FirstDefaultArgument) !=
+ computeODRHash(SecondDefaultArgument)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << FirstDefaultArgument;
+ DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << SecondDefaultArgument;
+ return true;
+ }
+ }
+
+ if (FirstNTTPD->isParameterPack() != SecondNTTPD->isParameterPack()) {
+ DiagTemplateError(FunctionTemplatePackParameter)
+ << (i + 1) << FirstNTTPD->isParameterPack();
+ DiagTemplateNote(FunctionTemplatePackParameter)
+ << (i + 1) << SecondNTTPD->isParameterPack();
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule.empty() << SecondModule << FirstDiffType
+ << SecondDecl->getSourceRange();
+ return true;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(const RecordDecl *FirstRecord,
+ const RecordDecl *SecondRecord) const {
+ if (FirstRecord == SecondRecord)
+ return false;
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
+
+ auto PopulateHashes = [](DeclHashes &Hashes, const RecordDecl *Record,
+ const DeclContext *DC) {
+ for (const Decl *D : Record->decls()) {
+ if (!ODRHash::isSubDeclToBeProcessed(D, DC))
+ continue;
+ Hashes.emplace_back(D, computeODRHash(D));
+ }
+ };
+
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ const DeclContext *DC = FirstRecord;
+ PopulateHashes(FirstHashes, FirstRecord, DC);
+ PopulateHashes(SecondHashes, SecondRecord, DC);
+
+ DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
+ ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+ ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+ const Decl *FirstDecl = DR.FirstDecl;
+ const Decl *SecondDecl = DR.SecondDecl;
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ diagnoseSubMismatchUnexpected(DR, FirstRecord, FirstModule, SecondRecord,
+ SecondModule);
+ return true;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord, FirstModule,
+ SecondRecord, SecondModule);
+ return true;
+ }
+
+ assert(FirstDiffType == SecondDiffType);
+ switch (FirstDiffType) {
+ // Already handled.
+ case EndOfClass:
+ case Other:
+ // C++ only, invalid in this context.
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ case StaticAssert:
+ case CXXMethod:
+ case TypeAlias:
+ case Friend:
+ case FunctionTemplate:
+ // Cannot be contained by RecordDecl, invalid in this context.
+ case ObjCMethod:
+ case ObjCIvar:
+ case ObjCProperty:
+ llvm_unreachable("Invalid diff type");
+
+ case Field: {
+ if (diagnoseSubMismatchField(FirstRecord, FirstModule, SecondModule,
+ cast<FieldDecl>(FirstDecl),
+ cast<FieldDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ case TypeDef: {
+ if (diagnoseSubMismatchTypedef(FirstRecord, FirstModule, SecondModule,
+ cast<TypedefNameDecl>(FirstDecl),
+ cast<TypedefNameDecl>(SecondDecl),
+ /*IsTypeAlias=*/false))
+ return true;
+ break;
+ }
+ case Var: {
+ if (diagnoseSubMismatchVar(FirstRecord, FirstModule, SecondModule,
+ cast<VarDecl>(FirstDecl),
+ cast<VarDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ }
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule.empty() << SecondModule << FirstDiffType
+ << SecondDecl->getSourceRange();
+ return true;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const FunctionDecl *FirstFunction,
+ const FunctionDecl *SecondFunction) const {
+ if (FirstFunction == SecondFunction)
+ return false;
+
+ // Keep in sync with select options in err_module_odr_violation_function.
+ enum ODRFunctionDifference {
+ ReturnType,
+ ParameterName,
+ ParameterType,
+ ParameterSingleDefaultArgument,
+ ParameterDifferentDefaultArgument,
+ FunctionBody,
+ };
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstFunction);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondFunction);
+
+ auto DiagError = [FirstFunction, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRFunctionDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_function)
+ << FirstFunction << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
+ ODRFunctionDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_function)
+ << SecondModule << Range << DiffType;
+ };
+
+ if (computeODRHash(FirstFunction->getReturnType()) !=
+ computeODRHash(SecondFunction->getReturnType())) {
+ DiagError(FirstFunction->getReturnTypeSourceRange().getBegin(),
+ FirstFunction->getReturnTypeSourceRange(), ReturnType)
+ << FirstFunction->getReturnType();
+ DiagNote(SecondFunction->getReturnTypeSourceRange().getBegin(),
+ SecondFunction->getReturnTypeSourceRange(), ReturnType)
+ << SecondFunction->getReturnType();
+ return true;
+ }
+
+ assert(FirstFunction->param_size() == SecondFunction->param_size() &&
+ "Merged functions with different number of parameters");
+
+ size_t ParamSize = FirstFunction->param_size();
+ for (unsigned I = 0; I < ParamSize; ++I) {
+ const ParmVarDecl *FirstParam = FirstFunction->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondFunction->getParamDecl(I);
+
+ assert(Context.hasSameType(FirstParam->getType(), SecondParam->getType()) &&
+ "Merged function has different parameter types.");
+
+ if (FirstParam->getDeclName() != SecondParam->getDeclName()) {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterName)
+ << I + 1 << FirstParam->getDeclName();
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterName)
+ << I + 1 << SecondParam->getDeclName();
+ return true;
+ };
+
+ QualType FirstParamType = FirstParam->getType();
+ QualType SecondParamType = SecondParam->getType();
+ if (FirstParamType != SecondParamType &&
+ computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
+ if (const DecayedType *ParamDecayedType =
+ FirstParamType->getAs<DecayedType>()) {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterType)
+ << (I + 1) << FirstParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterType)
+ << (I + 1) << FirstParamType << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterType)
+ << (I + 1) << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterType)
+ << (I + 1) << SecondParamType << false;
+ }
+ return true;
+ }
+
+ const Expr *FirstInit = FirstParam->getInit();
+ const Expr *SecondInit = SecondParam->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterSingleDefaultArgument)
+ << (I + 1) << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterSingleDefaultArgument)
+ << (I + 1) << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ return true;
+ }
+
+ if (FirstInit && SecondInit &&
+ computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterDifferentDefaultArgument)
+ << (I + 1) << FirstInit->getSourceRange();
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterDifferentDefaultArgument)
+ << (I + 1) << SecondInit->getSourceRange();
+ return true;
+ }
+
+ assert(computeODRHash(FirstParam) == computeODRHash(SecondParam) &&
+ "Undiagnosed parameter difference.");
+ }
+
+ // If no error has been generated before now, assume the problem is in
+ // the body and generate a message.
+ DiagError(FirstFunction->getLocation(), FirstFunction->getSourceRange(),
+ FunctionBody);
+ DiagNote(SecondFunction->getLocation(), SecondFunction->getSourceRange(),
+ FunctionBody);
+ return true;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(const EnumDecl *FirstEnum,
+ const EnumDecl *SecondEnum) const {
+ if (FirstEnum == SecondEnum)
+ return false;
+
+ // Keep in sync with select options in err_module_odr_violation_enum.
+ enum ODREnumDifference {
+ SingleScopedEnum,
+ EnumTagKeywordMismatch,
+ SingleSpecifiedType,
+ DifferentSpecifiedTypes,
+ DifferentNumberEnumConstants,
+ EnumConstantName,
+ EnumConstantSingleInitializer,
+ EnumConstantDifferentInitializer,
+ };
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstEnum);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondEnum);
+
+ auto DiagError = [FirstEnum, &FirstModule, this](const auto *DiagAnchor,
+ ODREnumDifference DiffType) {
+ return Diag(DiagAnchor->getLocation(), diag::err_module_odr_violation_enum)
+ << FirstEnum << FirstModule.empty() << FirstModule
+ << DiagAnchor->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [&SecondModule, this](const auto *DiagAnchor,
+ ODREnumDifference DiffType) {
+ return Diag(DiagAnchor->getLocation(), diag::note_module_odr_violation_enum)
+ << SecondModule << DiagAnchor->getSourceRange() << DiffType;
+ };
+
+ if (FirstEnum->isScoped() != SecondEnum->isScoped()) {
+ DiagError(FirstEnum, SingleScopedEnum) << FirstEnum->isScoped();
+ DiagNote(SecondEnum, SingleScopedEnum) << SecondEnum->isScoped();
+ return true;
+ }
+
+ if (FirstEnum->isScoped() && SecondEnum->isScoped()) {
+ if (FirstEnum->isScopedUsingClassTag() !=
+ SecondEnum->isScopedUsingClassTag()) {
+ DiagError(FirstEnum, EnumTagKeywordMismatch)
+ << FirstEnum->isScopedUsingClassTag();
+ DiagNote(SecondEnum, EnumTagKeywordMismatch)
+ << SecondEnum->isScopedUsingClassTag();
+ return true;
+ }
+ }
+
+ QualType FirstUnderlyingType =
+ FirstEnum->getIntegerTypeSourceInfo()
+ ? FirstEnum->getIntegerTypeSourceInfo()->getType()
+ : QualType();
+ QualType SecondUnderlyingType =
+ SecondEnum->getIntegerTypeSourceInfo()
+ ? SecondEnum->getIntegerTypeSourceInfo()->getType()
+ : QualType();
+ if (FirstUnderlyingType.isNull() != SecondUnderlyingType.isNull()) {
+ DiagError(FirstEnum, SingleSpecifiedType) << !FirstUnderlyingType.isNull();
+ DiagNote(SecondEnum, SingleSpecifiedType) << !SecondUnderlyingType.isNull();
+ return true;
+ }
+
+ if (!FirstUnderlyingType.isNull() && !SecondUnderlyingType.isNull()) {
+ if (computeODRHash(FirstUnderlyingType) !=
+ computeODRHash(SecondUnderlyingType)) {
+ DiagError(FirstEnum, DifferentSpecifiedTypes) << FirstUnderlyingType;
+ DiagNote(SecondEnum, DifferentSpecifiedTypes) << SecondUnderlyingType;
+ return true;
+ }
+ }
+
+ // Compare enum constants.
+ using DeclHashes =
+ llvm::SmallVector<std::pair<const EnumConstantDecl *, unsigned>, 4>;
+ auto PopulateHashes = [FirstEnum](DeclHashes &Hashes, const EnumDecl *Enum) {
+ for (const Decl *D : Enum->decls()) {
+ // Due to decl merging, the first EnumDecl is the parent of
+ // Decls in both records.
+ if (!ODRHash::isSubDeclToBeProcessed(D, FirstEnum))
+ continue;
+ assert(isa<EnumConstantDecl>(D) && "Unexpected Decl kind");
+ Hashes.emplace_back(cast<EnumConstantDecl>(D), computeODRHash(D));
+ }
+ };
+ DeclHashes FirstHashes;
+ PopulateHashes(FirstHashes, FirstEnum);
+ DeclHashes SecondHashes;
+ PopulateHashes(SecondHashes, SecondEnum);
+
+ if (FirstHashes.size() != SecondHashes.size()) {
+ DiagError(FirstEnum, DifferentNumberEnumConstants)
+ << (int)FirstHashes.size();
+ DiagNote(SecondEnum, DifferentNumberEnumConstants)
+ << (int)SecondHashes.size();
+ return true;
+ }
+
+ for (unsigned I = 0, N = FirstHashes.size(); I < N; ++I) {
+ if (FirstHashes[I].second == SecondHashes[I].second)
+ continue;
+ const EnumConstantDecl *FirstConstant = FirstHashes[I].first;
+ const EnumConstantDecl *SecondConstant = SecondHashes[I].first;
+
+ if (FirstConstant->getDeclName() != SecondConstant->getDeclName()) {
+ DiagError(FirstConstant, EnumConstantName) << I + 1 << FirstConstant;
+ DiagNote(SecondConstant, EnumConstantName) << I + 1 << SecondConstant;
+ return true;
+ }
+
+ const Expr *FirstInit = FirstConstant->getInitExpr();
+ const Expr *SecondInit = SecondConstant->getInitExpr();
+ if (!FirstInit && !SecondInit)
+ continue;
+
+ if (!FirstInit || !SecondInit) {
+ DiagError(FirstConstant, EnumConstantSingleInitializer)
+ << I + 1 << FirstConstant << (FirstInit != nullptr);
+ DiagNote(SecondConstant, EnumConstantSingleInitializer)
+ << I + 1 << SecondConstant << (SecondInit != nullptr);
+ return true;
+ }
+
+ if (computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
+ DiagError(FirstConstant, EnumConstantDifferentInitializer)
+ << I + 1 << FirstConstant;
+ DiagNote(SecondConstant, EnumConstantDifferentInitializer)
+ << I + 1 << SecondConstant;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const ObjCInterfaceDecl *FirstID, const ObjCInterfaceDecl *SecondID,
+ const struct ObjCInterfaceDecl::DefinitionData *SecondDD) const {
+ // Multiple different declarations got merged together; tell the user
+ // where they came from.
+ if (FirstID == SecondID)
+ return false;
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstID);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondID);
+
+ // Keep in sync with err_module_odr_violation_objc_interface.
+ enum ODRInterfaceDifference {
+ SuperClassType,
+ IVarAccess,
+ };
+
+ auto DiagError = [FirstID, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRInterfaceDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_objc_interface)
+ << FirstID << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
+ ODRInterfaceDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_objc_interface)
+ << SecondModule.empty() << SecondModule << Range << DiffType;
+ };
+
+ const struct ObjCInterfaceDecl::DefinitionData *FirstDD = &FirstID->data();
+ assert(FirstDD && SecondDD && "Definitions without DefinitionData");
+ if (FirstDD != SecondDD) {
+ // Check for matching super class.
+ auto GetSuperClassSourceRange = [](const TypeSourceInfo *SuperInfo,
+ const ObjCInterfaceDecl *ID) {
+ if (!SuperInfo)
+ return ID->getSourceRange();
+ TypeLoc Loc = SuperInfo->getTypeLoc();
+ return SourceRange(Loc.getBeginLoc(), Loc.getEndLoc());
+ };
+
+ ObjCInterfaceDecl *FirstSuperClass = FirstID->getSuperClass();
+ ObjCInterfaceDecl *SecondSuperClass = nullptr;
+ const TypeSourceInfo *FirstSuperInfo = FirstID->getSuperClassTInfo();
+ const TypeSourceInfo *SecondSuperInfo = SecondDD->SuperClassTInfo;
+ if (SecondSuperInfo)
+ SecondSuperClass =
+ SecondSuperInfo->getType()->castAs<ObjCObjectType>()->getInterface();
+
+ if ((FirstSuperClass && SecondSuperClass &&
+ FirstSuperClass->getODRHash() != SecondSuperClass->getODRHash()) ||
+ (FirstSuperClass && !SecondSuperClass) ||
+ (!FirstSuperClass && SecondSuperClass)) {
+ QualType FirstType;
+ if (FirstSuperInfo)
+ FirstType = FirstSuperInfo->getType();
+
+ DiagError(FirstID->getLocation(),
+ GetSuperClassSourceRange(FirstSuperInfo, FirstID),
+ SuperClassType)
+ << (bool)FirstSuperInfo << FirstType;
+
+ QualType SecondType;
+ if (SecondSuperInfo)
+ SecondType = SecondSuperInfo->getType();
+
+ DiagNote(SecondID->getLocation(),
+ GetSuperClassSourceRange(SecondSuperInfo, SecondID),
+ SuperClassType)
+ << (bool)SecondSuperInfo << SecondType;
+ return true;
+ }
+
+ // Check both interfaces reference the same protocols.
+ auto &FirstProtos = FirstID->getReferencedProtocols();
+ auto &SecondProtos = SecondDD->ReferencedProtocols;
+ if (diagnoseSubMismatchProtocols(FirstProtos, FirstID, FirstModule,
+ SecondProtos, SecondID, SecondModule))
+ return true;
+ }
+
+ auto PopulateHashes = [](DeclHashes &Hashes, const ObjCInterfaceDecl *ID,
+ const DeclContext *DC) {
+ for (auto *D : ID->decls()) {
+ if (!ODRHash::isSubDeclToBeProcessed(D, DC))
+ continue;
+ Hashes.emplace_back(D, computeODRHash(D));
+ }
+ };
+
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ // Use definition as DeclContext because definitions are merged when
+ // DeclContexts are merged and separate when DeclContexts are separate.
+ PopulateHashes(FirstHashes, FirstID, FirstID->getDefinition());
+ PopulateHashes(SecondHashes, SecondID, SecondID->getDefinition());
+
+ DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
+ ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+ ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+ const Decl *FirstDecl = DR.FirstDecl;
+ const Decl *SecondDecl = DR.SecondDecl;
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ diagnoseSubMismatchUnexpected(DR, FirstID, FirstModule, SecondID,
+ SecondModule);
+ return true;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ diagnoseSubMismatchDifferentDeclKinds(DR, FirstID, FirstModule, SecondID,
+ SecondModule);
+ return true;
+ }
+
+ assert(FirstDiffType == SecondDiffType);
+ switch (FirstDiffType) {
+ // Already handled.
+ case EndOfClass:
+ case Other:
+ // Cannot be contained by ObjCInterfaceDecl, invalid in this context.
+ case Field:
+ case TypeDef:
+ case Var:
+ // C++ only, invalid in this context.
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ case StaticAssert:
+ case CXXMethod:
+ case TypeAlias:
+ case Friend:
+ case FunctionTemplate:
+ llvm_unreachable("Invalid diff type");
+
+ case ObjCMethod: {
+ if (diagnoseSubMismatchObjCMethod(FirstID, FirstModule, SecondModule,
+ cast<ObjCMethodDecl>(FirstDecl),
+ cast<ObjCMethodDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ case ObjCIvar: {
+ if (diagnoseSubMismatchField(FirstID, FirstModule, SecondModule,
+ cast<FieldDecl>(FirstDecl),
+ cast<FieldDecl>(SecondDecl)))
+ return true;
+
+ // Check if the access match.
+ const ObjCIvarDecl *FirstIvar = cast<ObjCIvarDecl>(FirstDecl);
+ const ObjCIvarDecl *SecondIvar = cast<ObjCIvarDecl>(SecondDecl);
+ if (FirstIvar->getCanonicalAccessControl() !=
+ SecondIvar->getCanonicalAccessControl()) {
+ DiagError(FirstIvar->getLocation(), FirstIvar->getSourceRange(),
+ IVarAccess)
+ << FirstIvar->getName()
+ << (int)FirstIvar->getCanonicalAccessControl();
+ DiagNote(SecondIvar->getLocation(), SecondIvar->getSourceRange(),
+ IVarAccess)
+ << SecondIvar->getName()
+ << (int)SecondIvar->getCanonicalAccessControl();
+ return true;
+ }
+ break;
+ }
+ case ObjCProperty: {
+ if (diagnoseSubMismatchObjCProperty(FirstID, FirstModule, SecondModule,
+ cast<ObjCPropertyDecl>(FirstDecl),
+ cast<ObjCPropertyDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ }
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstID << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule << FirstDiffType << SecondDecl->getSourceRange();
+ return true;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const ObjCProtocolDecl *FirstProtocol,
+ const ObjCProtocolDecl *SecondProtocol,
+ const struct ObjCProtocolDecl::DefinitionData *SecondDD) const {
+ if (FirstProtocol == SecondProtocol)
+ return false;
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstProtocol);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondProtocol);
+
+ const ObjCProtocolDecl::DefinitionData *FirstDD = &FirstProtocol->data();
+ assert(FirstDD && SecondDD && "Definitions without DefinitionData");
+ // Diagnostics from ObjCProtocol DefinitionData are emitted here.
+ if (FirstDD != SecondDD) {
+ // Check both protocols reference the same protocols.
+ const ObjCProtocolList &FirstProtocols =
+ FirstProtocol->getReferencedProtocols();
+ const ObjCProtocolList &SecondProtocols = SecondDD->ReferencedProtocols;
+ if (diagnoseSubMismatchProtocols(FirstProtocols, FirstProtocol, FirstModule,
+ SecondProtocols, SecondProtocol,
+ SecondModule))
+ return true;
+ }
+
+ auto PopulateHashes = [](DeclHashes &Hashes, const ObjCProtocolDecl *ID,
+ const DeclContext *DC) {
+ for (const Decl *D : ID->decls()) {
+ if (!ODRHash::isSubDeclToBeProcessed(D, DC))
+ continue;
+ Hashes.emplace_back(D, computeODRHash(D));
+ }
+ };
+
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ // Use definition as DeclContext because definitions are merged when
+ // DeclContexts are merged and separate when DeclContexts are separate.
+ PopulateHashes(FirstHashes, FirstProtocol, FirstProtocol->getDefinition());
+ PopulateHashes(SecondHashes, SecondProtocol, SecondProtocol->getDefinition());
+
+ DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
+ ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+ ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+ const Decl *FirstDecl = DR.FirstDecl;
+ const Decl *SecondDecl = DR.SecondDecl;
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ diagnoseSubMismatchUnexpected(DR, FirstProtocol, FirstModule,
+ SecondProtocol, SecondModule);
+ return true;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ diagnoseSubMismatchDifferentDeclKinds(DR, FirstProtocol, FirstModule,
+ SecondProtocol, SecondModule);
+ return true;
+ }
+
+ assert(FirstDiffType == SecondDiffType);
+ switch (FirstDiffType) {
+ // Already handled.
+ case EndOfClass:
+ case Other:
+ // Cannot be contained by ObjCProtocolDecl, invalid in this context.
+ case Field:
+ case TypeDef:
+ case Var:
+ case ObjCIvar:
+ // C++ only, invalid in this context.
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ case StaticAssert:
+ case CXXMethod:
+ case TypeAlias:
+ case Friend:
+ case FunctionTemplate:
+ llvm_unreachable("Invalid diff type");
+ case ObjCMethod: {
+ if (diagnoseSubMismatchObjCMethod(FirstProtocol, FirstModule, SecondModule,
+ cast<ObjCMethodDecl>(FirstDecl),
+ cast<ObjCMethodDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ case ObjCProperty: {
+ if (diagnoseSubMismatchObjCProperty(FirstProtocol, FirstModule,
+ SecondModule,
+ cast<ObjCPropertyDecl>(FirstDecl),
+ cast<ObjCPropertyDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ }
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstProtocol << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule.empty() << SecondModule << FirstDiffType
+ << SecondDecl->getSourceRange();
+ return true;
+}
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 04cbb09356d7..3374b49f5d8e 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -72,7 +72,10 @@ void ODRHash::AddDeclarationNameImpl(DeclarationName Name) {
AddBoolean(S.isUnarySelector());
unsigned NumArgs = S.getNumArgs();
ID.AddInteger(NumArgs);
- for (unsigned i = 0; i < NumArgs; ++i) {
+ // Compare all selector slots. For selectors with arguments it means all arg
+ // slots. And if there are no arguments, compare the first-and-only slot.
+ unsigned SlotsToCheck = NumArgs > 0 ? NumArgs : 1;
+ for (unsigned i = 0; i < SlotsToCheck; ++i) {
const IdentifierInfo *II = S.getIdentifierInfoForSlot(i);
AddBoolean(II);
if (II) {
@@ -169,8 +172,14 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) {
AddDecl(TA.getAsDecl());
break;
case TemplateArgument::NullPtr:
- case TemplateArgument::Integral:
+ ID.AddPointer(nullptr);
break;
+ case TemplateArgument::Integral: {
+ // There are integrals (e.g.: _BitInt(128)) that cannot be represented as
+ // any builtin integral type, so we use the hash of APSInt instead.
+ TA.getAsIntegral().Profile(ID);
+ break;
+ }
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
AddTemplateName(TA.getAsTemplateOrTemplatePattern());
@@ -334,6 +343,20 @@ public:
Inherited::VisitFieldDecl(D);
}
+ void VisitObjCIvarDecl(const ObjCIvarDecl *D) {
+ ID.AddInteger(D->getCanonicalAccessControl());
+ Inherited::VisitObjCIvarDecl(D);
+ }
+
+ void VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
+ ID.AddInteger(D->getPropertyAttributes());
+ ID.AddInteger(D->getPropertyImplementation());
+ AddQualType(D->getType());
+ AddDecl(D);
+
+ Inherited::VisitObjCPropertyDecl(D);
+ }
+
void VisitFunctionDecl(const FunctionDecl *D) {
// Handled by the ODRHash for FunctionDecl
ID.AddInteger(D->getODRHash());
@@ -347,6 +370,64 @@ public:
Inherited::VisitCXXMethodDecl(D);
}
+ void VisitObjCMethodDecl(const ObjCMethodDecl *Method) {
+ ID.AddInteger(Method->getDeclKind());
+ Hash.AddBoolean(Method->isInstanceMethod()); // false if class method
+ Hash.AddBoolean(Method->isPropertyAccessor());
+ Hash.AddBoolean(Method->isVariadic());
+ Hash.AddBoolean(Method->isSynthesizedAccessorStub());
+ Hash.AddBoolean(Method->isDefined());
+ Hash.AddBoolean(Method->isOverriding());
+ Hash.AddBoolean(Method->isDirectMethod());
+ Hash.AddBoolean(Method->isThisDeclarationADesignatedInitializer());
+ Hash.AddBoolean(Method->hasSkippedBody());
+
+ ID.AddInteger(Method->getImplementationControl());
+ ID.AddInteger(Method->getMethodFamily());
+ ImplicitParamDecl *Cmd = Method->getCmdDecl();
+ Hash.AddBoolean(Cmd);
+ if (Cmd)
+ ID.AddInteger(Cmd->getParameterKind());
+
+ ImplicitParamDecl *Self = Method->getSelfDecl();
+ Hash.AddBoolean(Self);
+ if (Self)
+ ID.AddInteger(Self->getParameterKind());
+
+ AddDecl(Method);
+
+ AddQualType(Method->getReturnType());
+ ID.AddInteger(Method->param_size());
+ for (auto Param : Method->parameters())
+ Hash.AddSubDecl(Param);
+
+ if (Method->hasBody()) {
+ const bool IsDefinition = Method->isThisDeclarationADefinition();
+ Hash.AddBoolean(IsDefinition);
+ if (IsDefinition) {
+ Stmt *Body = Method->getBody();
+ Hash.AddBoolean(Body);
+ if (Body)
+ AddStmt(Body);
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : Method->decls())
+ if (ODRHash::isSubDeclToBeProcessed(SubDecl, Method))
+ Decls.push_back(SubDecl);
+
+ ID.AddInteger(Decls.size());
+ for (auto SubDecl : Decls)
+ Hash.AddSubDecl(SubDecl);
+ }
+ } else {
+ Hash.AddBoolean(false);
+ }
+
+ Inherited::VisitObjCMethodDecl(Method);
+ }
+
void VisitTypedefNameDecl(const TypedefNameDecl *D) {
AddQualType(D->getUnderlyingType());
@@ -441,7 +522,7 @@ public:
// Only allow a small portion of Decl's to be processed. Remove this once
// all Decl's can be handled.
-bool ODRHash::isDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
+bool ODRHash::isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
if (D->isImplicit()) return false;
if (D->getDeclContext() != Parent) return false;
@@ -460,6 +541,9 @@ bool ODRHash::isDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
case Decl::TypeAlias:
case Decl::Typedef:
case Decl::Var:
+ case Decl::ObjCMethod:
+ case Decl::ObjCIvar:
+ case Decl::ObjCProperty:
return true;
}
}
@@ -488,7 +572,7 @@ void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
// accurate count of Decl's.
llvm::SmallVector<const Decl *, 16> Decls;
for (Decl *SubDecl : Record->decls()) {
- if (isDeclToBeProcessed(SubDecl, Record)) {
+ if (isSubDeclToBeProcessed(SubDecl, Record)) {
Decls.push_back(SubDecl);
if (auto *Function = dyn_cast<FunctionDecl>(SubDecl)) {
// Compute/Preload ODRHash into FunctionDecl.
@@ -517,6 +601,51 @@ void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
}
}
+void ODRHash::AddRecordDecl(const RecordDecl *Record) {
+ assert(!isa<CXXRecordDecl>(Record) &&
+ "For CXXRecordDecl should call AddCXXRecordDecl.");
+ AddDecl(Record);
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : Record->decls()) {
+ if (isSubDeclToBeProcessed(SubDecl, Record))
+ Decls.push_back(SubDecl);
+ }
+
+ ID.AddInteger(Decls.size());
+ for (const Decl *SubDecl : Decls)
+ AddSubDecl(SubDecl);
+}
+
+void ODRHash::AddObjCInterfaceDecl(const ObjCInterfaceDecl *IF) {
+ AddDecl(IF);
+
+ auto *SuperClass = IF->getSuperClass();
+ AddBoolean(SuperClass);
+ if (SuperClass)
+ ID.AddInteger(SuperClass->getODRHash());
+
+ // Hash referenced protocols.
+ ID.AddInteger(IF->getReferencedProtocols().size());
+ for (const ObjCProtocolDecl *RefP : IF->protocols()) {
+ // Hash the name only as a referenced protocol can be a forward declaration.
+ AddDeclarationName(RefP->getDeclName());
+ }
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : IF->decls())
+ if (isSubDeclToBeProcessed(SubDecl, IF))
+ Decls.push_back(SubDecl);
+
+ ID.AddInteger(Decls.size());
+ for (auto *SubDecl : Decls)
+ AddSubDecl(SubDecl);
+}
+
void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
bool SkipBody) {
assert(Function && "Expecting non-null pointer.");
@@ -564,7 +693,7 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
AddQualType(Function->getReturnType());
ID.AddInteger(Function->param_size());
- for (auto Param : Function->parameters())
+ for (auto *Param : Function->parameters())
AddSubDecl(Param);
if (SkipBody) {
@@ -589,7 +718,7 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
// accurate count of Decl's.
llvm::SmallVector<const Decl *, 16> Decls;
for (Decl *SubDecl : Function->decls()) {
- if (isDeclToBeProcessed(SubDecl, Function)) {
+ if (isSubDeclToBeProcessed(SubDecl, Function)) {
Decls.push_back(SubDecl);
}
}
@@ -615,7 +744,7 @@ void ODRHash::AddEnumDecl(const EnumDecl *Enum) {
// accurate count of Decl's.
llvm::SmallVector<const Decl *, 16> Decls;
for (Decl *SubDecl : Enum->decls()) {
- if (isDeclToBeProcessed(SubDecl, Enum)) {
+ if (isSubDeclToBeProcessed(SubDecl, Enum)) {
assert(isa<EnumConstantDecl>(SubDecl) && "Unexpected Decl");
Decls.push_back(SubDecl);
}
@@ -628,6 +757,31 @@ void ODRHash::AddEnumDecl(const EnumDecl *Enum) {
}
+void ODRHash::AddObjCProtocolDecl(const ObjCProtocolDecl *P) {
+ AddDecl(P);
+
+ // Hash referenced protocols.
+ ID.AddInteger(P->getReferencedProtocols().size());
+ for (const ObjCProtocolDecl *RefP : P->protocols()) {
+ // Hash the name only as a referenced protocol can be a forward declaration.
+ AddDeclarationName(RefP->getDeclName());
+ }
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : P->decls()) {
+ if (isSubDeclToBeProcessed(SubDecl, P)) {
+ Decls.push_back(SubDecl);
+ }
+ }
+
+ ID.AddInteger(Decls.size());
+ for (auto *SubDecl : Decls) {
+ AddSubDecl(SubDecl);
+ }
+}
+
void ODRHash::AddDecl(const Decl *D) {
assert(D && "Expecting non-null pointer.");
D = D->getCanonicalDecl();
@@ -671,7 +825,7 @@ public:
}
}
- void AddDecl(Decl *D) {
+ void AddDecl(const Decl *D) {
Hash.AddBoolean(D);
if (D) {
Hash.AddDecl(D);
@@ -861,7 +1015,7 @@ public:
ID.AddInteger(T->isConstrained());
if (T->isConstrained()) {
AddDecl(T->getTypeConstraintConcept());
- ID.AddInteger(T->getNumArgs());
+ ID.AddInteger(T->getTypeConstraintArguments().size());
for (const auto &TA : T->getTypeConstraintArguments())
Hash.AddTemplateArgument(TA);
}
@@ -934,7 +1088,7 @@ public:
auto Protocols = T->getProtocols();
ID.AddInteger(Protocols.size());
- for (auto Protocol : Protocols) {
+ for (auto *Protocol : Protocols) {
AddDecl(Protocol);
}
@@ -952,7 +1106,7 @@ public:
AddDecl(T->getDecl());
auto Protocols = T->getProtocols();
ID.AddInteger(Protocols.size());
- for (auto Protocol : Protocols) {
+ for (auto *Protocol : Protocols) {
AddDecl(Protocol);
}
@@ -995,13 +1149,13 @@ public:
void
VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
- AddType(T->getReplacedParameter());
+ AddDecl(T->getAssociatedDecl());
Hash.AddTemplateArgument(T->getArgumentPack());
VisitType(T);
}
void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
- AddType(T->getReplacedParameter());
+ AddDecl(T->getAssociatedDecl());
AddQualType(T->getReplacementType());
VisitType(T);
}
@@ -1015,7 +1169,7 @@ public:
void VisitEnumType(const EnumType *T) { VisitTagType(T); }
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
- ID.AddInteger(T->getNumArgs());
+ ID.AddInteger(T->template_arguments().size());
for (const auto &TA : T->template_arguments()) {
Hash.AddTemplateArgument(TA);
}
@@ -1061,7 +1215,7 @@ public:
VisitType(T);
}
void VisitTypeOfType(const TypeOfType *T) {
- AddQualType(T->getUnderlyingType());
+ AddQualType(T->getUnmodifiedType());
VisitType(T);
}
@@ -1080,7 +1234,7 @@ public:
const DependentTemplateSpecializationType *T) {
AddIdentifierInfo(T->getIdentifier());
AddNestedNameSpecifier(T->getQualifier());
- ID.AddInteger(T->getNumArgs());
+ ID.AddInteger(T->template_arguments().size());
for (const auto &TA : T->template_arguments()) {
Hash.AddTemplateArgument(TA);
}
diff --git a/clang/lib/AST/OSLog.cpp b/clang/lib/AST/OSLog.cpp
index 40fa8c3802c3..5e320416b30d 100644
--- a/clang/lib/AST/OSLog.cpp
+++ b/clang/lib/AST/OSLog.cpp
@@ -8,6 +8,7 @@
#include "clang/AST/FormatString.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/SmallBitVector.h"
+#include <optional>
using namespace clang;
@@ -20,11 +21,11 @@ class OSLogFormatStringHandler
private:
struct ArgData {
const Expr *E = nullptr;
- Optional<OSLogBufferItem::Kind> Kind;
- Optional<unsigned> Size;
- Optional<const Expr *> Count;
- Optional<const Expr *> Precision;
- Optional<const Expr *> FieldWidth;
+ std::optional<OSLogBufferItem::Kind> Kind;
+ std::optional<unsigned> Size;
+ std::optional<const Expr *> Count;
+ std::optional<const Expr *> Precision;
+ std::optional<const Expr *> FieldWidth;
unsigned char Flags = 0;
StringRef MaskType;
};
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index dc2d90e366bc..2e88c08ae789 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
+#include <optional>
using namespace clang;
using namespace llvm;
@@ -102,6 +103,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPNocontextClause *>(C);
case OMPC_filter:
return static_cast<const OMPFilterClause *>(C);
+ case OMPC_ompx_dyn_cgroup_mem:
+ return static_cast<const OMPXDynCGroupMemClause *>(C);
case OMPC_default:
case OMPC_proc_bind:
case OMPC_safelen:
@@ -152,6 +155,9 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
@@ -251,6 +257,9 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
@@ -307,7 +316,7 @@ OMPClause::child_range OMPNumTasksClause::used_children() {
OMPClause::child_range OMPFinalClause::used_children() {
if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
return child_range(C, C + 1);
- return child_range(&Condition, &Condition + 1);
+ return children();
}
OMPClause::child_range OMPPriorityClause::used_children() {
@@ -319,13 +328,13 @@ OMPClause::child_range OMPPriorityClause::used_children() {
OMPClause::child_range OMPNovariantsClause::used_children() {
if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
return child_range(C, C + 1);
- return child_range(&Condition, &Condition + 1);
+ return children();
}
OMPClause::child_range OMPNocontextClause::used_children() {
if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
return child_range(C, C + 1);
- return child_range(&Condition, &Condition + 1);
+ return children();
}
OMPOrderedClause *OMPOrderedClause::Create(const ASTContext &C, Expr *Num,
@@ -361,7 +370,7 @@ void OMPOrderedClause::setLoopNumIterations(unsigned NumLoop,
}
ArrayRef<Expr *> OMPOrderedClause::getLoopNumIterations() const {
- return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumberOfLoops);
+ return llvm::ArrayRef(getTrailingObjects<Expr *>(), NumberOfLoops);
}
void OMPOrderedClause::setLoopCounter(unsigned NumLoop, Expr *Counter) {
@@ -1127,7 +1136,7 @@ OMPMapClause *OMPMapClause::Create(
const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
ArrayRef<ValueDecl *> Declarations,
MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs,
- ArrayRef<OpenMPMapModifierKind> MapModifiers,
+ Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapModifiers,
ArrayRef<SourceLocation> MapModifiersLoc,
NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId,
OpenMPMapClauseKind Type, bool TypeIsImplicit, SourceLocation TypeLoc) {
@@ -1150,7 +1159,7 @@ OMPMapClause *OMPMapClause::Create(
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ 2 * Sizes.NumVars + 1, Sizes.NumUniqueDeclarations,
Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
Sizes.NumComponents));
OMPMapClause *Clause = new (Mem)
@@ -1159,6 +1168,7 @@ OMPMapClause *OMPMapClause::Create(
Clause->setVarRefs(Vars);
Clause->setUDMapperRefs(UDMapperRefs);
+ Clause->setIteratorModifier(IteratorModifier);
Clause->setClauseInfo(Declarations, ComponentLists);
Clause->setMapType(Type);
Clause->setMapLoc(TypeLoc);
@@ -1171,10 +1181,12 @@ OMPMapClause::CreateEmpty(const ASTContext &C,
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ 2 * Sizes.NumVars + 1, Sizes.NumUniqueDeclarations,
Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
Sizes.NumComponents));
- return new (Mem) OMPMapClause(Sizes);
+ OMPMapClause *Clause = new (Mem) OMPMapClause(Sizes);
+ Clause->setIteratorModifier(nullptr);
+ return Clause;
}
OMPToClause *OMPToClause::Create(
@@ -1626,18 +1638,19 @@ OMPAffinityClause *OMPAffinityClause::CreateEmpty(const ASTContext &C,
}
OMPInitClause *OMPInitClause::Create(const ASTContext &C, Expr *InteropVar,
- ArrayRef<Expr *> PrefExprs, bool IsTarget,
- bool IsTargetSync, SourceLocation StartLoc,
+ OMPInteropInfo &InteropInfo,
+ SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation VarLoc,
SourceLocation EndLoc) {
- void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(PrefExprs.size() + 1));
- auto *Clause =
- new (Mem) OMPInitClause(IsTarget, IsTargetSync, StartLoc, LParenLoc,
- VarLoc, EndLoc, PrefExprs.size() + 1);
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<Expr *>(InteropInfo.PreferTypes.size() + 1));
+ auto *Clause = new (Mem) OMPInitClause(
+ InteropInfo.IsTarget, InteropInfo.IsTargetSync, StartLoc, LParenLoc,
+ VarLoc, EndLoc, InteropInfo.PreferTypes.size() + 1);
Clause->setInteropVar(InteropVar);
- llvm::copy(PrefExprs, Clause->getTrailingObjects<Expr *>() + 1);
+ llvm::copy(InteropInfo.PreferTypes, Clause->getTrailingObjects<Expr *>() + 1);
return Clause;
}
@@ -1701,7 +1714,7 @@ void OMPClausePrinter::VisitOMPSimdlenClause(OMPSimdlenClause *Node) {
void OMPClausePrinter::VisitOMPSizesClause(OMPSizesClause *Node) {
OS << "sizes(";
bool First = true;
- for (auto Size : Node->getSizesRefs()) {
+ for (auto *Size : Node->getSizesRefs()) {
if (!First)
OS << ", ";
Size->printPretty(OS, nullptr, Policy, 0);
@@ -1780,6 +1793,22 @@ void OMPClausePrinter::VisitOMPAtomicDefaultMemOrderClause(
<< ")";
}
+void OMPClausePrinter::VisitOMPAtClause(OMPAtClause *Node) {
+ OS << "at(" << getOpenMPSimpleClauseTypeName(OMPC_at, Node->getAtKind())
+ << ")";
+}
+
+void OMPClausePrinter::VisitOMPSeverityClause(OMPSeverityClause *Node) {
+ OS << "severity("
+ << getOpenMPSimpleClauseTypeName(OMPC_severity, Node->getSeverityKind())
+ << ")";
+}
+
+void OMPClausePrinter::VisitOMPMessageClause(OMPMessageClause *Node) {
+ OS << "message(\""
+ << cast<StringLiteral>(Node->getMessageString())->getString() << "\")";
+}
+
void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
OS << "schedule(";
if (Node->getFirstScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown) {
@@ -1904,12 +1933,22 @@ void OMPClausePrinter::VisitOMPPriorityClause(OMPPriorityClause *Node) {
void OMPClausePrinter::VisitOMPGrainsizeClause(OMPGrainsizeClause *Node) {
OS << "grainsize(";
+ OpenMPGrainsizeClauseModifier Modifier = Node->getModifier();
+ if (Modifier != OMPC_GRAINSIZE_unknown) {
+ OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Modifier)
+ << ": ";
+ }
Node->getGrainsize()->printPretty(OS, nullptr, Policy, 0);
OS << ")";
}
void OMPClausePrinter::VisitOMPNumTasksClause(OMPNumTasksClause *Node) {
OS << "num_tasks(";
+ OpenMPNumTasksClauseModifier Modifier = Node->getModifier();
+ if (Modifier != OMPC_NUMTASKS_unknown) {
+ OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Modifier)
+ << ": ";
+ }
Node->getNumTasks()->printPretty(OS, nullptr, Policy, 0);
OS << ")";
}
@@ -2215,16 +2254,27 @@ static void PrintMapper(raw_ostream &OS, T *Node,
OS << Node->getMapperIdInfo() << ')';
}
+template <typename T>
+static void PrintIterator(raw_ostream &OS, T *Node,
+ const PrintingPolicy &Policy) {
+ if (Expr *IteratorModifier = Node->getIteratorModifier())
+ IteratorModifier->printPretty(OS, nullptr, Policy);
+}
+
void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) {
if (!Node->varlist_empty()) {
OS << "map(";
if (Node->getMapType() != OMPC_MAP_unknown) {
for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) {
if (Node->getMapTypeModifier(I) != OMPC_MAP_MODIFIER_unknown) {
- OS << getOpenMPSimpleClauseTypeName(OMPC_map,
- Node->getMapTypeModifier(I));
- if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_mapper)
- PrintMapper(OS, Node, Policy);
+ if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_iterator) {
+ PrintIterator(OS, Node, Policy);
+ } else {
+ OS << getOpenMPSimpleClauseTypeName(OMPC_map,
+ Node->getMapTypeModifier(I));
+ if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_mapper)
+ PrintMapper(OS, Node, Policy);
+ }
OS << ',';
}
}
@@ -2337,8 +2387,12 @@ void OMPClausePrinter::VisitOMPNontemporalClause(OMPNontemporalClause *Node) {
}
void OMPClausePrinter::VisitOMPOrderClause(OMPOrderClause *Node) {
- OS << "order(" << getOpenMPSimpleClauseTypeName(OMPC_order, Node->getKind())
- << ")";
+ OS << "order(";
+ if (Node->getModifier() != OMPC_ORDER_MODIFIER_unknown) {
+ OS << getOpenMPSimpleClauseTypeName(OMPC_order, Node->getModifier());
+ OS << ": ";
+ }
+ OS << getOpenMPSimpleClauseTypeName(OMPC_order, Node->getKind()) << ")";
}
void OMPClausePrinter::VisitOMPInclusiveClause(OMPInclusiveClause *Node) {
@@ -2403,6 +2457,13 @@ void OMPClausePrinter::VisitOMPBindClause(OMPBindClause *Node) {
<< ")";
}
+void OMPClausePrinter::VisitOMPXDynCGroupMemClause(
+ OMPXDynCGroupMemClause *Node) {
+ OS << "ompx_dyn_cgroup_mem(";
+ Node->getSize()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
VariantMatchInfo &VMI) const {
for (const OMPTraitSet &Set : Sets) {
@@ -2417,7 +2478,7 @@ void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
TraitProperty::user_condition_unknown &&
"Ill-formed user condition, expected unknown trait property!");
- if (Optional<APSInt> CondVal =
+ if (std::optional<APSInt> CondVal =
Selector.ScoreOrCondition->getIntegerConstantExpr(ASTCtx))
VMI.addTrait(CondVal->isZero() ? TraitProperty::user_condition_false
: TraitProperty::user_condition_true,
@@ -2427,7 +2488,7 @@ void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
continue;
}
- Optional<llvm::APSInt> Score;
+ std::optional<llvm::APSInt> Score;
llvm::APInt *ScorePtr = nullptr;
if (Selector.ScoreOrCondition) {
if ((Score = Selector.ScoreOrCondition->getIntegerConstantExpr(ASTCtx)))
diff --git a/clang/lib/AST/ParentMap.cpp b/clang/lib/AST/ParentMap.cpp
index da21e573c320..3d6a1cc84c7b 100644
--- a/clang/lib/AST/ParentMap.cpp
+++ b/clang/lib/AST/ParentMap.cpp
@@ -33,9 +33,11 @@ static void BuildParentMap(MapTy& M, Stmt* S,
switch (S->getStmtClass()) {
case Stmt::PseudoObjectExprClass: {
- assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
+ if (OVMode == OV_Opaque && M[POE->getSyntacticForm()])
+ break;
+
// If we are rebuilding the map, clear out any existing state.
if (M[POE->getSyntacticForm()])
for (Stmt *SubStmt : S->children())
diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp
index e0d4700e4b10..21cfd5b1de6e 100644
--- a/clang/lib/AST/ParentMapContext.cpp
+++ b/clang/lib/AST/ParentMapContext.cpp
@@ -99,7 +99,7 @@ class ParentMapContext::ParentMap {
return llvm::ArrayRef<DynTypedNode>();
}
if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
- return llvm::makeArrayRef(*V);
+ return llvm::ArrayRef(*V);
}
return getSingleDynTypedNodeFromParentMap(I->second);
}
@@ -252,7 +252,7 @@ public:
const auto *S = It->second.dyn_cast<const Stmt *>();
if (!S) {
if (auto *Vec = It->second.dyn_cast<ParentVector *>())
- return llvm::makeArrayRef(*Vec);
+ return llvm::ArrayRef(*Vec);
return getSingleDynTypedNodeFromParentMap(It->second);
}
const auto *P = dyn_cast<Expr>(S);
@@ -265,16 +265,6 @@ public:
}
};
-template <typename Tuple, std::size_t... Is>
-auto tuple_pop_front_impl(const Tuple &tuple, std::index_sequence<Is...>) {
- return std::make_tuple(std::get<1 + Is>(tuple)...);
-}
-
-template <typename Tuple> auto tuple_pop_front(const Tuple &tuple) {
- return tuple_pop_front_impl(
- tuple, std::make_index_sequence<std::tuple_size<Tuple>::value - 1>());
-}
-
template <typename T, typename... U> struct MatchParents {
static std::tuple<bool, DynTypedNodeList, const T *, const U *...>
match(const DynTypedNodeList &NodeList,
@@ -285,10 +275,11 @@ template <typename T, typename... U> struct MatchParents {
if (NextParentList.size() == 1) {
auto TailTuple = MatchParents<U...>::match(NextParentList, ParentMap);
if (std::get<bool>(TailTuple)) {
- return std::tuple_cat(
- std::make_tuple(true, std::get<DynTypedNodeList>(TailTuple),
- TypedNode),
- tuple_pop_front(tuple_pop_front(TailTuple)));
+ return std::apply(
+ [TypedNode](bool, DynTypedNodeList NodeList, auto... TupleTail) {
+ return std::make_tuple(true, NodeList, TypedNode, TupleTail...);
+ },
+ TailTuple);
}
}
}
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index c6c41abc7e9a..96079c235c5e 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -326,6 +326,14 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case 's': k = ConversionSpecifier::sArg; break;
case 'u': k = ConversionSpecifier::uArg; break;
case 'x': k = ConversionSpecifier::xArg; break;
+ // C23.
+ case 'b':
+ if (isFreeBSDKPrintf)
+ k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
+ else
+ k = ConversionSpecifier::bArg;
+ break;
+ case 'B': k = ConversionSpecifier::BArg; break;
// POSIX specific.
case 'C': k = ConversionSpecifier::CArg; break;
case 'S': k = ConversionSpecifier::SArg; break;
@@ -337,11 +345,6 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
- // FreeBSD kernel specific.
- case 'b':
- if (isFreeBSDKPrintf)
- k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
- break;
case 'r':
if (isFreeBSDKPrintf)
k = ConversionSpecifier::FreeBSDrArg; // int
@@ -497,7 +500,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return Ctx.IntTy;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return ArgType::Invalid();
}
@@ -844,7 +847,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
+ if (LangOpt.C99 || LangOpt.CPlusPlus11)
namedTypeToLengthModifier(QT, LM);
// If fixing the length modifier was enough, we might be done.
@@ -874,7 +877,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
// Set conversion specifier and disable any flags which do not apply to it.
// Let typedefs to char fall through to int, as %c is silly for uint8_t.
- if (!isa<TypedefType>(QT) && QT->isCharType()) {
+ if (!QT->getAs<TypedefType>() && QT->isCharType()) {
CS.setKind(ConversionSpecifier::cArg);
LM.setKind(LengthModifier::None);
Precision.setHowSpecified(OptionalAmount::NotSpecified);
@@ -885,12 +888,10 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
// Test for Floating type first as LongDouble can pass isUnsignedIntegerType
else if (QT->isRealFloatingType()) {
CS.setKind(ConversionSpecifier::fArg);
- }
- else if (QT->isSignedIntegerType()) {
+ } else if (QT->isSignedIntegerType()) {
CS.setKind(ConversionSpecifier::dArg);
HasAlternativeForm = false;
- }
- else if (QT->isUnsignedIntegerType()) {
+ } else if (QT->isUnsignedIntegerType()) {
CS.setKind(ConversionSpecifier::uArg);
HasAlternativeForm = false;
HasPlusPrefix = false;
@@ -963,8 +964,10 @@ bool PrintfSpecifier::hasValidAlternativeForm() const {
if (!HasAlternativeForm)
return true;
- // Alternate form flag only valid with the oxXaAeEfFgG conversions
+ // Alternate form flag only valid with the bBoxXaAeEfFgG conversions
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::oArg:
case ConversionSpecifier::OArg:
case ConversionSpecifier::xArg:
@@ -990,8 +993,10 @@ bool PrintfSpecifier::hasValidLeadingZeros() const {
if (!HasLeadingZeroes)
return true;
- // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
+ // Leading zeroes flag only valid with the bBdiouxXaAeEfFgG conversions
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
@@ -1082,8 +1087,10 @@ bool PrintfSpecifier::hasValidPrecision() const {
if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
return true;
- // Precision is only valid with the diouxXaAeEfFgGsP conversions
+ // Precision is only valid with the bBdiouxXaAeEfFgGsP conversions
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp
index 26aaa96a1dc6..7557336f0aaf 100644
--- a/clang/lib/AST/QualTypeNames.cpp
+++ b/clang/lib/AST/QualTypeNames.cpp
@@ -129,11 +129,9 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
bool MightHaveChanged = false;
SmallVector<TemplateArgument, 4> FQArgs;
- for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
- I != E; ++I) {
- // Cheap to copy and potentially modified by
- // getFullyQualifedTemplateArgument.
- TemplateArgument Arg(*I);
+ // Cheap to copy and potentially modified by
+ // getFullyQualifedTemplateArgument.
+ for (TemplateArgument Arg : TST->template_arguments()) {
MightHaveChanged |= getFullyQualifiedTemplateArgument(
Ctx, Arg, WithGlobalNsPrefix);
FQArgs.push_back(Arg);
@@ -422,13 +420,6 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
return QT;
}
- // We don't consider the alias introduced by `using a::X` as a new type.
- // The qualified name is still a::X.
- if (isa<UsingType>(QT.getTypePtr())) {
- return getFullyQualifiedType(QT.getSingleStepDesugaredType(Ctx), Ctx,
- WithGlobalNsPrefix);
- }
-
// Remove the part of the type related to the type being a template
// parameter (we won't report it as part of the 'type name' and it
// is actually make the code below to be more complex (to handle
@@ -455,6 +446,14 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
assert(!QT.hasLocalQualifiers());
Keyword = ETypeInput->getKeyword();
}
+
+ // We don't consider the alias introduced by `using a::X` as a new type.
+ // The qualified name is still a::X.
+ if (const auto *UT = QT->getAs<UsingType>()) {
+ QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers);
+ return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
+ }
+
// Create a nested name specifier if needed.
Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
true /*FullyQualified*/,
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 6f3ede2ce42a..2f546398338c 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -1059,10 +1059,10 @@ void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases(
// primary base, add it in now.
} else if (RD->isDynamicClass()) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
- CharUnits PtrWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- CharUnits PtrAlign =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+ CharUnits PtrWidth = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerWidth(LangAS::Default));
+ CharUnits PtrAlign = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerAlign(LangAS::Default));
EnsureVTablePointerAlignment(PtrAlign);
HasOwnVFPtr = true;
@@ -1890,11 +1890,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
LastBitfieldStorageUnitSize = 0;
llvm::Triple Target = Context.getTargetInfo().getTriple();
- bool FieldPacked = (Packed && (!FieldClass || FieldClass->isPOD() ||
- Context.getLangOpts().getClangABICompat() <=
- LangOptions::ClangABI::Ver14 ||
- Target.isPS() || Target.isOSDarwin())) ||
- D->hasAttr<PackedAttr>();
AlignRequirementKind AlignRequirement = AlignRequirementKind::None;
CharUnits FieldSize;
@@ -1916,12 +1911,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
if (D->getType()->isIncompleteArrayType()) {
setDeclInfo(true /* IsIncompleteArrayType */);
- } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
- unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType());
- EffectiveFieldSize = FieldSize = Context.toCharUnitsFromBits(
- Context.getTargetInfo().getPointerWidth(AS));
- FieldAlign = Context.toCharUnitsFromBits(
- Context.getTargetInfo().getPointerAlign(AS));
} else {
setDeclInfo(false /* IsIncompleteArrayType */);
@@ -1975,6 +1964,14 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
}
}
+ bool FieldPacked = (Packed && (!FieldClass || FieldClass->isPOD() ||
+ FieldClass->hasAttr<PackedAttr>() ||
+ Context.getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver15 ||
+ Target.isPS() || Target.isOSDarwin() ||
+ Target.isOSAIX())) ||
+ D->hasAttr<PackedAttr>();
+
// When used as part of a typedef, or together with a 'packed' attribute, the
// 'aligned' attribute can be used to decrease alignment. In that case, it
// overrides any computed alignment we have, and there is no need to upgrade
@@ -2025,28 +2022,34 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// The align if the field is not packed. This is to check if the attribute
// was unnecessary (-Wpacked).
- CharUnits UnpackedFieldAlign =
- !DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign;
+ CharUnits UnpackedFieldAlign = FieldAlign;
+ CharUnits PackedFieldAlign = CharUnits::One();
CharUnits UnpackedFieldOffset = FieldOffset;
CharUnits OriginalFieldAlign = UnpackedFieldAlign;
- if (FieldPacked) {
- FieldAlign = CharUnits::One();
- PreferredAlign = CharUnits::One();
- }
CharUnits MaxAlignmentInChars =
Context.toCharUnitsFromBits(D->getMaxAlignment());
- FieldAlign = std::max(FieldAlign, MaxAlignmentInChars);
+ PackedFieldAlign = std::max(PackedFieldAlign, MaxAlignmentInChars);
PreferredAlign = std::max(PreferredAlign, MaxAlignmentInChars);
UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
// The maximum field alignment overrides the aligned attribute.
if (!MaxFieldAlignment.isZero()) {
- FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment);
PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
}
+
+ if (!FieldPacked)
+ FieldAlign = UnpackedFieldAlign;
+ if (DefaultsToAIXPowerAlignment)
+ UnpackedFieldAlign = PreferredAlign;
+ if (FieldPacked) {
+ PreferredAlign = PackedFieldAlign;
+ FieldAlign = PackedFieldAlign;
+ }
+
CharUnits AlignTo =
!DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign;
// Round up the current record size to the field's alignment boundary.
@@ -2129,6 +2132,9 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
<< Context.getTypeDeclType(RD) << D->getName() << D->getType();
}
}
+
+ if (Packed && !FieldPacked && PackedFieldAlign < FieldAlign)
+ Diag(D->getLocation(), diag::warn_unpacked_field) << D;
}
void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
@@ -2757,7 +2763,8 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
// than the pointer size.
if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>()){
unsigned PackedAlignment = MFAA->getAlignment();
- if (PackedAlignment <= Context.getTargetInfo().getPointerWidth(0))
+ if (PackedAlignment <=
+ Context.getTargetInfo().getPointerWidth(LangAS::Default))
MaxFieldAlignment = Context.toCharUnitsFromBits(PackedAlignment);
}
// Packed attribute forces max field alignment to be 1.
@@ -2782,10 +2789,10 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
SharedVBPtrBase = nullptr;
// Calculate pointer size and alignment. These are used for vfptr and vbprt
// injection.
- PointerInfo.Size =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- PointerInfo.Alignment =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+ PointerInfo.Size = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerWidth(LangAS::Default));
+ PointerInfo.Alignment = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerAlign(LangAS::Default));
// Respect pragma pack.
if (!MaxFieldAlignment.isZero())
PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment);
@@ -3070,10 +3077,9 @@ void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
VBPtrOffset += Offset;
if (UseExternalLayout) {
- // The class may have no bases or fields, but still have a vfptr
- // (e.g. it's an interface class). The size was not correctly set before
- // in this case.
- if (FieldOffsets.empty() && Bases.empty())
+ // The class may have size 0 and a vfptr (e.g. it's an interface class). The
+ // size was not correctly set before in this case.
+ if (Size.isZero())
Size += Offset;
return;
}
@@ -3275,6 +3281,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
if (D->hasExternalLexicalStorage() && !D->getDefinition())
getExternalSource()->CompleteType(const_cast<RecordDecl*>(D));
+ // Complete the redecl chain (if necessary).
+ (void)D->getMostRecentDecl();
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index 8d763f28e57f..d6ff1a616285 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -161,6 +161,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
default:
break;
case '%': k = ConversionSpecifier::PercentArg; break;
+ case 'b': k = ConversionSpecifier::bArg; break;
case 'A': k = ConversionSpecifier::AArg; break;
case 'E': k = ConversionSpecifier::EArg; break;
case 'F': k = ConversionSpecifier::FArg; break;
@@ -267,6 +268,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
llvm_unreachable("Unsupported LengthModifier Type");
// Unsigned int.
+ case ConversionSpecifier::bArg:
case ConversionSpecifier::oArg:
case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
@@ -343,7 +345,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return ArgType::PtrTo(ArgType::AnyCharTy);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return ArgType::Invalid();
}
@@ -360,7 +362,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return ArgType::PtrTo(ArgType::AnyCharTy);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return ArgType::Invalid();
}
@@ -500,7 +502,7 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
+ if (LangOpt.C99 || LangOpt.CPlusPlus11)
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 8eae04d0d9fd..8744bba6c6d9 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -41,6 +41,7 @@
#include <algorithm>
#include <cassert>
#include <cstring>
+#include <optional>
#include <string>
#include <type_traits>
#include <utility>
@@ -1001,18 +1002,18 @@ bool IfStmt::isObjCAvailabilityCheck() const {
return isa<ObjCAvailabilityCheckExpr>(getCond());
}
-Optional<Stmt *> IfStmt::getNondiscardedCase(const ASTContext &Ctx) {
+std::optional<Stmt *> IfStmt::getNondiscardedCase(const ASTContext &Ctx) {
if (!isConstexpr() || getCond()->isValueDependent())
- return None;
+ return std::nullopt;
return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen();
}
-Optional<const Stmt *>
+std::optional<const Stmt *>
IfStmt::getNondiscardedCase(const ASTContext &Ctx) const {
- if (Optional<Stmt *> Result =
+ if (std::optional<Stmt *> Result =
const_cast<IfStmt *>(this)->getNondiscardedCase(Ctx))
return *Result;
- return None;
+ return std::nullopt;
}
ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index e0a4221db7ec..7c5b9f23fc26 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -31,7 +31,7 @@ void OMPChildren::setClauses(ArrayRef<OMPClause *> Clauses) {
}
MutableArrayRef<Stmt *> OMPChildren::getChildren() {
- return llvm::makeMutableArrayRef(getTrailingObjects<Stmt *>(), NumChildren);
+ return llvm::MutableArrayRef(getTrailingObjects<Stmt *>(), NumChildren);
}
OMPChildren *OMPChildren::Create(void *Mem, ArrayRef<OMPClause *> Clauses) {
@@ -517,7 +517,7 @@ OMPSectionDirective *OMPSectionDirective::Create(const ASTContext &C,
Stmt *AssociatedStmt,
bool HasCancel) {
auto *Dir =
- createDirective<OMPSectionDirective>(C, llvm::None, AssociatedStmt,
+ createDirective<OMPSectionDirective>(C, std::nullopt, AssociatedStmt,
/*NumChildren=*/0, StartLoc, EndLoc);
Dir->setHasCancel(HasCancel);
return Dir;
@@ -550,7 +550,7 @@ OMPMasterDirective *OMPMasterDirective::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc,
Stmt *AssociatedStmt) {
- return createDirective<OMPMasterDirective>(C, llvm::None, AssociatedStmt,
+ return createDirective<OMPMasterDirective>(C, std::nullopt, AssociatedStmt,
/*NumChildren=*/0, StartLoc,
EndLoc);
}
@@ -744,6 +744,21 @@ OMPTaskyieldDirective *OMPTaskyieldDirective::CreateEmpty(const ASTContext &C,
return new (C) OMPTaskyieldDirective();
}
+OMPErrorDirective *OMPErrorDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses) {
+ return createDirective<OMPErrorDirective>(
+ C, Clauses, /*AssociatedStmt=*/nullptr, /*NumChildren=*/0, StartLoc,
+ EndLoc);
+}
+
+OMPErrorDirective *OMPErrorDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ return createEmptyDirective<OMPErrorDirective>(C, NumClauses);
+}
+
OMPBarrierDirective *OMPBarrierDirective::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc) {
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 8d778500d103..0a879bb6df2a 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -54,6 +54,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <optional>
#include <string>
using namespace clang;
@@ -843,6 +844,11 @@ void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPErrorDirective(OMPErrorDirective *Node) {
+ Indent() << "#pragma omp error";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *Node) {
Indent() << "#pragma omp taskgroup";
PrintOMPExecutableDirective(Node);
@@ -1280,6 +1286,7 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
case BuiltinType::Char_S:
case BuiltinType::Char_U: OS << "i8"; break;
case BuiltinType::UChar: OS << "Ui8"; break;
+ case BuiltinType::SChar: OS << "i8"; break;
case BuiltinType::Short: OS << "i16"; break;
case BuiltinType::UShort: OS << "Ui16"; break;
case BuiltinType::Int: break; // no suffix.
@@ -1292,6 +1299,9 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
break; // no suffix.
case BuiltinType::UInt128:
break; // no suffix.
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ break; // no suffix
}
}
@@ -1993,7 +2003,7 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
cast<FunctionDecl>(DRE->getDecl())->getTemplateSpecializationArgs();
assert(Args);
- if (Args->size() != 1) {
+ if (Args->size() != 1 || Args->get(0).getKind() != TemplateArgument::Pack) {
const TemplateParameterList *TPL = nullptr;
if (!DRE->hadMultipleCandidates())
if (const auto *TD = dyn_cast<TemplateDecl>(DRE->getDecl()))
@@ -2164,7 +2174,8 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
OS << "...";
if (Node->isInitCapture(C)) {
- VarDecl *D = C->getCapturedVar();
+ // Init captures are always VarDecl.
+ auto *D = cast<VarDecl>(C->getCapturedVar());
llvm::StringRef Pre;
llvm::StringRef Post;
@@ -2265,7 +2276,7 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isArray()) {
llvm::raw_string_ostream s(TypeS);
s << '[';
- if (Optional<Expr *> Size = E->getArraySize())
+ if (std::optional<Expr *> Size = E->getArraySize())
(*Size)->printPretty(s, Helper, Policy);
s << ']';
}
@@ -2455,6 +2466,13 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
OS << ")";
}
+void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) {
+ OS << "(";
+ llvm::interleaveComma(Node->getInitExprs(), OS,
+ [&](Expr *E) { PrintExpr(E); });
+ OS << ")";
+}
+
void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
if (NNS)
@@ -2511,7 +2529,7 @@ void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) {
} else {
auto *NestedReq = cast<concepts::NestedRequirement>(Req);
OS << "requires ";
- if (NestedReq->isSubstitutionFailure())
+ if (NestedReq->hasInvalidConstraint())
OS << "<<error-expression>>";
else
PrintExpr(NestedReq->getConstraintExpr());
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 92a8b18cf68a..960cc4f4fc27 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -472,7 +472,7 @@ void OMPClauseProfiler::VisitOMPSimdlenClause(const OMPSimdlenClause *C) {
}
void OMPClauseProfiler::VisitOMPSizesClause(const OMPSizesClause *C) {
- for (auto E : C->getSizesRefs())
+ for (auto *E : C->getSizesRefs())
if (E)
Profiler->VisitExpr(E);
}
@@ -530,6 +530,15 @@ void OMPClauseProfiler::VisitOMPDynamicAllocatorsClause(
void OMPClauseProfiler::VisitOMPAtomicDefaultMemOrderClause(
const OMPAtomicDefaultMemOrderClause *C) {}
+void OMPClauseProfiler::VisitOMPAtClause(const OMPAtClause *C) {}
+
+void OMPClauseProfiler::VisitOMPSeverityClause(const OMPSeverityClause *C) {}
+
+void OMPClauseProfiler::VisitOMPMessageClause(const OMPMessageClause *C) {
+ if (C->getMessageString())
+ Profiler->VisitStmt(C->getMessageString());
+}
+
void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) {
VistOMPClauseWithPreInit(C);
if (auto *S = C->getChunkSize())
@@ -894,6 +903,12 @@ void OMPClauseProfiler::VisitOMPAffinityClause(const OMPAffinityClause *C) {
}
void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {}
void OMPClauseProfiler::VisitOMPBindClause(const OMPBindClause *C) {}
+void OMPClauseProfiler::VisitOMPXDynCGroupMemClause(
+ const OMPXDynCGroupMemClause *C) {
+ VistOMPClauseWithPreInit(C);
+ if (Expr *Size = C->getSize())
+ Profiler->VisitStmt(Size);
+}
} // namespace
void
@@ -1014,6 +1029,9 @@ void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) {
VisitOMPExecutableDirective(S);
}
+void StmtProfiler::VisitOMPErrorDirective(const OMPErrorDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
void StmtProfiler::VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *S) {
VisitOMPExecutableDirective(S);
if (const Expr *E = S->getReductionRef())
@@ -1610,8 +1628,8 @@ void StmtProfiler::VisitRequiresExpr(const RequiresExpr *S) {
} else {
ID.AddInteger(concepts::Requirement::RK_Nested);
auto *NestedReq = cast<concepts::NestedRequirement>(Req);
- ID.AddBoolean(NestedReq->isSubstitutionFailure());
- if (!NestedReq->isSubstitutionFailure())
+ ID.AddBoolean(NestedReq->hasInvalidConstraint());
+ if (!NestedReq->hasInvalidConstraint())
Visit(NestedReq->getConstraintExpr());
}
}
@@ -2181,6 +2199,10 @@ void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) {
ID.AddInteger(S->getOperator());
}
+void StmtProfiler::VisitCXXParenListInitExpr(const CXXParenListInitExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
VisitStmt(S);
}
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index e0f5916a9a0b..ceff7a313716 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -29,7 +29,6 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -41,6 +40,7 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <optional>
using namespace clang;
@@ -271,12 +271,12 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
return getDependence() & TemplateArgumentDependence::UnexpandedPack;
}
-Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+std::optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
assert(getKind() == TemplateExpansion);
if (TemplateArg.NumExpansions)
return TemplateArg.NumExpansions - 1;
- return None;
+ return std::nullopt;
}
QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
@@ -321,26 +321,15 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
case Declaration:
getParamTypeForDecl().Profile(ID);
- ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr);
+ ID.AddPointer(getAsDecl());
break;
+ case TemplateExpansion:
+ ID.AddInteger(TemplateArg.NumExpansions);
+ LLVM_FALLTHROUGH;
case Template:
- case TemplateExpansion: {
- TemplateName Template = getAsTemplateOrTemplatePattern();
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast_or_null<TemplateTemplateParmDecl>(
- Template.getAsTemplateDecl())) {
- ID.AddBoolean(true);
- ID.AddInteger(TTP->getDepth());
- ID.AddInteger(TTP->getPosition());
- ID.AddBoolean(TTP->isParameterPack());
- } else {
- ID.AddBoolean(false);
- ID.AddPointer(Context.getCanonicalTemplateName(Template)
- .getAsVoidPointer());
- }
+ getAsTemplateOrTemplatePattern().Profile(ID);
break;
- }
case Integral:
getAsIntegral().Profile(ID);
@@ -374,7 +363,8 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
TemplateArg.NumExpansions == Other.TemplateArg.NumExpansions;
case Declaration:
- return getAsDecl() == Other.getAsDecl();
+ return getAsDecl() == Other.getAsDecl() &&
+ getParamTypeForDecl() == Other.getParamTypeForDecl();
case Integral:
return getIntegralType() == Other.getIntegralType() &&
@@ -432,10 +422,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
}
case Declaration: {
- // FIXME: Include the type if it's not obvious from the context.
NamedDecl *ND = getAsDecl();
if (getParamTypeForDecl()->isRecordType()) {
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
+ TPO->getType().getUnqualifiedType().print(Out, Policy);
TPO->printAsInit(Out, Policy);
break;
}
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index 11dc3d2e1985..a6dd0fad9331 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -29,37 +29,74 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <optional>
#include <string>
using namespace clang;
TemplateArgument
SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
- return TemplateArgument(llvm::makeArrayRef(Arguments, size()));
+ return TemplateArgument(llvm::ArrayRef(Arguments, Bits.Data));
+}
+
+TemplateTemplateParmDecl *
+SubstTemplateTemplateParmPackStorage::getParameterPack() const {
+ return cast<TemplateTemplateParmDecl>(
+ getReplacedTemplateParameterList(getAssociatedDecl())
+ ->asArray()[Bits.Index]);
+}
+
+TemplateTemplateParmDecl *
+SubstTemplateTemplateParmStorage::getParameter() const {
+ return cast<TemplateTemplateParmDecl>(
+ getReplacedTemplateParameterList(getAssociatedDecl())
+ ->asArray()[Bits.Index]);
}
void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Parameter, Replacement);
+ Profile(ID, Replacement, getAssociatedDecl(), getIndex(), getPackIndex());
+}
+
+void SubstTemplateTemplateParmStorage::Profile(
+ llvm::FoldingSetNodeID &ID, TemplateName Replacement, Decl *AssociatedDecl,
+ unsigned Index, std::optional<unsigned> PackIndex) {
+ Replacement.Profile(ID);
+ ID.AddPointer(AssociatedDecl);
+ ID.AddInteger(Index);
+ ID.AddInteger(PackIndex ? *PackIndex + 1 : 0);
}
-void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID,
- TemplateTemplateParmDecl *parameter,
- TemplateName replacement) {
- ID.AddPointer(parameter);
- ID.AddPointer(replacement.getAsVoidPointer());
+SubstTemplateTemplateParmPackStorage::SubstTemplateTemplateParmPackStorage(
+ ArrayRef<TemplateArgument> ArgPack, Decl *AssociatedDecl, unsigned Index,
+ bool Final)
+ : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Index,
+ ArgPack.size()),
+ Arguments(ArgPack.data()), AssociatedDeclAndFinal(AssociatedDecl, Final) {
+ assert(AssociatedDecl != nullptr);
}
void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
ASTContext &Context) {
- Profile(ID, Context, Parameter, getArgumentPack());
+ Profile(ID, Context, getArgumentPack(), getAssociatedDecl(), getIndex(),
+ getFinal());
}
-void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
- ASTContext &Context,
- TemplateTemplateParmDecl *Parameter,
- const TemplateArgument &ArgPack) {
- ID.AddPointer(Parameter);
+Decl *SubstTemplateTemplateParmPackStorage::getAssociatedDecl() const {
+ return AssociatedDeclAndFinal.getPointer();
+}
+
+bool SubstTemplateTemplateParmPackStorage::getFinal() const {
+ return AssociatedDeclAndFinal.getInt();
+}
+
+void SubstTemplateTemplateParmPackStorage::Profile(
+ llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index,
+ bool Final) {
ArgPack.Profile(ID, Context);
+ ID.AddPointer(AssociatedDecl);
+ ID.AddInteger(Index);
+ ID.AddBoolean(Final);
}
TemplateName::TemplateName(void *Ptr) {
@@ -304,7 +341,7 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
} else {
assert(getKind() == TemplateName::OverloadedTemplate);
OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
- (*OTS->begin())->printName(OS);
+ (*OTS->begin())->printName(OS, Policy);
}
}
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 22643d4edbec..a5573c117e62 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1543,17 +1543,23 @@ void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
void TextNodeDumper::VisitUsingType(const UsingType *T) {
dumpDeclRef(T->getFoundDecl());
+ if (!T->typeMatchesDecl())
+ OS << " divergent";
}
void TextNodeDumper::VisitTypedefType(const TypedefType *T) {
dumpDeclRef(T->getDecl());
+ if (!T->typeMatchesDecl())
+ OS << " divergent";
}
void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {
switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- OS << " underlying_type";
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ case UnaryTransformType::Enum: \
+ OS << " " #Trait; \
break;
+#include "clang/Basic/TransformTypeTraits.def"
}
}
@@ -1568,6 +1574,20 @@ void TextNodeDumper::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
dumpDeclRef(T->getDecl());
}
+void TextNodeDumper::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *T) {
+ dumpDeclRef(T->getAssociatedDecl());
+ VisitTemplateTypeParmDecl(T->getReplacedParameter());
+ if (auto PackIndex = T->getPackIndex())
+ OS << " pack_index " << *PackIndex;
+}
+
+void TextNodeDumper::VisitSubstTemplateTypeParmPackType(
+ const SubstTemplateTypeParmPackType *T) {
+ dumpDeclRef(T->getAssociatedDecl());
+ VisitTemplateTypeParmDecl(T->getReplacedParameter());
+}
+
void TextNodeDumper::VisitAutoType(const AutoType *T) {
if (T->isDecltypeAuto())
OS << " decltype(auto)";
@@ -1786,6 +1806,8 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
case VarDecl::ListInit:
OS << " listinit";
break;
+ case VarDecl::ParenListInit:
+ OS << " parenlistinit";
}
}
if (D->needsDestruction(D->getASTContext()))
@@ -1911,6 +1933,8 @@ void TextNodeDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
dumpName(D);
if (D->isInline())
OS << " inline";
+ if (D->isNested())
+ OS << " nested";
if (!D->isOriginalNamespace())
dumpDeclRef(D->getOriginalNamespace(), "original");
}
@@ -2380,3 +2404,11 @@ void TextNodeDumper::VisitCompoundStmt(const CompoundStmt *S) {
if (S->hasStoredFPFeatures())
printFPOptions(S->getStoredFPFeatures());
}
+
+void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
+ if (D->isCBuffer())
+ OS << " cbuffer";
+ else
+ OS << " tbuffer";
+ dumpName(D);
+}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 0f168a518707..a713d6e3bd03 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -42,7 +42,6 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@@ -51,6 +50,7 @@
#include <cassert>
#include <cstdint>
#include <cstring>
+#include <optional>
#include <type_traits>
using namespace clang;
@@ -525,6 +525,10 @@ template <> const TypedefType *Type::getAs() const {
return getAsSugar<TypedefType>(this);
}
+template <> const UsingType *Type::getAs() const {
+ return getAsSugar<UsingType>(this);
+}
+
template <> const TemplateSpecializationType *Type::getAs() const {
return getAsSugar<TemplateSpecializationType>(this);
}
@@ -1073,7 +1077,7 @@ public:
if (exceptionChanged) {
info.ExceptionSpec.Exceptions =
- llvm::makeArrayRef(exceptionTypes).copy(Ctx);
+ llvm::ArrayRef(exceptionTypes).copy(Ctx);
}
}
@@ -1166,8 +1170,9 @@ public:
== T->getReplacementType().getAsOpaquePtr())
return QualType(T, 0);
- return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(),
- replacementType);
+ return Ctx.getSubstTemplateTypeParmType(replacementType,
+ T->getAssociatedDecl(),
+ T->getIndex(), T->getPackIndex());
}
// FIXME: Non-trivial to implement, but important for C++
@@ -1214,10 +1219,10 @@ public:
!typeArgChanged)
return QualType(T, 0);
- return Ctx.getObjCObjectType(baseType, typeArgs,
- llvm::makeArrayRef(T->qual_begin(),
- T->getNumProtocols()),
- T->isKindOfTypeAsWritten());
+ return Ctx.getObjCObjectType(
+ baseType, typeArgs,
+ llvm::ArrayRef(T->qual_begin(), T->getNumProtocols()),
+ T->isKindOfTypeAsWritten());
}
TRIVIAL_TYPE_CLASS(ObjCInterface)
@@ -1369,7 +1374,7 @@ struct SubstObjCTypeArgsVisitor
if (exceptionChanged) {
info.ExceptionSpec.Exceptions =
- llvm::makeArrayRef(exceptionTypes).copy(Ctx);
+ llvm::ArrayRef(exceptionTypes).copy(Ctx);
}
}
@@ -1479,6 +1484,25 @@ struct StripObjCKindOfTypeVisitor
} // namespace
+bool QualType::UseExcessPrecision(const ASTContext &Ctx) {
+ const BuiltinType *BT = getTypePtr()->getAs<BuiltinType>();
+ if (BT) {
+ switch (BT->getKind()) {
+ case BuiltinType::Kind::Float16: {
+ const TargetInfo &TI = Ctx.getTargetInfo();
+ if (TI.hasFloat16Type() && !TI.hasLegalHalfType() &&
+ Ctx.getLangOpts().getFloat16ExcessPrecision() !=
+ Ctx.getLangOpts().ExcessPrecisionKind::FPP_None)
+ return true;
+ return false;
+ }
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
/// Substitute the given type arguments for Objective-C type
/// parameters within the given type, recursively.
QualType QualType::substObjCTypeArgs(ASTContext &ctx,
@@ -1510,8 +1534,8 @@ QualType QualType::getAtomicUnqualifiedType() const {
return getUnqualifiedType();
}
-Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
- const DeclContext *dc) const {
+std::optional<ArrayRef<QualType>>
+Type::getObjCSubstitutions(const DeclContext *dc) const {
// Look through method scopes.
if (const auto method = dyn_cast<ObjCMethodDecl>(dc))
dc = method->getDeclContext();
@@ -1526,23 +1550,23 @@ Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
// substitution to do.
dcTypeParams = dcClassDecl->getTypeParamList();
if (!dcTypeParams)
- return None;
+ return std::nullopt;
} else {
// If we are in neither a class nor a category, there's no
// substitution to perform.
dcCategoryDecl = dyn_cast<ObjCCategoryDecl>(dc);
if (!dcCategoryDecl)
- return None;
+ return std::nullopt;
// If the category does not have any type parameters, there's no
// substitution to do.
dcTypeParams = dcCategoryDecl->getTypeParamList();
if (!dcTypeParams)
- return None;
+ return std::nullopt;
dcClassDecl = dcCategoryDecl->getClassInterface();
if (!dcClassDecl)
- return None;
+ return std::nullopt;
}
assert(dcTypeParams && "No substitutions to perform");
assert(dcClassDecl && "No class context");
@@ -2320,6 +2344,20 @@ bool Type::isSizelessBuiltinType() const {
bool Type::isSizelessType() const { return isSizelessBuiltinType(); }
+bool Type::isSVESizelessBuiltinType() const {
+ if (const BuiltinType *BT = getAs<BuiltinType>()) {
+ switch (BT->getKind()) {
+ // SVE Types
+#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
bool Type::isVLSTBuiltinType() const {
if (const BuiltinType *BT = getAs<BuiltinType>()) {
switch (BT->getKind()) {
@@ -2777,39 +2815,6 @@ bool Type::isStdByteType() const {
return false;
}
-bool Type::isPromotableIntegerType() const {
- if (const auto *BT = getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Bool:
- case BuiltinType::Char_S:
- case BuiltinType::Char_U:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- case BuiltinType::Char8:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- return true;
- default:
- return false;
- }
-
- // Enumerated types are promotable to their compatible integer types
- // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2).
- if (const auto *ET = getAs<EnumType>()){
- if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull()
- || ET->getDecl()->isScoped())
- return false;
-
- return true;
- }
-
- return false;
-}
-
bool Type::isSpecifierType() const {
// Note that this intentionally does not use the canonical type.
switch (getTypeClass()) {
@@ -2928,7 +2933,7 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
DependentTemplateSpecializationTypeBits.NumArgs = Args.size();
assert((!NNS || NNS->isDependent()) &&
"DependentTemplateSpecializatonType requires dependent qualifier");
- TemplateArgument *ArgBuffer = getArgBuffer();
+ auto *ArgBuffer = const_cast<TemplateArgument *>(template_arguments().data());
for (const TemplateArgument &Arg : Args) {
addDependence(toTypeDependence(Arg.getDependence() &
TemplateArgumentDependence::UnexpandedPack));
@@ -3084,7 +3089,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Char32:
return "char32_t";
case NullPtr:
- return "std::nullptr_t";
+ return Policy.NullptrTypeInNamespace ? "std::nullptr_t" : "nullptr_t";
case Overload:
return "<overloaded function type>";
case BoundMember:
@@ -3434,25 +3439,34 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
}
TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D,
- QualType underlying, QualType can)
- : Type(tc, can, toSemanticDependence(underlying->getDependence())),
+ QualType Underlying, QualType can)
+ : Type(tc, can, toSemanticDependence(can->getDependence())),
Decl(const_cast<TypedefNameDecl *>(D)) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
+ TypedefBits.hasTypeDifferentFromDecl = !Underlying.isNull();
+ if (!typeMatchesDecl())
+ *getTrailingObjects<QualType>() = Underlying;
}
QualType TypedefType::desugar() const {
- return getDecl()->getUnderlyingType();
+ return typeMatchesDecl() ? Decl->getUnderlyingType()
+ : *getTrailingObjects<QualType>();
}
UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying,
QualType Canon)
- : Type(Using, Canon, toSemanticDependence(Underlying->getDependence())),
+ : Type(Using, Canon, toSemanticDependence(Canon->getDependence())),
Found(const_cast<UsingShadowDecl *>(Found)) {
- assert(Underlying == getUnderlyingType());
+ UsingBits.hasTypeDifferentFromDecl = !Underlying.isNull();
+ if (!typeMatchesDecl())
+ *getTrailingObjects<QualType>() = Underlying;
}
QualType UsingType::getUnderlyingType() const {
- return QualType(cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0);
+ return typeMatchesDecl()
+ ? QualType(
+ cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0)
+ : *getTrailingObjects<QualType>();
}
QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); }
@@ -3469,27 +3483,37 @@ QualType MacroQualifiedType::getModifiedType() const {
return Inner;
}
-TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
- : Type(TypeOfExpr, can,
+TypeOfExprType::TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can)
+ : Type(TypeOfExpr,
+ // We have to protect against 'Can' being invalid through its
+ // default argument.
+ Kind == TypeOfKind::Unqualified && !Can.isNull()
+ ? Can.getAtomicUnqualifiedType()
+ : Can,
toTypeDependence(E->getDependence()) |
(E->getType()->getDependence() &
TypeDependence::VariablyModified)),
- TOExpr(E) {}
+ TOExpr(E) {
+ TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
+}
bool TypeOfExprType::isSugared() const {
return !TOExpr->isTypeDependent();
}
QualType TypeOfExprType::desugar() const {
- if (isSugared())
- return getUnderlyingExpr()->getType();
-
+ if (isSugared()) {
+ QualType QT = getUnderlyingExpr()->getType();
+ return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
+ }
return QualType(this, 0);
}
void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
- const ASTContext &Context, Expr *E) {
+ const ASTContext &Context, Expr *E,
+ bool IsUnqual) {
E->Profile(ID, Context, true);
+ ID.AddBoolean(IsUnqual);
}
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
@@ -3539,7 +3563,7 @@ TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
decl(const_cast<TagDecl *>(D)) {}
static TagDecl *getInterestingTagDecl(TagDecl *decl) {
- for (auto I : decl->redecls()) {
+ for (auto *I : decl->redecls()) {
if (I->isCompleteDefinition() || I->isBeingDefined())
return I;
}
@@ -3649,28 +3673,80 @@ IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier();
}
+static const TemplateTypeParmDecl *getReplacedParameter(Decl *D,
+ unsigned Index) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
+ return TTP;
+ return cast<TemplateTypeParmDecl>(
+ getReplacedTemplateParameterList(D)->getParam(Index));
+}
+
+SubstTemplateTypeParmType::SubstTemplateTypeParmType(
+ QualType Replacement, Decl *AssociatedDecl, unsigned Index,
+ std::optional<unsigned> PackIndex)
+ : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(),
+ Replacement->getDependence()),
+ AssociatedDecl(AssociatedDecl) {
+ SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType =
+ Replacement != getCanonicalTypeInternal();
+ if (SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType)
+ *getTrailingObjects<QualType>() = Replacement;
+
+ SubstTemplateTypeParmTypeBits.Index = Index;
+ SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
+ assert(AssociatedDecl != nullptr);
+}
+
+const TemplateTypeParmDecl *
+SubstTemplateTypeParmType::getReplacedParameter() const {
+ return ::getReplacedParameter(getAssociatedDecl(), getIndex());
+}
+
SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType(
- const TemplateTypeParmType *Param, QualType Canon,
+ QualType Canon, Decl *AssociatedDecl, unsigned Index, bool Final,
const TemplateArgument &ArgPack)
: Type(SubstTemplateTypeParmPack, Canon,
TypeDependence::DependentInstantiation |
TypeDependence::UnexpandedPack),
- Replaced(Param), Arguments(ArgPack.pack_begin()) {
+ Arguments(ArgPack.pack_begin()),
+ AssociatedDeclAndFinal(AssociatedDecl, Final) {
+ SubstTemplateTypeParmPackTypeBits.Index = Index;
SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size();
+ assert(AssociatedDecl != nullptr);
+}
+
+Decl *SubstTemplateTypeParmPackType::getAssociatedDecl() const {
+ return AssociatedDeclAndFinal.getPointer();
+}
+
+bool SubstTemplateTypeParmPackType::getFinal() const {
+ return AssociatedDeclAndFinal.getInt();
+}
+
+const TemplateTypeParmDecl *
+SubstTemplateTypeParmPackType::getReplacedParameter() const {
+ return ::getReplacedParameter(getAssociatedDecl(), getIndex());
+}
+
+IdentifierInfo *SubstTemplateTypeParmPackType::getIdentifier() const {
+ return getReplacedParameter()->getIdentifier();
}
TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const {
- return TemplateArgument(llvm::makeArrayRef(Arguments, getNumArgs()));
+ return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs()));
}
void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getReplacedParameter(), getArgumentPack());
+ Profile(ID, getAssociatedDecl(), getIndex(), getFinal(), getArgumentPack());
}
void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
- const TemplateTypeParmType *Replaced,
+ const Decl *AssociatedDecl,
+ unsigned Index, bool Final,
const TemplateArgument &ArgPack) {
- ID.AddPointer(Replaced);
+ ID.AddPointer(AssociatedDecl);
+ ID.AddInteger(Index);
+ ID.AddBoolean(Final);
ID.AddInteger(ArgPack.pack_size());
for (const auto &P : ArgPack.pack_elements())
ID.AddPointer(P.getAsType().getAsOpaquePtr());
@@ -3740,10 +3816,22 @@ TemplateSpecializationType::TemplateSpecializationType(
// Store the aliased type if this is a type alias template specialization.
if (isTypeAlias()) {
auto *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
- *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
+ *reinterpret_cast<QualType *>(Begin + Args.size()) = AliasedType;
}
}
+QualType TemplateSpecializationType::getAliasedType() const {
+ assert(isTypeAlias() && "not a type alias template specialization");
+ return *reinterpret_cast<const QualType *>(template_arguments().end());
+}
+
+void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Ctx) {
+ Profile(ID, Template, template_arguments(), Ctx);
+ if (isTypeAlias())
+ getAliasedType().Profile(ID);
+}
+
void
TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
TemplateName T,
@@ -3780,14 +3868,14 @@ void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID,
for (auto typeArg : typeArgs)
ID.AddPointer(typeArg.getAsOpaquePtr());
ID.AddInteger(protocols.size());
- for (auto proto : protocols)
+ for (auto *proto : protocols)
ID.AddPointer(proto);
ID.AddBoolean(isKindOf);
}
void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getBaseType(), getTypeArgsAsWritten(),
- llvm::makeArrayRef(qual_begin(), getNumProtocols()),
+ llvm::ArrayRef(qual_begin(), getNumProtocols()),
isKindOfTypeAsWritten());
}
@@ -3798,13 +3886,13 @@ void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID,
ID.AddPointer(OTPDecl);
ID.AddPointer(CanonicalType.getAsOpaquePtr());
ID.AddInteger(protocols.size());
- for (auto proto : protocols)
+ for (auto *proto : protocols)
ID.AddPointer(proto);
}
void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getDecl(), getCanonicalTypeInternal(),
- llvm::makeArrayRef(qual_begin(), getNumProtocols()));
+ llvm::ArrayRef(qual_begin(), getNumProtocols()));
}
namespace {
@@ -4091,8 +4179,7 @@ LinkageInfo Type::getLinkageAndVisibility() const {
return LinkageComputer{}.getTypeLinkageAndVisibility(this);
}
-Optional<NullabilityKind>
-Type::getNullability(const ASTContext &Context) const {
+std::optional<NullabilityKind> Type::getNullability() const {
QualType Type(this, 0);
while (const auto *AT = Type->getAs<AttributedType>()) {
// Check whether this is an attributed type with nullability
@@ -4102,7 +4189,7 @@ Type::getNullability(const ASTContext &Context) const {
Type = AT->getEquivalentType();
}
- return None;
+ return std::nullopt;
}
bool Type::canHaveNullability(bool ResultIfUnknown) const {
@@ -4233,8 +4320,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
llvm_unreachable("bad type kind!");
}
-llvm::Optional<NullabilityKind>
-AttributedType::getImmediateNullability() const {
+std::optional<NullabilityKind> AttributedType::getImmediateNullability() const {
if (getAttrKind() == attr::TypeNonNull)
return NullabilityKind::NonNull;
if (getAttrKind() == attr::TypeNullable)
@@ -4243,10 +4329,11 @@ AttributedType::getImmediateNullability() const {
return NullabilityKind::Unspecified;
if (getAttrKind() == attr::TypeNullableResult)
return NullabilityKind::NullableResult;
- return None;
+ return std::nullopt;
}
-Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) {
+std::optional<NullabilityKind>
+AttributedType::stripOuterNullability(QualType &T) {
QualType AttrTy = T;
if (auto MacroTy = dyn_cast<MacroQualifiedType>(T))
AttrTy = MacroTy->getUnderlyingType();
@@ -4258,7 +4345,7 @@ Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) {
}
}
- return None;
+ return std::nullopt;
}
bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const {
@@ -4320,20 +4407,13 @@ bool Type::isObjCARCImplicitlyUnretainedType() const {
}
bool Type::isObjCNSObjectType() const {
- const Type *cur = this;
- while (true) {
- if (const auto *typedefType = dyn_cast<TypedefType>(cur))
- return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>();
-
- // Single-step desugar until we run out of sugar.
- QualType next = cur->getLocallyUnqualifiedSingleStepDesugaredType();
- if (next.getTypePtr() == cur) return false;
- cur = next.getTypePtr();
- }
+ if (const auto *typedefType = getAs<TypedefType>())
+ return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>();
+ return false;
}
bool Type::isObjCIndependentClassType() const {
- if (const auto *typedefType = dyn_cast<TypedefType>(this))
+ if (const auto *typedefType = getAs<TypedefType>())
return typedefType->getDecl()->hasAttr<ObjCIndependentClassAttr>();
return false;
}
@@ -4465,7 +4545,8 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
AutoTypeBits.NumArgs = TypeConstraintArgs.size();
this->TypeConstraintConcept = TypeConstraintConcept;
if (TypeConstraintConcept) {
- TemplateArgument *ArgBuffer = getArgBuffer();
+ auto *ArgBuffer =
+ const_cast<TemplateArgument *>(getTypeConstraintArguments().data());
for (const TemplateArgument &Arg : TypeConstraintArgs) {
addDependence(
toSyntacticDependence(toTypeDependence(Arg.getDependence())));
@@ -4486,3 +4567,8 @@ void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
for (const TemplateArgument &Arg : Arguments)
Arg.Profile(ID, Context);
}
+
+void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
+ getTypeConstraintConcept(), getTypeConstraintArguments());
+}
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index cf5e2f979230..bcc5a223e6f7 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -194,15 +194,21 @@ SourceLocation TypeLoc::getBeginLoc() const {
while (true) {
switch (Cur.getTypeLocClass()) {
case Elaborated:
- LeftMost = Cur;
- break;
+ if (Cur.getLocalSourceRange().getBegin().isValid()) {
+ LeftMost = Cur;
+ break;
+ }
+ Cur = Cur.getNextTypeLoc();
+ if (Cur.isNull())
+ break;
+ continue;
case FunctionProto:
if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()
->hasTrailingReturn()) {
LeftMost = Cur;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case FunctionNoProto:
case ConstantArray:
case DependentSizedArray:
@@ -254,7 +260,7 @@ SourceLocation TypeLoc::getEndLoc() const {
// `id` and `id<...>` have no star location.
if (Cur.castAs<ObjCObjectPointerTypeLoc>().getStarLoc().isInvalid())
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Pointer:
case BlockPointer:
case MemberPointer:
@@ -515,8 +521,8 @@ void TypeOfTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo>
::initializeLocal(Context, Loc);
- this->getLocalData()->UnderlyingTInfo = Context.getTrivialTypeSourceInfo(
- getUnderlyingType(), Loc);
+ this->getLocalData()->UnmodifiedTInfo =
+ Context.getTrivialTypeSourceInfo(getUnmodifiedType(), Loc);
}
void UnaryTransformTypeLoc::initializeLocal(ASTContext &Context,
@@ -530,6 +536,8 @@ void UnaryTransformTypeLoc::initializeLocal(ASTContext &Context,
void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
+ if (isEmpty())
+ return;
setElaboratedKeywordLoc(Loc);
NestedNameSpecifierLocBuilder Builder;
Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
@@ -560,17 +568,14 @@ DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
setTemplateNameLoc(Loc);
setLAngleLoc(Loc);
setRAngleLoc(Loc);
- TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
- getTypePtr()->getArgs(),
- getArgInfos(), Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(
+ Context, getTypePtr()->template_arguments(), getArgInfos(), Loc);
}
-void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
- unsigned NumArgs,
- const TemplateArgument *Args,
- TemplateArgumentLocInfo *ArgInfos,
- SourceLocation Loc) {
- for (unsigned i = 0, e = NumArgs; i != e; ++i) {
+void TemplateSpecializationTypeLoc::initializeArgLocs(
+ ASTContext &Context, ArrayRef<TemplateArgument> Args,
+ TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc) {
+ for (unsigned i = 0, e = Args.size(); i != e; ++i) {
switch (Args[i].getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Impossible TemplateArgument");
@@ -627,9 +632,8 @@ void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
setRAngleLoc(Loc);
setLAngleLoc(Loc);
setRParenLoc(Loc);
- TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
- getTypePtr()->getArgs(),
- getArgInfos(), Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(
+ Context, getTypePtr()->getTypeConstraintArguments(), getArgInfos(), Loc);
setNameLoc(Loc);
}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 6b13d3806037..5c2464904485 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
+#include "clang/AST/TextNodeDumper.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/ExceptionSpecificationType.h"
@@ -32,6 +33,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -47,109 +49,103 @@ using namespace clang;
namespace {
- /// RAII object that enables printing of the ARC __strong lifetime
- /// qualifier.
- class IncludeStrongLifetimeRAII {
- PrintingPolicy &Policy;
- bool Old;
-
- public:
- explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
- : Policy(Policy), Old(Policy.SuppressStrongLifetime) {
- if (!Policy.SuppressLifetimeQualifiers)
- Policy.SuppressStrongLifetime = false;
- }
+/// RAII object that enables printing of the ARC __strong lifetime
+/// qualifier.
+class IncludeStrongLifetimeRAII {
+ PrintingPolicy &Policy;
+ bool Old;
+
+public:
+ explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
+ : Policy(Policy), Old(Policy.SuppressStrongLifetime) {
+ if (!Policy.SuppressLifetimeQualifiers)
+ Policy.SuppressStrongLifetime = false;
+ }
- ~IncludeStrongLifetimeRAII() {
- Policy.SuppressStrongLifetime = Old;
- }
- };
+ ~IncludeStrongLifetimeRAII() { Policy.SuppressStrongLifetime = Old; }
+};
- class ParamPolicyRAII {
- PrintingPolicy &Policy;
- bool Old;
+class ParamPolicyRAII {
+ PrintingPolicy &Policy;
+ bool Old;
- public:
- explicit ParamPolicyRAII(PrintingPolicy &Policy)
- : Policy(Policy), Old(Policy.SuppressSpecifiers) {
- Policy.SuppressSpecifiers = false;
- }
+public:
+ explicit ParamPolicyRAII(PrintingPolicy &Policy)
+ : Policy(Policy), Old(Policy.SuppressSpecifiers) {
+ Policy.SuppressSpecifiers = false;
+ }
- ~ParamPolicyRAII() {
- Policy.SuppressSpecifiers = Old;
- }
- };
+ ~ParamPolicyRAII() { Policy.SuppressSpecifiers = Old; }
+};
- class DefaultTemplateArgsPolicyRAII {
- PrintingPolicy &Policy;
- bool Old;
+class DefaultTemplateArgsPolicyRAII {
+ PrintingPolicy &Policy;
+ bool Old;
- public:
- explicit DefaultTemplateArgsPolicyRAII(PrintingPolicy &Policy)
- : Policy(Policy), Old(Policy.SuppressDefaultTemplateArgs) {
- Policy.SuppressDefaultTemplateArgs = false;
- }
+public:
+ explicit DefaultTemplateArgsPolicyRAII(PrintingPolicy &Policy)
+ : Policy(Policy), Old(Policy.SuppressDefaultTemplateArgs) {
+ Policy.SuppressDefaultTemplateArgs = false;
+ }
- ~DefaultTemplateArgsPolicyRAII() {
- Policy.SuppressDefaultTemplateArgs = Old;
- }
- };
-
- class ElaboratedTypePolicyRAII {
- PrintingPolicy &Policy;
- bool SuppressTagKeyword;
- bool SuppressScope;
-
- public:
- explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy) : Policy(Policy) {
- SuppressTagKeyword = Policy.SuppressTagKeyword;
- SuppressScope = Policy.SuppressScope;
- Policy.SuppressTagKeyword = true;
- Policy.SuppressScope = true;
- }
+ ~DefaultTemplateArgsPolicyRAII() { Policy.SuppressDefaultTemplateArgs = Old; }
+};
- ~ElaboratedTypePolicyRAII() {
- Policy.SuppressTagKeyword = SuppressTagKeyword;
- Policy.SuppressScope = SuppressScope;
- }
- };
-
- class TypePrinter {
- PrintingPolicy Policy;
- unsigned Indentation;
- bool HasEmptyPlaceHolder = false;
- bool InsideCCAttribute = false;
-
- public:
- explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0)
- : Policy(Policy), Indentation(Indentation) {}
-
- void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
- StringRef PlaceHolder);
- void print(QualType T, raw_ostream &OS, StringRef PlaceHolder);
-
- static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier);
- void spaceBeforePlaceHolder(raw_ostream &OS);
- void printTypeSpec(NamedDecl *D, raw_ostream &OS);
- void printTemplateId(const TemplateSpecializationType *T, raw_ostream &OS,
- bool FullyQualify);
-
- void printBefore(QualType T, raw_ostream &OS);
- void printAfter(QualType T, raw_ostream &OS);
- void AppendScope(DeclContext *DC, raw_ostream &OS,
- DeclarationName NameInScope);
- void printTag(TagDecl *T, raw_ostream &OS);
- void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
+class ElaboratedTypePolicyRAII {
+ PrintingPolicy &Policy;
+ bool SuppressTagKeyword;
+ bool SuppressScope;
+
+public:
+ explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy) : Policy(Policy) {
+ SuppressTagKeyword = Policy.SuppressTagKeyword;
+ SuppressScope = Policy.SuppressScope;
+ Policy.SuppressTagKeyword = true;
+ Policy.SuppressScope = true;
+ }
+
+ ~ElaboratedTypePolicyRAII() {
+ Policy.SuppressTagKeyword = SuppressTagKeyword;
+ Policy.SuppressScope = SuppressScope;
+ }
+};
+
+class TypePrinter {
+ PrintingPolicy Policy;
+ unsigned Indentation;
+ bool HasEmptyPlaceHolder = false;
+ bool InsideCCAttribute = false;
+
+public:
+ explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0)
+ : Policy(Policy), Indentation(Indentation) {}
+
+ void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
+ StringRef PlaceHolder);
+ void print(QualType T, raw_ostream &OS, StringRef PlaceHolder);
+
+ static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier);
+ void spaceBeforePlaceHolder(raw_ostream &OS);
+ void printTypeSpec(NamedDecl *D, raw_ostream &OS);
+ void printTemplateId(const TemplateSpecializationType *T, raw_ostream &OS,
+ bool FullyQualify);
+
+ void printBefore(QualType T, raw_ostream &OS);
+ void printAfter(QualType T, raw_ostream &OS);
+ void AppendScope(DeclContext *DC, raw_ostream &OS,
+ DeclarationName NameInScope);
+ void printTag(TagDecl *T, raw_ostream &OS);
+ void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
#define ABSTRACT_TYPE(CLASS, PARENT)
-#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);
+#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.inc"
- private:
- void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
- void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS);
- };
+private:
+ void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
+ void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS);
+};
} // namespace
@@ -199,7 +195,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS,
return;
}
- SaveAndRestore<bool> PHVal(HasEmptyPlaceHolder, PlaceHolder.empty());
+ SaveAndRestore PHVal(HasEmptyPlaceHolder, PlaceHolder.empty());
printBefore(T, Quals, OS);
OS << PlaceHolder;
@@ -262,7 +258,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::VariableArray:
case Type::DependentSizedArray:
NeedARCStrongQualifier = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::ConstantArray:
case Type::IncompleteArray:
@@ -323,7 +319,7 @@ void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) {
if (Policy.SuppressSpecifiers && T->isSpecifierType())
return;
- SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder);
+ SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder);
// Print qualifiers as appropriate.
@@ -400,7 +396,7 @@ void TypePrinter::printComplexAfter(const ComplexType *T, raw_ostream &OS) {
void TypePrinter::printPointerBefore(const PointerType *T, raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
printBefore(T->getPointeeType(), OS);
// Handle things like 'int (*A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
@@ -411,7 +407,7 @@ void TypePrinter::printPointerBefore(const PointerType *T, raw_ostream &OS) {
void TypePrinter::printPointerAfter(const PointerType *T, raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
// Handle things like 'int (*A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
if (isa<ArrayType>(T->getPointeeType()))
@@ -421,14 +417,14 @@ void TypePrinter::printPointerAfter(const PointerType *T, raw_ostream &OS) {
void TypePrinter::printBlockPointerBefore(const BlockPointerType *T,
raw_ostream &OS) {
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
printBefore(T->getPointeeType(), OS);
OS << '^';
}
void TypePrinter::printBlockPointerAfter(const BlockPointerType *T,
raw_ostream &OS) {
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
printAfter(T->getPointeeType(), OS);
}
@@ -443,7 +439,7 @@ static QualType skipTopLevelReferences(QualType T) {
void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
printBefore(Inner, OS);
// Handle things like 'int (&A)[4];' correctly.
@@ -456,7 +452,7 @@ void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T,
void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
// Handle things like 'int (&A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
@@ -468,7 +464,7 @@ void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T,
void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
printBefore(Inner, OS);
// Handle things like 'int (&&A)[4];' correctly.
@@ -481,7 +477,7 @@ void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T,
void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
// Handle things like 'int (&&A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
@@ -493,7 +489,7 @@ void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T,
void TypePrinter::printMemberPointerBefore(const MemberPointerType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
printBefore(T->getPointeeType(), OS);
// Handle things like 'int (Cls::*A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
@@ -510,7 +506,7 @@ void TypePrinter::printMemberPointerBefore(const MemberPointerType *T,
void TypePrinter::printMemberPointerAfter(const MemberPointerType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
// Handle things like 'int (Cls::*A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
if (isa<ArrayType>(T->getPointeeType()))
@@ -852,7 +848,7 @@ void TypePrinter::printFunctionProtoBefore(const FunctionProtoType *T,
OS << '(';
} else {
// If needed for precedence reasons, wrap the inner part in grouping parens.
- SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
+ SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder, false);
printBefore(T->getReturnType(), OS);
if (!PrevPHIsEmpty.get())
OS << '(';
@@ -880,7 +876,7 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!HasEmptyPlaceHolder)
OS << ')';
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
OS << '(';
{
@@ -1031,7 +1027,7 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T,
raw_ostream &OS) {
// If needed for precedence reasons, wrap the inner part in grouping parens.
- SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
+ SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder, false);
printBefore(T->getReturnType(), OS);
if (!PrevPHIsEmpty.get())
OS << '(';
@@ -1042,7 +1038,7 @@ void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T,
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!HasEmptyPlaceHolder)
OS << ')';
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
OS << "()";
printFunctionAfter(T->getExtInfo(), OS);
@@ -1108,7 +1104,8 @@ void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) {}
void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T,
raw_ostream &OS) {
- OS << "typeof ";
+ OS << (T->getKind() == TypeOfKind::Unqualified ? "typeof_unqual "
+ : "typeof ");
if (T->getUnderlyingExpr())
T->getUnderlyingExpr()->printPretty(OS, nullptr, Policy);
spaceBeforePlaceHolder(OS);
@@ -1118,8 +1115,9 @@ void TypePrinter::printTypeOfExprAfter(const TypeOfExprType *T,
raw_ostream &OS) {}
void TypePrinter::printTypeOfBefore(const TypeOfType *T, raw_ostream &OS) {
- OS << "typeof(";
- print(T->getUnderlyingType(), OS, StringRef());
+ OS << (T->getKind() == TypeOfKind::Unqualified ? "typeof_unqual("
+ : "typeof(");
+ print(T->getUnmodifiedType(), OS, StringRef());
OS << ')';
spaceBeforePlaceHolder(OS);
}
@@ -1140,29 +1138,19 @@ void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- OS << "__underlying_type(";
- print(T->getBaseType(), OS, StringRef());
- OS << ')';
- spaceBeforePlaceHolder(OS);
- return;
- }
-
- printBefore(T->getBaseType(), OS);
+ static llvm::DenseMap<int, const char *> Transformation = {{
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ {UnaryTransformType::Enum, "__" #Trait},
+#include "clang/Basic/TransformTypeTraits.def"
+ }};
+ OS << Transformation[T->getUTTKind()] << '(';
+ print(T->getBaseType(), OS, StringRef());
+ OS << ')';
+ spaceBeforePlaceHolder(OS);
}
void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
-
- switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- return;
- }
-
- printAfter(T->getBaseType(), OS);
-}
+ raw_ostream &OS) {}
void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
// If the type has been deduced, do not print 'auto'.
@@ -1470,14 +1458,27 @@ void TypePrinter::printSubstTemplateTypeParmPackBefore(
const SubstTemplateTypeParmPackType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- printTemplateTypeParmBefore(T->getReplacedParameter(), OS);
+ if (const TemplateTypeParmDecl *D = T->getReplacedParameter()) {
+ if (D && D->isImplicit()) {
+ if (auto *TC = D->getTypeConstraint()) {
+ TC->print(OS, Policy);
+ OS << ' ';
+ }
+ OS << "auto";
+ } else if (IdentifierInfo *Id = D->getIdentifier())
+ OS << (Policy.CleanUglifiedParameters ? Id->deuglifiedName()
+ : Id->getName());
+ else
+ OS << "type-parameter-" << D->getDepth() << '-' << D->getIndex();
+
+ spaceBeforePlaceHolder(OS);
+ }
}
void TypePrinter::printSubstTemplateTypeParmPackAfter(
const SubstTemplateTypeParmPackType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- printTemplateTypeParmAfter(T->getReplacedParameter(), OS);
}
void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
@@ -1675,7 +1676,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
// If this is a calling convention attribute, don't print the implicit CC from
// the modified type.
- SaveAndRestore<bool> MaybeSuppressCC(InsideCCAttribute, T->isCallingConv());
+ SaveAndRestore MaybeSuppressCC(InsideCCAttribute, T->isCallingConv());
printAfter(T->getModifiedType(), OS);
@@ -1733,6 +1734,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::OpenCLLocalAddressSpace:
case attr::OpenCLConstantAddressSpace:
case attr::OpenCLGenericAddressSpace:
+ case attr::HLSLGroupSharedAddressSpace:
// FIXME: Update printAttributedBefore to print these once we generate
// AttributedType nodes for them.
break;
@@ -1992,11 +1994,11 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(),
Args, Depth))
return false;
- if (TemplateArgs.size() != PTST->getNumArgs())
+ if (TemplateArgs.size() != PTST->template_arguments().size())
return false;
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PTST->getArg(I),
- Args, Depth))
+ if (!isSubstitutedTemplateArgument(
+ Ctx, TemplateArgs[I], PTST->template_arguments()[I], Args, Depth))
return false;
return true;
}
@@ -2023,6 +2025,16 @@ static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
}
}
+ if (Arg.getKind() == TemplateArgument::Integral &&
+ Pattern.getKind() == TemplateArgument::Expression) {
+ Expr const *expr = Pattern.getAsExpr();
+
+ if (!expr->isValueDependent() && expr->isIntegerConstantExpr(Ctx)) {
+ return llvm::APSInt::isSameValue(expr->EvaluateKnownConstInt(Ctx),
+ Arg.getAsIntegral());
+ }
+ }
+
if (Arg.getKind() != Pattern.getKind())
return false;
@@ -2042,9 +2054,7 @@ static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
return false;
}
-/// Make a best-effort determination of whether the type T can be produced by
-/// substituting Args into the default argument of Param.
-static bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
+bool clang::isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
const NamedDecl *Param,
ArrayRef<TemplateArgument> Args,
unsigned Depth) {
@@ -2228,6 +2238,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
return "__uptr __ptr32";
case LangAS::ptr64:
return "__ptr64";
+ case LangAS::hlsl_groupshared:
+ return "groupshared";
default:
return std::to_string(toTargetAddressSpace(AS));
}
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index 3d64cb17fa9c..bc9a83bde8a0 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -670,8 +670,9 @@ CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
// Under the relative ABI, the offset widths are 32-bit ints instead of
// pointer widths.
CharUnits OffsetWidth = Context.toCharUnitsFromBits(
- VTables.isRelativeLayout() ? 32
- : Context.getTargetInfo().getPointerWidth(0));
+ VTables.isRelativeLayout()
+ ? 32
+ : Context.getTargetInfo().getPointerWidth(LangAS::Default));
CharUnits OffsetOffset = OffsetWidth * OffsetIndex;
return OffsetOffset;
diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
index ac8e4eccad8e..a27fac62bdef 100644
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -779,7 +779,7 @@ private:
#define IMPL(Index) \
template <typename NodeType> \
- typename std::enable_if_t< \
+ std::enable_if_t< \
llvm::is_one_of<const NodeType *, CMD_TYPES_##Index>::value> \
SetCallbackAndRawNode(const MatchCallback *CB, const NodeType &N) { \
assertEmpty(); \
@@ -788,8 +788,8 @@ private:
} \
\
template <typename T> \
- typename std::enable_if_t< \
- llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, const T *> \
+ std::enable_if_t<llvm::is_one_of<const T *, CMD_TYPES_##Index>::value, \
+ const T *> \
getNode() const { \
assertHoldsState(); \
return Callback.getInt() == (Index) ? Node##Index.dyn_cast<const T *>() \
@@ -1562,7 +1562,7 @@ MatchFinder::~MatchFinder() {}
void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
MatchCallback *Action) {
- llvm::Optional<TraversalKind> TK;
+ std::optional<TraversalKind> TK;
if (Action)
TK = Action->getCheckTraversalKind();
if (TK)
@@ -1580,7 +1580,7 @@ void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
MatchCallback *Action) {
- llvm::Optional<TraversalKind> TK;
+ std::optional<TraversalKind> TK;
if (Action)
TK = Action->getCheckTraversalKind();
if (TK)
@@ -1685,9 +1685,9 @@ void MatchFinder::registerTestCallbackAfterParsing(
StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; }
-llvm::Optional<TraversalKind>
+std::optional<TraversalKind>
MatchFinder::MatchCallback::getCheckTraversalKind() const {
- return llvm::None;
+ return std::nullopt;
}
} // end namespace ast_matchers
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 4c438f9e4879..f1f73fc42075 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -22,7 +22,6 @@
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -35,6 +34,7 @@
#include <algorithm>
#include <cassert>
#include <cstddef>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -140,7 +140,7 @@ public:
return Result;
}
- llvm::Optional<clang::TraversalKind> TraversalKind() const override {
+ std::optional<clang::TraversalKind> TraversalKind() const override {
return InnerMatcher->TraversalKind();
}
@@ -176,7 +176,7 @@ public:
return this->InnerMatcher->dynMatches(DynNode, Finder, Builder);
}
- llvm::Optional<clang::TraversalKind> TraversalKind() const override {
+ std::optional<clang::TraversalKind> TraversalKind() const override {
return TK;
}
@@ -339,8 +339,9 @@ bool DynTypedMatcher::matchesNoKindCheck(const DynTypedNode &DynNode,
return false;
}
-llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const {
- if (!AllowBind) return llvm::None;
+std::optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const {
+ if (!AllowBind)
+ return std::nullopt;
auto Result = *this;
Result.Implementation =
new IdDynMatcher(ID, std::move(Result.Implementation));
@@ -685,7 +686,7 @@ static bool isTokenAtLoc(const SourceManager &SM, const LangOptions &LangOpts,
return !Invalid && Text == TokenText;
}
-llvm::Optional<SourceLocation>
+std::optional<SourceLocation>
getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc,
const ASTContext &Context) {
auto &SM = Context.getSourceManager();
@@ -696,14 +697,14 @@ getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc,
if (Expansion.isMacroArgExpansion())
// Check macro argument for an expansion of the given macro. For example,
// `F(G(3))`, where `MacroName` is `G`.
- if (llvm::Optional<SourceLocation> ArgLoc = getExpansionLocOfMacro(
+ if (std::optional<SourceLocation> ArgLoc = getExpansionLocOfMacro(
MacroName, Expansion.getSpellingLoc(), Context))
return ArgLoc;
Loc = Expansion.getExpansionLocStart();
if (isTokenAtLoc(SM, LangOpts, MacroName, Loc))
return Loc;
}
- return llvm::None;
+ return std::nullopt;
}
std::shared_ptr<llvm::Regex> createAndVerifyRegex(StringRef Regex,
diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp
index 70b5953fe969..cf9ae7c974a6 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp
@@ -8,12 +8,12 @@
#include "Marshallers.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Regex.h"
+#include <optional>
#include <string>
-static llvm::Optional<std::string>
+static std::optional<std::string>
getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed,
llvm::StringRef DropPrefix = "", unsigned MaxEditDistance = 3) {
if (MaxEditDistance != ~0U)
@@ -56,10 +56,10 @@ getBestGuess(llvm::StringRef Search, llvm::ArrayRef<llvm::StringRef> Allowed,
if (!Res.empty())
return Res.str();
}
- return llvm::None;
+ return std::nullopt;
}
-llvm::Optional<std::string>
+std::optional<std::string>
clang::ast_matchers::dynamic::internal::ArgTypeTraits<
clang::attr::Kind>::getBestGuess(const VariantValue &Value) {
static constexpr llvm::StringRef Allowed[] = {
@@ -67,12 +67,11 @@ clang::ast_matchers::dynamic::internal::ArgTypeTraits<
#include "clang/Basic/AttrList.inc"
};
if (Value.isString())
- return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
- "attr::");
- return llvm::None;
+ return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "attr::");
+ return std::nullopt;
}
-llvm::Optional<std::string>
+std::optional<std::string>
clang::ast_matchers::dynamic::internal::ArgTypeTraits<
clang::CastKind>::getBestGuess(const VariantValue &Value) {
static constexpr llvm::StringRef Allowed[] = {
@@ -80,12 +79,11 @@ clang::ast_matchers::dynamic::internal::ArgTypeTraits<
#include "clang/AST/OperationKinds.def"
};
if (Value.isString())
- return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
- "CK_");
- return llvm::None;
+ return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "CK_");
+ return std::nullopt;
}
-llvm::Optional<std::string>
+std::optional<std::string>
clang::ast_matchers::dynamic::internal::ArgTypeTraits<
clang::OpenMPClauseKind>::getBestGuess(const VariantValue &Value) {
static constexpr llvm::StringRef Allowed[] = {
@@ -94,12 +92,11 @@ clang::ast_matchers::dynamic::internal::ArgTypeTraits<
#include "llvm/Frontend/OpenMP/OMP.inc"
};
if (Value.isString())
- return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
- "OMPC_");
- return llvm::None;
+ return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "OMPC_");
+ return std::nullopt;
}
-llvm::Optional<std::string>
+std::optional<std::string>
clang::ast_matchers::dynamic::internal::ArgTypeTraits<
clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) {
static constexpr llvm::StringRef Allowed[] = {
@@ -108,9 +105,8 @@ clang::ast_matchers::dynamic::internal::ArgTypeTraits<
#include "clang/Basic/TokenKinds.def"
};
if (Value.isString())
- return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed),
- "UETT_");
- return llvm::None;
+ return ::getBestGuess(Value.getString(), llvm::ArrayRef(Allowed), "UETT_");
+ return std::nullopt;
}
static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags>
@@ -121,55 +117,54 @@ static constexpr std::pair<llvm::StringRef, llvm::Regex::RegexFlags>
{"BasicRegex", llvm::Regex::RegexFlags::BasicRegex},
};
-static llvm::Optional<llvm::Regex::RegexFlags>
+static std::optional<llvm::Regex::RegexFlags>
getRegexFlag(llvm::StringRef Flag) {
for (const auto &StringFlag : RegexMap) {
if (Flag == StringFlag.first)
return StringFlag.second;
}
- return llvm::None;
+ return std::nullopt;
}
-static llvm::Optional<llvm::StringRef>
-getCloseRegexMatch(llvm::StringRef Flag) {
+static std::optional<llvm::StringRef> getCloseRegexMatch(llvm::StringRef Flag) {
for (const auto &StringFlag : RegexMap) {
if (Flag.edit_distance(StringFlag.first) < 3)
return StringFlag.first;
}
- return llvm::None;
+ return std::nullopt;
}
-llvm::Optional<llvm::Regex::RegexFlags>
+std::optional<llvm::Regex::RegexFlags>
clang::ast_matchers::dynamic::internal::ArgTypeTraits<
llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) {
- llvm::Optional<llvm::Regex::RegexFlags> Flag;
+ std::optional<llvm::Regex::RegexFlags> Flag;
SmallVector<StringRef, 4> Split;
Flags.split(Split, '|', -1, false);
for (StringRef OrFlag : Split) {
- if (llvm::Optional<llvm::Regex::RegexFlags> NextFlag =
+ if (std::optional<llvm::Regex::RegexFlags> NextFlag =
getRegexFlag(OrFlag.trim()))
Flag = Flag.value_or(llvm::Regex::NoFlags) | *NextFlag;
else
- return None;
+ return std::nullopt;
}
return Flag;
}
-llvm::Optional<std::string>
+std::optional<std::string>
clang::ast_matchers::dynamic::internal::ArgTypeTraits<
llvm::Regex::RegexFlags>::getBestGuess(const VariantValue &Value) {
if (!Value.isString())
- return llvm::None;
+ return std::nullopt;
SmallVector<StringRef, 4> Split;
llvm::StringRef(Value.getString()).split(Split, '|', -1, false);
for (llvm::StringRef &Flag : Split) {
- if (llvm::Optional<llvm::StringRef> BestGuess =
+ if (std::optional<llvm::StringRef> BestGuess =
getCloseRegexMatch(Flag.trim()))
Flag = *BestGuess;
else
- return None;
+ return std::nullopt;
}
if (Split.empty())
- return None;
+ return std::nullopt;
return llvm::join(Split, " | ");
}
diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
index bab36e5db47e..1b099ec3a314 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -29,8 +29,6 @@
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/TypeTraits.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@@ -41,6 +39,7 @@
#include <iterator>
#include <limits>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -71,8 +70,8 @@ template <> struct ArgTypeTraits<std::string> {
return ArgKind(ArgKind::AK_String);
}
- static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
- return llvm::None;
+ static std::optional<std::string> getBestGuess(const VariantValue &) {
+ return std::nullopt;
}
};
@@ -96,8 +95,8 @@ template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T>> {
return ArgKind::MakeMatcherArg(ASTNodeKind::getFromNodeKind<T>());
}
- static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
- return llvm::None;
+ static std::optional<std::string> getBestGuess(const VariantValue &) {
+ return std::nullopt;
}
};
@@ -115,8 +114,8 @@ template <> struct ArgTypeTraits<bool> {
return ArgKind(ArgKind::AK_Boolean);
}
- static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
- return llvm::None;
+ static std::optional<std::string> getBestGuess(const VariantValue &) {
+ return std::nullopt;
}
};
@@ -134,8 +133,8 @@ template <> struct ArgTypeTraits<double> {
return ArgKind(ArgKind::AK_Double);
}
- static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
- return llvm::None;
+ static std::optional<std::string> getBestGuess(const VariantValue &) {
+ return std::nullopt;
}
};
@@ -153,20 +152,20 @@ template <> struct ArgTypeTraits<unsigned> {
return ArgKind(ArgKind::AK_Unsigned);
}
- static llvm::Optional<std::string> getBestGuess(const VariantValue &) {
- return llvm::None;
+ static std::optional<std::string> getBestGuess(const VariantValue &) {
+ return std::nullopt;
}
};
template <> struct ArgTypeTraits<attr::Kind> {
private:
- static Optional<attr::Kind> getAttrKind(llvm::StringRef AttrKind) {
+ static std::optional<attr::Kind> getAttrKind(llvm::StringRef AttrKind) {
if (!AttrKind.consume_front("attr::"))
- return llvm::None;
- return llvm::StringSwitch<Optional<attr::Kind>>(AttrKind)
+ return std::nullopt;
+ return llvm::StringSwitch<std::optional<attr::Kind>>(AttrKind)
#define ATTR(X) .Case(#X, attr::X)
#include "clang/Basic/AttrList.inc"
- .Default(llvm::None);
+ .Default(std::nullopt);
}
public:
@@ -185,18 +184,18 @@ public:
return ArgKind(ArgKind::AK_String);
}
- static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
+ static std::optional<std::string> getBestGuess(const VariantValue &Value);
};
template <> struct ArgTypeTraits<CastKind> {
private:
- static Optional<CastKind> getCastKind(llvm::StringRef AttrKind) {
+ static std::optional<CastKind> getCastKind(llvm::StringRef AttrKind) {
if (!AttrKind.consume_front("CK_"))
- return llvm::None;
- return llvm::StringSwitch<Optional<CastKind>>(AttrKind)
+ return std::nullopt;
+ return llvm::StringSwitch<std::optional<CastKind>>(AttrKind)
#define CAST_OPERATION(Name) .Case(#Name, CK_##Name)
#include "clang/AST/OperationKinds.def"
- .Default(llvm::None);
+ .Default(std::nullopt);
}
public:
@@ -215,12 +214,12 @@ public:
return ArgKind(ArgKind::AK_String);
}
- static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
+ static std::optional<std::string> getBestGuess(const VariantValue &Value);
};
template <> struct ArgTypeTraits<llvm::Regex::RegexFlags> {
private:
- static Optional<llvm::Regex::RegexFlags> getFlags(llvm::StringRef Flags);
+ static std::optional<llvm::Regex::RegexFlags> getFlags(llvm::StringRef Flags);
public:
static bool hasCorrectType(const VariantValue &Value) {
@@ -236,17 +235,18 @@ public:
static ArgKind getKind() { return ArgKind(ArgKind::AK_String); }
- static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
+ static std::optional<std::string> getBestGuess(const VariantValue &Value);
};
template <> struct ArgTypeTraits<OpenMPClauseKind> {
private:
- static Optional<OpenMPClauseKind> getClauseKind(llvm::StringRef ClauseKind) {
- return llvm::StringSwitch<Optional<OpenMPClauseKind>>(ClauseKind)
+ static std::optional<OpenMPClauseKind>
+ getClauseKind(llvm::StringRef ClauseKind) {
+ return llvm::StringSwitch<std::optional<OpenMPClauseKind>>(ClauseKind)
#define GEN_CLANG_CLAUSE_CLASS
#define CLAUSE_CLASS(Enum, Str, Class) .Case(#Enum, llvm::omp::Clause::Enum)
#include "llvm/Frontend/OpenMP/OMP.inc"
- .Default(llvm::None);
+ .Default(std::nullopt);
}
public:
@@ -263,21 +263,21 @@ public:
static ArgKind getKind() { return ArgKind(ArgKind::AK_String); }
- static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
+ static std::optional<std::string> getBestGuess(const VariantValue &Value);
};
template <> struct ArgTypeTraits<UnaryExprOrTypeTrait> {
private:
- static Optional<UnaryExprOrTypeTrait>
+ static std::optional<UnaryExprOrTypeTrait>
getUnaryOrTypeTraitKind(llvm::StringRef ClauseKind) {
if (!ClauseKind.consume_front("UETT_"))
- return llvm::None;
- return llvm::StringSwitch<Optional<UnaryExprOrTypeTrait>>(ClauseKind)
+ return std::nullopt;
+ return llvm::StringSwitch<std::optional<UnaryExprOrTypeTrait>>(ClauseKind)
#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) .Case(#Name, UETT_##Name)
#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \
.Case(#Name, UETT_##Name)
#include "clang/Basic/TokenKinds.def"
- .Default(llvm::None);
+ .Default(std::nullopt);
}
public:
@@ -294,7 +294,7 @@ public:
static ArgKind getKind() { return ArgKind(ArgKind::AK_String); }
- static llvm::Optional<std::string> getBestGuess(const VariantValue &Value);
+ static std::optional<std::string> getBestGuess(const VariantValue &Value);
};
/// Matcher descriptor interface.
@@ -508,7 +508,7 @@ variadicMatcherDescriptor(StringRef MatcherName, SourceRange NameRange,
return {};
}
if (!ArgTraits::hasCorrectValue(Value)) {
- if (llvm::Optional<std::string> BestGuess =
+ if (std::optional<std::string> BestGuess =
ArgTraits::getBestGuess(Value)) {
Error->addError(Arg.Range, Error->ET_RegistryUnknownEnumWithReplace)
<< i + 1 << Value.getString() << *BestGuess;
@@ -635,7 +635,7 @@ private:
return VariantMatcher(); \
} \
if (!ArgTypeTraits<type>::hasCorrectValue(Args[index].Value)) { \
- if (llvm::Optional<std::string> BestGuess = \
+ if (std::optional<std::string> BestGuess = \
ArgTypeTraits<type>::getBestGuess(Args[index].Value)) { \
Error->addError(Args[index].Range, \
Error->ET_RegistryUnknownEnumWithReplace) \
@@ -845,7 +845,7 @@ public:
}
if (!ArgTypeTraits<llvm::Regex::RegexFlags>::hasCorrectValue(
Args[1].Value)) {
- if (llvm::Optional<std::string> BestGuess =
+ if (std::optional<std::string> BestGuess =
ArgTypeTraits<llvm::Regex::RegexFlags>::getBestGuess(
Args[1].Value)) {
Error->addError(Args[1].Range, Error->ET_RegistryUnknownEnumWithReplace)
@@ -1060,7 +1060,7 @@ makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) {
BuildReturnTypeVector<ReturnType>::build(RetTypes);
return std::make_unique<FixedArgCountMatcherDescriptor>(
matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func),
- MatcherName, RetTypes, None);
+ MatcherName, RetTypes, std::nullopt);
}
/// 1-arg overload
diff --git a/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/clang/lib/ASTMatchers/Dynamic/Parser.cpp
index 6470df27e6e2..33a10fe838a6 100644
--- a/clang/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -16,7 +16,6 @@
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/Registry.h"
#include "clang/Basic/CharInfo.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
@@ -25,6 +24,7 @@
#include <cerrno>
#include <cstddef>
#include <cstdlib>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -395,10 +395,10 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
return false;
assert(NamedValue.isMatcher());
- llvm::Optional<DynTypedMatcher> Result =
+ std::optional<DynTypedMatcher> Result =
NamedValue.getMatcher().getSingleMatcher();
if (Result) {
- llvm::Optional<DynTypedMatcher> Bound = Result->tryBind(BindID);
+ std::optional<DynTypedMatcher> Bound = Result->tryBind(BindID);
if (Bound) {
*Value = VariantMatcher::SingleMatcher(*Bound);
return true;
@@ -438,7 +438,7 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
return false;
}
- llvm::Optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);
+ std::optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);
// Parse as a matcher expression.
return parseMatcherExpressionImpl(NameToken, OpenToken, Ctor, Value);
@@ -517,7 +517,7 @@ bool Parser::parseMatcherBuilder(MatcherCtor Ctor, const TokenInfo &NameToken,
ArgValue.Text = NodeMatcherToken.Text;
ArgValue.Range = NodeMatcherToken.Range;
- llvm::Optional<MatcherCtor> MappedMatcher =
+ std::optional<MatcherCtor> MappedMatcher =
S->lookupMatcherCtor(ArgValue.Text);
if (!MappedMatcher) {
@@ -628,7 +628,7 @@ bool Parser::parseMatcherBuilder(MatcherCtor Ctor, const TokenInfo &NameToken,
/// returns \c false.
bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
const TokenInfo &OpenToken,
- llvm::Optional<MatcherCtor> Ctor,
+ std::optional<MatcherCtor> Ctor,
VariantValue *Value) {
if (!Ctor) {
Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound)
@@ -828,7 +828,7 @@ Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
Parser::RegistrySema::~RegistrySema() = default;
-llvm::Optional<MatcherCtor>
+std::optional<MatcherCtor>
Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
return Registry::lookupMatcherCtor(MatcherName);
}
@@ -904,19 +904,18 @@ Parser::completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S,
return P.Completions;
}
-llvm::Optional<DynTypedMatcher>
+std::optional<DynTypedMatcher>
Parser::parseMatcherExpression(StringRef &Code, Sema *S,
const NamedValueMap *NamedValues,
Diagnostics *Error) {
VariantValue Value;
if (!parseExpression(Code, S, NamedValues, &Value, Error))
- return llvm::Optional<DynTypedMatcher>();
+ return std::nullopt;
if (!Value.isMatcher()) {
Error->addError(SourceRange(), Error->ET_ParserNotAMatcher);
- return llvm::Optional<DynTypedMatcher>();
+ return std::nullopt;
}
- llvm::Optional<DynTypedMatcher> Result =
- Value.getMatcher().getSingleMatcher();
+ std::optional<DynTypedMatcher> Result = Value.getMatcher().getSingleMatcher();
if (!Result) {
Error->addError(SourceRange(), Error->ET_ParserOverloadedType)
<< Value.getTypeAsString();
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 0a58652884ee..0d436fa29a79 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -17,7 +17,6 @@
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/Dynamic/Diagnostics.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -26,6 +25,7 @@
#include <cassert>
#include <iterator>
#include <memory>
+#include <optional>
#include <set>
#include <string>
#include <utility>
@@ -428,6 +428,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isPrivateKind);
REGISTER_MATCHER(isFirstPrivateKind);
REGISTER_MATCHER(isImplicit);
+ REGISTER_MATCHER(isInAnonymousNamespace);
REGISTER_MATCHER(isInStdNamespace);
REGISTER_MATCHER(isInTemplateInstantiation);
REGISTER_MATCHER(isInitCapture);
@@ -620,11 +621,10 @@ Registry::buildMatcherCtor(MatcherCtor Ctor, SourceRange NameRange,
}
// static
-llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
+std::optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
auto it = RegistryData->constructors().find(MatcherName);
- return it == RegistryData->constructors().end()
- ? llvm::Optional<MatcherCtor>()
- : it->second.get();
+ return it == RegistryData->constructors().end() ? std::optional<MatcherCtor>()
+ : it->second.get();
}
static llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
@@ -797,9 +797,9 @@ VariantMatcher Registry::constructBoundMatcher(MatcherCtor Ctor,
VariantMatcher Out = constructMatcher(Ctor, NameRange, Args, Error);
if (Out.isNull()) return Out;
- llvm::Optional<DynTypedMatcher> Result = Out.getSingleMatcher();
+ std::optional<DynTypedMatcher> Result = Out.getSingleMatcher();
if (Result) {
- llvm::Optional<DynTypedMatcher> Bound = Result->tryBind(BindID);
+ std::optional<DynTypedMatcher> Bound = Result->tryBind(BindID);
if (Bound) {
return VariantMatcher::SingleMatcher(*Bound);
}
diff --git a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
index 813eb1597756..4f6b021b26f0 100644
--- a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -14,6 +14,7 @@
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
namespace clang {
namespace ast_matchers {
@@ -66,7 +67,7 @@ DynTypedMatcher VariantMatcher::MatcherOps::convertMatcher(
return Matcher.dynCastTo(NodeKind);
}
-llvm::Optional<DynTypedMatcher>
+std::optional<DynTypedMatcher>
VariantMatcher::MatcherOps::constructVariadicOperator(
DynTypedMatcher::VariadicOperator Op,
ArrayRef<VariantMatcher> InnerMatchers) const {
@@ -75,11 +76,11 @@ VariantMatcher::MatcherOps::constructVariadicOperator(
// Abort if any of the inner matchers can't be converted to
// Matcher<T>.
if (!InnerMatcher.Value)
- return llvm::None;
- llvm::Optional<DynTypedMatcher> Inner =
+ return std::nullopt;
+ std::optional<DynTypedMatcher> Inner =
InnerMatcher.Value->getTypedMatcher(*this);
if (!Inner)
- return llvm::None;
+ return std::nullopt;
DynMatchers.push_back(*Inner);
}
return DynTypedMatcher::constructVariadic(Op, NodeKind, DynMatchers);
@@ -91,7 +92,7 @@ class VariantMatcher::SinglePayload : public VariantMatcher::Payload {
public:
SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {}
- llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
+ std::optional<DynTypedMatcher> getSingleMatcher() const override {
return Matcher;
}
@@ -100,12 +101,12 @@ public:
.str();
}
- llvm::Optional<DynTypedMatcher>
+ std::optional<DynTypedMatcher>
getTypedMatcher(const MatcherOps &Ops) const override {
bool Ignore;
if (Ops.canConstructFrom(Matcher, Ignore))
return Matcher;
- return llvm::None;
+ return std::nullopt;
}
bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {
@@ -124,9 +125,9 @@ public:
~PolymorphicPayload() override {}
- llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
+ std::optional<DynTypedMatcher> getSingleMatcher() const override {
if (Matchers.size() != 1)
- return llvm::Optional<DynTypedMatcher>();
+ return std::nullopt;
return Matchers[0];
}
@@ -140,7 +141,7 @@ public:
return (Twine("Matcher<") + Inner + ">").str();
}
- llvm::Optional<DynTypedMatcher>
+ std::optional<DynTypedMatcher>
getTypedMatcher(const MatcherOps &Ops) const override {
bool FoundIsExact = false;
const DynTypedMatcher *Found = nullptr;
@@ -162,7 +163,7 @@ public:
// We only succeed if we found exactly one, or if we found an exact match.
if (Found && (FoundIsExact || NumFound == 1))
return *Found;
- return llvm::None;
+ return std::nullopt;
}
bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity) const override {
@@ -189,8 +190,8 @@ public:
std::vector<VariantMatcher> Args)
: Op(Op), Args(std::move(Args)) {}
- llvm::Optional<DynTypedMatcher> getSingleMatcher() const override {
- return llvm::Optional<DynTypedMatcher>();
+ std::optional<DynTypedMatcher> getSingleMatcher() const override {
+ return std::nullopt;
}
std::string getTypeAsString() const override {
@@ -203,7 +204,7 @@ public:
return Inner;
}
- llvm::Optional<DynTypedMatcher>
+ std::optional<DynTypedMatcher>
getTypedMatcher(const MatcherOps &Ops) const override {
return Ops.constructVariadicOperator(Op, Args);
}
@@ -240,8 +241,8 @@ VariantMatcher VariantMatcher::VariadicOperatorMatcher(
std::make_shared<VariadicOpPayload>(Op, std::move(Args)));
}
-llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
- return Value ? Value->getSingleMatcher() : llvm::Optional<DynTypedMatcher>();
+std::optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const {
+ return Value ? Value->getSingleMatcher() : std::optional<DynTypedMatcher>();
}
void VariantMatcher::reset() { Value.reset(); }
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
index f20924604f64..d3a1a993711f 100644
--- a/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -142,7 +142,7 @@ bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const {
/// Returns true if \param VD is an Objective-C implicit 'self' parameter.
static bool isSelfDecl(const VarDecl *VD) {
- return isa<ImplicitParamDecl>(VD) && VD->getName() == "self";
+ return isa_and_nonnull<ImplicitParamDecl>(VD) && VD->getName() == "self";
}
const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
@@ -169,8 +169,8 @@ const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
if (!LC.capturesVariable())
continue;
- VarDecl *VD = LC.getCapturedVar();
- if (isSelfDecl(VD))
+ ValueDecl *VD = LC.getCapturedVar();
+ if (isSelfDecl(dyn_cast<VarDecl>(VD)))
return dyn_cast<ImplicitParamDecl>(VD);
}
@@ -231,8 +231,7 @@ CFG *AnalysisDeclContext::getCFG() {
CFG *AnalysisDeclContext::getUnoptimizedCFG() {
if (!builtCompleteCFG) {
- SaveAndRestore<bool> NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges,
- false);
+ SaveAndRestore NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges, false);
completeCFG =
CFG::buildCFG(D, getBody(), &D->getASTContext(), cfgBuildOptions);
// Even when the cfg is not successfully built, we don't
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index 38f100ae0a4f..c05534886cb5 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -24,6 +24,7 @@
#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
+#include <optional>
#define DEBUG_TYPE "body-farm"
@@ -541,7 +542,7 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) {
CallExpr *CE = CallExpr::Create(
/*ASTContext=*/C,
/*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Block),
- /*Args=*/None,
+ /*Args=*/std::nullopt,
/*QualType=*/C.VoidTy,
/*ExprValueType=*/VK_PRValue,
/*SourceLocation=*/SourceLocation(), FPOptionsOverride());
@@ -609,7 +610,7 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) {
ASTMaker M(C);
DeclRefExpr *DR = M.makeDeclRefExpr(PV);
ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
- CallExpr *CE = CallExpr::Create(C, ICE, None, C.VoidTy, VK_PRValue,
+ CallExpr *CE = CallExpr::Create(C, ICE, std::nullopt, C.VoidTy, VK_PRValue,
SourceLocation(), FPOptionsOverride());
return CE;
}
@@ -697,9 +698,9 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
}
Stmt *BodyFarm::getBody(const FunctionDecl *D) {
- Optional<Stmt *> &Val = Bodies[D];
+ std::optional<Stmt *> &Val = Bodies[D];
if (Val)
- return Val.value();
+ return *Val;
Val = nullptr;
@@ -872,9 +873,9 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
if (!D->isImplicit())
return nullptr;
- Optional<Stmt *> &Val = Bodies[D];
+ std::optional<Stmt *> &Val = Bodies[D];
if (Val)
- return Val.value();
+ return *Val;
Val = nullptr;
// For now, we only synthesize getters.
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 84178ff488a5..ea8b73e81ea2 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -40,7 +40,6 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -56,6 +55,7 @@
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -72,6 +72,10 @@ static SourceLocation GetEndLoc(Decl *D) {
/// Returns true on constant values based around a single IntegerLiteral.
/// Allow for use of parentheses, integer casts, and negative signs.
+/// FIXME: it would be good to unify this function with
+/// getIntegerLiteralSubexpressionValue at some point given the similarity
+/// between the functions.
+
static bool IsIntegerLiteralConstantExpr(const Expr *E) {
// Allow parentheses
E = E->IgnoreParens();
@@ -432,8 +436,8 @@ reverse_children::reverse_children(Stmt *S) {
// Note: Fill in this switch with more cases we want to optimize.
case Stmt::InitListExprClass: {
InitListExpr *IE = cast<InitListExpr>(S);
- children = llvm::makeArrayRef(reinterpret_cast<Stmt**>(IE->getInits()),
- IE->getNumInits());
+ children = llvm::ArrayRef(reinterpret_cast<Stmt **>(IE->getInits()),
+ IE->getNumInits());
return;
}
default:
@@ -723,9 +727,9 @@ private:
// hence strict duck-typing.
template <typename CallLikeExpr,
typename = std::enable_if_t<
- std::is_base_of<CallExpr, CallLikeExpr>::value ||
- std::is_base_of<CXXConstructExpr, CallLikeExpr>::value ||
- std::is_base_of<ObjCMessageExpr, CallLikeExpr>::value>>
+ std::is_base_of_v<CallExpr, CallLikeExpr> ||
+ std::is_base_of_v<CXXConstructExpr, CallLikeExpr> ||
+ std::is_base_of_v<ObjCMessageExpr, CallLikeExpr>>>
void findConstructionContextsForArguments(CallLikeExpr *E) {
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
Expr *Arg = E->getArg(i);
@@ -964,15 +968,16 @@ private:
const Expr *LHSExpr = B->getLHS()->IgnoreParens();
const Expr *RHSExpr = B->getRHS()->IgnoreParens();
- const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
+ std::optional<llvm::APInt> IntLiteral1 =
+ getIntegerLiteralSubexpressionValue(LHSExpr);
const Expr *BoolExpr = RHSExpr;
- if (!IntLiteral) {
- IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
+ if (!IntLiteral1) {
+ IntLiteral1 = getIntegerLiteralSubexpressionValue(RHSExpr);
BoolExpr = LHSExpr;
}
- if (!IntLiteral)
+ if (!IntLiteral1)
return TryResult();
const BinaryOperator *BitOp = dyn_cast<BinaryOperator>(BoolExpr);
@@ -981,26 +986,26 @@ private:
const Expr *LHSExpr2 = BitOp->getLHS()->IgnoreParens();
const Expr *RHSExpr2 = BitOp->getRHS()->IgnoreParens();
- const IntegerLiteral *IntLiteral2 = dyn_cast<IntegerLiteral>(LHSExpr2);
+ std::optional<llvm::APInt> IntLiteral2 =
+ getIntegerLiteralSubexpressionValue(LHSExpr2);
if (!IntLiteral2)
- IntLiteral2 = dyn_cast<IntegerLiteral>(RHSExpr2);
+ IntLiteral2 = getIntegerLiteralSubexpressionValue(RHSExpr2);
if (!IntLiteral2)
return TryResult();
- llvm::APInt L1 = IntLiteral->getValue();
- llvm::APInt L2 = IntLiteral2->getValue();
- if ((BitOp->getOpcode() == BO_And && (L2 & L1) != L1) ||
- (BitOp->getOpcode() == BO_Or && (L2 | L1) != L1)) {
+ if ((BitOp->getOpcode() == BO_And &&
+ (*IntLiteral2 & *IntLiteral1) != *IntLiteral1) ||
+ (BitOp->getOpcode() == BO_Or &&
+ (*IntLiteral2 | *IntLiteral1) != *IntLiteral1)) {
if (BuildOpts.Observer)
BuildOpts.Observer->compareBitwiseEquality(B,
B->getOpcode() != BO_EQ);
- TryResult(B->getOpcode() != BO_EQ);
+ return TryResult(B->getOpcode() != BO_EQ);
}
} else if (BoolExpr->isKnownToHaveBooleanValue()) {
- llvm::APInt IntValue = IntLiteral->getValue();
- if ((IntValue == 1) || (IntValue == 0)) {
+ if ((*IntLiteral1 == 1) || (*IntLiteral1 == 0)) {
return TryResult();
}
return TryResult(B->getOpcode() != BO_EQ);
@@ -1009,6 +1014,47 @@ private:
return TryResult();
}
+ // Helper function to get an APInt from an expression. Supports expressions
+ // which are an IntegerLiteral or a UnaryOperator and returns the value with
+ // all operations performed on it.
+ // FIXME: it would be good to unify this function with
+ // IsIntegerLiteralConstantExpr at some point given the similarity between the
+ // functions.
+ std::optional<llvm::APInt>
+ getIntegerLiteralSubexpressionValue(const Expr *E) {
+
+ // If unary.
+ if (const auto *UnOp = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
+ // Get the sub expression of the unary expression and get the Integer
+ // Literal.
+ const Expr *SubExpr = UnOp->getSubExpr()->IgnoreParens();
+
+ if (const auto *IntLiteral = dyn_cast<IntegerLiteral>(SubExpr)) {
+
+ llvm::APInt Value = IntLiteral->getValue();
+
+ // Perform the operation manually.
+ switch (UnOp->getOpcode()) {
+ case UO_Plus:
+ return Value;
+ case UO_Minus:
+ return -Value;
+ case UO_Not:
+ return ~Value;
+ case UO_LNot:
+ return llvm::APInt(Context->getTypeSize(Context->IntTy), !Value);
+ default:
+ assert(false && "Unexpected unary operator!");
+ return std::nullopt;
+ }
+ }
+ } else if (const auto *IntLiteral =
+ dyn_cast<IntegerLiteral>(E->IgnoreParens()))
+ return IntLiteral->getValue();
+
+ return std::nullopt;
+ }
+
TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
const llvm::APSInt &Value1,
const llvm::APSInt &Value2) {
@@ -1287,6 +1333,18 @@ private:
} // namespace
+Expr *
+clang::extractElementInitializerFromNestedAILE(const ArrayInitLoopExpr *AILE) {
+ if (!AILE)
+ return nullptr;
+
+ Expr *AILEInit = AILE->getSubExpr();
+ while (const auto *E = dyn_cast<ArrayInitLoopExpr>(AILEInit))
+ AILEInit = E->getSubExpr();
+
+ return AILEInit;
+}
+
inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder,
const Stmt *stmt) const {
return builder.alwaysAdd(stmt) || kind == AlwaysAdd;
@@ -1616,7 +1674,7 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
}
/// createBlock - Used to lazily create blocks that are connected
-/// to the current (global) succcessor.
+/// to the current (global) successor.
CFGBlock *CFGBuilder::createBlock(bool add_successor) {
CFGBlock *B = cfg->createBlock();
if (add_successor && Succ)
@@ -1661,11 +1719,12 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
if (Init) {
// If the initializer is an ArrayInitLoopExpr, we want to extract the
// initializer, that's used for each element.
- const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
+ auto *AILEInit = extractElementInitializerFromNestedAILE(
+ dyn_cast<ArrayInitLoopExpr>(Init));
findConstructionContexts(
ConstructionContextLayer::create(cfg->getBumpVectorContext(), I),
- AILE ? AILE->getSubExpr() : Init);
+ AILEInit ? AILEInit : Init);
if (HasTemporaries) {
// For expression with temporaries go directly to subexpression to omit
@@ -1891,7 +1950,7 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
// (which is different from the current class) is responsible for
// destroying them.
const CXXRecordDecl *CD = VI.getType()->getAsCXXRecordDecl();
- if (!CD->hasTrivialDestructor()) {
+ if (CD && !CD->hasTrivialDestructor()) {
autoCreateBlock();
appendBaseDtor(Block, &VI);
}
@@ -1901,7 +1960,7 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
for (const auto &BI : RD->bases()) {
if (!BI.isVirtual()) {
const CXXRecordDecl *CD = BI.getType()->getAsCXXRecordDecl();
- if (!CD->hasTrivialDestructor()) {
+ if (CD && !CD->hasTrivialDestructor()) {
autoCreateBlock();
appendBaseDtor(Block, &BI);
}
@@ -1912,9 +1971,10 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) {
for (auto *FI : RD->fields()) {
// Check for constant size array. Set type to array element type.
QualType QT = FI->getType();
- if (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
+ // It may be a multidimensional array.
+ while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) {
if (AT->getSize() == 0)
- continue;
+ break;
QT = AT->getElementType();
}
@@ -2935,7 +2995,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// If we bind to a tuple-like type, we iterate over the HoldingVars, and
// create a DeclStmt for each of them.
if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
- for (auto BD : llvm::reverse(DD->bindings())) {
+ for (auto *BD : llvm::reverse(DD->bindings())) {
if (auto *VD = BD->getHoldingVar()) {
DeclGroupRef DG(VD);
DeclStmt *DSNew =
@@ -3014,7 +3074,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for C++17 if init-stmt if one exists.
if (Stmt *Init = I->getInit())
@@ -3039,7 +3099,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
CFGBlock *ElseBlock = Succ;
if (Stmt *Else = I->getElse()) {
- SaveAndRestore<CFGBlock*> sv(Succ);
+ SaveAndRestore sv(Succ);
// NULL out Block so that the recursive call to Visit will
// create a new basic block.
@@ -3065,7 +3125,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
{
Stmt *Then = I->getThen();
assert(Then);
- SaveAndRestore<CFGBlock*> sv(Succ);
+ SaveAndRestore sv(Succ);
Block = nullptr;
// If branch is not a compound statement create implicit scope
@@ -3215,7 +3275,7 @@ CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
// Save local scope position because in case of exception variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
addStmt(ES->getBlock());
CFGBlock *SEHExceptBlock = Block;
@@ -3305,13 +3365,13 @@ CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) {
Succ = SEHTrySuccessor;
// Save the current "__try" context.
- SaveAndRestore<CFGBlock *> SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
+ SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
cfg->addTryDispatchBlock(TryTerminatedBlock);
// Save the current value for the __leave target.
// All __leaves should go to the code following the __try
// (FIXME: or if the __try has a __finally, to the __finally.)
- SaveAndRestore<JumpTarget> save_break(SEHLeaveJumpTarget);
+ SaveAndRestore save_break(SEHLeaveJumpTarget);
SEHLeaveJumpTarget = JumpTarget(SEHTrySuccessor, ScopePos);
assert(Terminator->getTryBlock() && "__try must contain a non-NULL body");
@@ -3370,11 +3430,12 @@ CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
if (Expr *Init = *it) {
// If the initializer is an ArrayInitLoopExpr, we want to extract the
// initializer, that's used for each element.
- const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
+ auto *AILEInit = extractElementInitializerFromNestedAILE(
+ dyn_cast<ArrayInitLoopExpr>(Init));
findConstructionContexts(ConstructionContextLayer::create(
cfg->getBumpVectorContext(), {E, Idx}),
- AILE ? AILE->getSubExpr() : Init);
+ AILEInit ? AILEInit : Init);
CFGBlock *Tmp = Visit(Init);
if (Tmp)
@@ -3433,7 +3494,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for init statement and possible condition variable.
// Add destructor for init statement and condition variable.
@@ -3461,7 +3522,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// Save the current value for the break targets.
// All breaks should go to the code following the loop.
- SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
+ SaveAndRestore save_break(BreakJumpTarget);
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
CFGBlock *BodyBlock = nullptr, *TransitionBlock = nullptr;
@@ -3471,8 +3532,8 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
assert(F->getBody());
// Save the current values for Block, Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget);
// Create an empty block to represent the transition block for looping back
// to the head of the loop. If we have increment code, it will
@@ -3527,7 +3588,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
do {
Expr *C = F->getCond();
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Specially handle logical operators, which have a slightly
// more optimal CFG representation.
@@ -3593,7 +3654,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
// If the loop contains initialization, create a new block for those
// statements. This block can also contain statements that precede the loop.
if (Stmt *I = F->getInit()) {
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
ScopePos = LoopBeginScopePos;
Block = createBlock();
return addStmt(I);
@@ -3696,9 +3757,9 @@ CFGBlock *CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
// Now create the true branch.
{
// Save the current values for Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
- save_break(BreakJumpTarget);
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget),
+ save_break(BreakJumpTarget);
// Add an intermediate block between the BodyBlock and the
// EntryConditionBlock to represent the "loop back" transition, for looping
@@ -3792,7 +3853,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for possible condition variable.
// Store scope position for continue statement.
@@ -3821,9 +3882,9 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
assert(W->getBody());
// Save the current values for Block, Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
- save_break(BreakJumpTarget);
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget),
+ save_break(BreakJumpTarget);
// Create an empty block to represent the transition block for looping back
// to the head of the loop.
@@ -3949,7 +4010,7 @@ CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) {
// Save local scope position because in case of exception variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
if (CS->getCatchBody())
addStmt(CS->getCatchBody());
@@ -4044,7 +4105,7 @@ CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) {
Succ = TrySuccessor;
// Save the current "try" context.
- SaveAndRestore<CFGBlock *> SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
+ SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
cfg->addTryDispatchBlock(TryTerminatedBlock);
assert(Terminator->getTryBody() && "try must contain a non-NULL body");
@@ -4147,8 +4208,8 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
assert(D->getBody());
// Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget),
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget),
save_break(BreakJumpTarget);
// All continues within this loop should go to the condition block
@@ -4266,7 +4327,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// Save local scope position because in case of condition variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for C++17 switch init-stmt if one exists.
if (Stmt *Init = Terminator->getInit())
@@ -4286,9 +4347,9 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
} else SwitchSuccessor = Succ;
// Save the current "switch" context.
- SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
- save_default(DefaultCaseBlock);
- SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
+ SaveAndRestore save_switch(SwitchTerminatedBlock),
+ save_default(DefaultCaseBlock);
+ SaveAndRestore save_break(BreakJumpTarget);
// Set the "default" case to be the block after the switch statement. If the
// switch statement contains a "default:", this value will be overwritten with
@@ -4311,15 +4372,13 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
// For pruning unreachable case statements, save the current state
// for tracking the condition value.
- SaveAndRestore<bool> save_switchExclusivelyCovered(switchExclusivelyCovered,
- false);
+ SaveAndRestore save_switchExclusivelyCovered(switchExclusivelyCovered, false);
// Determine if the switch condition can be explicitly evaluated.
assert(Terminator->getCond() && "switch condition must be non-NULL");
Expr::EvalResult result;
bool b = tryEvaluate(Terminator->getCond(), result);
- SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond,
- b ? &result : nullptr);
+ SaveAndRestore save_switchCond(switchCond, b ? &result : nullptr);
// If body is not a compound statement create implicit scope
// and add destructors.
@@ -4546,7 +4605,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
Succ = TrySuccessor;
// Save the current "try" context.
- SaveAndRestore<CFGBlock *> SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
+ SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock);
cfg->addTryDispatchBlock(TryTerminatedBlock);
assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
@@ -4560,7 +4619,7 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) {
// Save local scope position because in case of exception variable ScopePos
// won't be restored when traversing AST.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scope for possible exception variable.
// Store scope position. Add implicit destructor.
@@ -4612,7 +4671,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// }
// Save local scope position before the addition of the implicit variables.
- SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos);
+ SaveAndRestore save_scope_pos(ScopePos);
// Create local scopes and destructors for range, begin and end variables.
if (Stmt *Range = S->getRangeStmt())
@@ -4637,7 +4696,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
// Save the current value for the break targets.
// All breaks should go to the code following the loop.
- SaveAndRestore<JumpTarget> save_break(BreakJumpTarget);
+ SaveAndRestore save_break(BreakJumpTarget);
BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos);
// The block for the __begin != __end expression.
@@ -4670,8 +4729,8 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
assert(S->getBody());
// Save the current values for Block, Succ, and continue targets.
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ);
- SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget);
+ SaveAndRestore save_Block(Block), save_Succ(Succ);
+ SaveAndRestore save_continue(ContinueJumpTarget);
// Generate increment code in its own basic block. This is the target of
// continue statements.
@@ -5274,8 +5333,19 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
const CXXTemporary *temp = bindExpr->getTemporary();
return temp->getDestructor();
}
+ case CFGElement::MemberDtor: {
+ const FieldDecl *field = castAs<CFGMemberDtor>().getFieldDecl();
+ QualType ty = field->getType();
+
+ while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
+ ty = arrayType->getElementType();
+ }
+
+ const CXXRecordDecl *classDecl = ty->getAsCXXRecordDecl();
+ assert(classDecl);
+ return classDecl->getDestructor();
+ }
case CFGElement::BaseDtor:
- case CFGElement::MemberDtor:
// Not yet supported.
return nullptr;
}
@@ -5353,7 +5423,7 @@ public:
unsigned j = 1;
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
BI != BEnd; ++BI, ++j ) {
- if (Optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
const Stmt *stmt= SE->getStmt();
std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
StmtMap[stmt] = P;
@@ -5727,7 +5797,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
OS << " (BindTemporary)";
} else if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(S)) {
OS << " (CXXConstructExpr";
- if (Optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
+ if (std::optional<CFGConstructor> CE = E.getAs<CFGConstructor>()) {
print_construction_context(OS, Helper, CE->getConstructionContext());
}
OS << ", " << CCE->getType() << ")";
@@ -6102,7 +6172,7 @@ static bool isImmediateSinkBlock(const CFGBlock *Blk) {
// we'd need to carefully handle the case when the throw is being
// immediately caught.
if (llvm::any_of(*Blk, [](const CFGElement &Elm) {
- if (Optional<CFGStmt> StmtElm = Elm.getAs<CFGStmt>())
+ if (std::optional<CFGStmt> StmtElm = Elm.getAs<CFGStmt>())
if (isa<CXXThrowExpr>(StmtElm->getStmt()))
return true;
return false;
diff --git a/clang/lib/Analysis/CFGStmtMap.cpp b/clang/lib/Analysis/CFGStmtMap.cpp
index d1c23e3c879b..c3a4581e1fb1 100644
--- a/clang/lib/Analysis/CFGStmtMap.cpp
+++ b/clang/lib/Analysis/CFGStmtMap.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ParentMap.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
+#include <optional>
using namespace clang;
@@ -49,7 +50,7 @@ static void Accumulate(SMap &SM, CFGBlock *B) {
// First walk the block-level expressions.
for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) {
const CFGElement &CE = *I;
- Optional<CFGStmt> CS = CE.getAs<CFGStmt>();
+ std::optional<CFGStmt> CS = CE.getAs<CFGStmt>();
if (!CS)
continue;
diff --git a/clang/lib/Analysis/CalledOnceCheck.cpp b/clang/lib/Analysis/CalledOnceCheck.cpp
index c1d1d7b89ec7..5b4fc24b6f0e 100644
--- a/clang/lib/Analysis/CalledOnceCheck.cpp
+++ b/clang/lib/Analysis/CalledOnceCheck.cpp
@@ -28,7 +28,6 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/BitmaskEnum.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
@@ -38,6 +37,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <memory>
+#include <optional>
using namespace clang;
@@ -319,7 +319,7 @@ public:
// We care about logical not only if we care about comparisons.
if (!ShouldRetrieveFromComparisons)
return nullptr;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// Function pointer/references can be dereferenced before a call.
// That doesn't make it, however, any different from a regular call.
// For this reason, dereference operation is a "no-op".
@@ -494,7 +494,7 @@ struct Clarification {
/// of basic blocks.
class NotCalledClarifier
: public ConstStmtVisitor<NotCalledClarifier,
- llvm::Optional<Clarification>> {
+ std::optional<Clarification>> {
public:
/// The main entrypoint for the class, the function that tries to find the
/// clarification of how to explain which sub-path starts with a CFG edge
@@ -508,24 +508,24 @@ public:
/// results only for such cases. For this very reason, the parent basic
/// block, Conditional, is named that way, so it is clear what kind of
/// block is expected.
- static llvm::Optional<Clarification>
- clarify(const CFGBlock *Conditional, const CFGBlock *SuccWithoutCall) {
+ static std::optional<Clarification> clarify(const CFGBlock *Conditional,
+ const CFGBlock *SuccWithoutCall) {
if (const Stmt *Terminator = Conditional->getTerminatorStmt()) {
return NotCalledClarifier{Conditional, SuccWithoutCall}.Visit(Terminator);
}
- return llvm::None;
+ return std::nullopt;
}
- llvm::Optional<Clarification> VisitIfStmt(const IfStmt *If) {
+ std::optional<Clarification> VisitIfStmt(const IfStmt *If) {
return VisitBranchingBlock(If, NeverCalledReason::IfThen);
}
- llvm::Optional<Clarification>
+ std::optional<Clarification>
VisitAbstractConditionalOperator(const AbstractConditionalOperator *Ternary) {
return VisitBranchingBlock(Ternary, NeverCalledReason::IfThen);
}
- llvm::Optional<Clarification> VisitSwitchStmt(const SwitchStmt *Switch) {
+ std::optional<Clarification> VisitSwitchStmt(const SwitchStmt *Switch) {
const Stmt *CaseToBlame = SuccInQuestion->getLabel();
if (!CaseToBlame) {
// If interesting basic block is not labeled, it means that this
@@ -543,15 +543,15 @@ public:
llvm_unreachable("Found unexpected switch structure");
}
- llvm::Optional<Clarification> VisitForStmt(const ForStmt *For) {
+ std::optional<Clarification> VisitForStmt(const ForStmt *For) {
return VisitBranchingBlock(For, NeverCalledReason::LoopEntered);
}
- llvm::Optional<Clarification> VisitWhileStmt(const WhileStmt *While) {
+ std::optional<Clarification> VisitWhileStmt(const WhileStmt *While) {
return VisitBranchingBlock(While, NeverCalledReason::LoopEntered);
}
- llvm::Optional<Clarification>
+ std::optional<Clarification>
VisitBranchingBlock(const Stmt *Terminator, NeverCalledReason DefaultReason) {
assert(Parent->succ_size() == 2 &&
"Branching block should have exactly two successors");
@@ -561,12 +561,12 @@ public:
return Clarification{ActualReason, Terminator};
}
- llvm::Optional<Clarification> VisitBinaryOperator(const BinaryOperator *) {
+ std::optional<Clarification> VisitBinaryOperator(const BinaryOperator *) {
// We don't want to report on short-curcuit logical operations.
- return llvm::None;
+ return std::nullopt;
}
- llvm::Optional<Clarification> VisitStmt(const Stmt *Terminator) {
+ std::optional<Clarification> VisitStmt(const Stmt *Terminator) {
// If we got here, we didn't have a visit function for more derived
// classes of statement that this terminator actually belongs to.
//
@@ -753,7 +753,7 @@ private:
// We use a backward dataflow propagation and for this reason we
// should traverse basic blocks bottom-up.
for (const CFGElement &Element : llvm::reverse(*BB)) {
- if (Optional<CFGStmt> S = Element.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> S = Element.getAs<CFGStmt>()) {
check(S->getStmt());
}
}
@@ -880,8 +880,8 @@ private:
template <class CallLikeExpr>
void checkIndirectCall(const CallLikeExpr *CallOrMessage) {
// CallExpr::arguments does not interact nicely with llvm::enumerate.
- llvm::ArrayRef<const Expr *> Arguments = llvm::makeArrayRef(
- CallOrMessage->getArgs(), CallOrMessage->getNumArgs());
+ llvm::ArrayRef<const Expr *> Arguments =
+ llvm::ArrayRef(CallOrMessage->getArgs(), CallOrMessage->getNumArgs());
// Let's check if any of the call arguments is a point of interest.
for (const auto &Argument : llvm::enumerate(Arguments)) {
@@ -997,10 +997,10 @@ private:
/// Return true/false if 'swift_async' attribute states that the given
/// parameter is conventionally called once.
- /// Return llvm::None if the given declaration doesn't have 'swift_async'
+ /// Return std::nullopt if the given declaration doesn't have 'swift_async'
/// attribute.
- static llvm::Optional<bool> isConventionalSwiftAsync(const Decl *D,
- unsigned ParamIndex) {
+ static std::optional<bool> isConventionalSwiftAsync(const Decl *D,
+ unsigned ParamIndex) {
if (const SwiftAsyncAttr *A = D->getAttr<SwiftAsyncAttr>()) {
if (A->getKind() == SwiftAsyncAttr::None) {
return false;
@@ -1008,7 +1008,7 @@ private:
return A->getCompletionHandlerIndex().getASTIndex() == ParamIndex;
}
- return llvm::None;
+ return std::nullopt;
}
/// Return true if the specified selector represents init method.
@@ -1157,8 +1157,8 @@ private:
bool shouldBlockArgumentBeCalledOnce(const CallLikeExpr *CallOrMessage,
const Stmt *BlockArgument) const {
// CallExpr::arguments does not interact nicely with llvm::enumerate.
- llvm::ArrayRef<const Expr *> Arguments = llvm::makeArrayRef(
- CallOrMessage->getArgs(), CallOrMessage->getNumArgs());
+ llvm::ArrayRef<const Expr *> Arguments =
+ llvm::ArrayRef(CallOrMessage->getArgs(), CallOrMessage->getNumArgs());
for (const auto &Argument : llvm::enumerate(Arguments)) {
if (Argument.value() == BlockArgument) {
@@ -1265,7 +1265,7 @@ private:
llvm::reverse(*BB), // we should start with return statements, if we
// have any, i.e. from the bottom of the block
[&ReturnChildren](const CFGElement &Element) {
- if (Optional<CFGStmt> S = Element.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> S = Element.getAs<CFGStmt>()) {
const Stmt *SuspiciousStmt = S->getStmt();
if (isa<ReturnStmt>(SuspiciousStmt)) {
@@ -1635,19 +1635,19 @@ public:
private:
unsigned size() const { return TrackedParams.size(); }
- llvm::Optional<unsigned> getIndexOfCallee(const CallExpr *Call) const {
+ std::optional<unsigned> getIndexOfCallee(const CallExpr *Call) const {
return getIndexOfExpression(Call->getCallee());
}
- llvm::Optional<unsigned> getIndexOfExpression(const Expr *E) const {
+ std::optional<unsigned> getIndexOfExpression(const Expr *E) const {
if (const ParmVarDecl *Parameter = findReferencedParmVarDecl(E)) {
return getIndex(*Parameter);
}
- return llvm::None;
+ return std::nullopt;
}
- llvm::Optional<unsigned> getIndex(const ParmVarDecl &Parameter) const {
+ std::optional<unsigned> getIndex(const ParmVarDecl &Parameter) const {
// Expected number of parameters that we actually track is 1.
//
// Also, the maximum number of declared parameters could not be on a scale
@@ -1662,7 +1662,7 @@ private:
return It - TrackedParams.begin();
}
- return llvm::None;
+ return std::nullopt;
}
const ParmVarDecl *getParameter(unsigned Index) const {
diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp
index 9560248b173f..8ab6d7a7f3b0 100644
--- a/clang/lib/Analysis/Consumed.cpp
+++ b/clang/lib/Analysis/Consumed.cpp
@@ -27,13 +27,13 @@
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <memory>
+#include <optional>
#include <utility>
// TODO: Adjust states of args to constructors in the same way that arguments to
@@ -62,7 +62,7 @@ static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
// Find the source location of the first statement in the block, if the block
// is not empty.
for (const auto &B : *Block)
- if (Optional<CFGStmt> CS = B.getAs<CFGStmt>())
+ if (std::optional<CFGStmt> CS = B.getAs<CFGStmt>())
return CS->getStmt()->getBeginLoc();
// Block is empty.
@@ -81,7 +81,7 @@ static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
} else {
for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
BE = Block->rend(); BI != BE; ++BI) {
- if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
+ if (std::optional<CFGStmt> CS = BI->getAs<CFGStmt>())
return CS->getStmt()->getBeginLoc();
}
}
diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
index 58708b5b5efb..2492b5203724 100644
--- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
@@ -36,7 +36,7 @@ buildStmtToBasicBlockMap(const CFG &Cfg) {
if (!Stmt)
continue;
- StmtToBlock[Stmt.value().getStmt()] = Block;
+ StmtToBlock[Stmt->getStmt()] = Block;
}
if (const Stmt *TerminatorStmt = Block->getTerminatorStmt())
StmtToBlock[TerminatorStmt] = Block;
@@ -45,7 +45,7 @@ buildStmtToBasicBlockMap(const CFG &Cfg) {
}
llvm::Expected<ControlFlowContext>
-ControlFlowContext::build(const Decl *D, Stmt *S, ASTContext *C) {
+ControlFlowContext::build(const Decl *D, Stmt &S, ASTContext &C) {
CFG::BuildOptions Options;
Options.PruneTriviallyFalseEdges = false;
Options.AddImplicitDtors = true;
@@ -56,7 +56,7 @@ ControlFlowContext::build(const Decl *D, Stmt *S, ASTContext *C) {
// Ensure that all sub-expressions in basic blocks are evaluated.
Options.setAllAlwaysAdd();
- auto Cfg = CFG::buildCFG(D, S, C, Options);
+ auto Cfg = CFG::buildCFG(D, &S, &C, Options);
if (Cfg == nullptr)
return llvm::createStringError(
std::make_error_code(std::errc::invalid_argument),
@@ -64,7 +64,7 @@ ControlFlowContext::build(const Decl *D, Stmt *S, ASTContext *C) {
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock =
buildStmtToBasicBlockMap(*Cfg);
- return ControlFlowContext(std::move(Cfg), std::move(StmtToBlock));
+ return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock));
}
} // namespace dataflow
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
index 216f41bdee1c..480606bdac8d 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Analysis/FlowSensitive/DebugSupport.h"
#include "clang/Analysis/FlowSensitive/Value.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/Support/Debug.h"
#include <cassert>
#include <memory>
@@ -24,15 +25,33 @@
namespace clang {
namespace dataflow {
-StorageLocation &
-DataflowAnalysisContext::getStableStorageLocation(QualType Type) {
+void DataflowAnalysisContext::addModeledFields(
+ const llvm::DenseSet<const FieldDecl *> &Fields) {
+ llvm::set_union(ModeledFields, Fields);
+}
+
+llvm::DenseSet<const FieldDecl *>
+DataflowAnalysisContext::getReferencedFields(QualType Type) {
+ llvm::DenseSet<const FieldDecl *> Fields = getObjectFields(Type);
+ llvm::set_intersect(Fields, ModeledFields);
+ return Fields;
+}
+
+StorageLocation &DataflowAnalysisContext::createStorageLocation(QualType Type) {
if (!Type.isNull() &&
(Type->isStructureOrClassType() || Type->isUnionType())) {
- // FIXME: Explore options to avoid eager initialization of fields as some of
- // them might not be needed for a particular analysis.
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
- for (const FieldDecl *Field : getObjectFields(Type))
- FieldLocs.insert({Field, &getStableStorageLocation(Field->getType())});
+ // During context-sensitive analysis, a struct may be allocated in one
+ // function, but its field accessed in a function lower in the stack than
+ // the allocation. Since we only collect fields used in the function where
+ // the allocation occurs, we can't apply that filter when performing
+ // context-sensitive analysis. But, this only applies to storage locations,
+ // since field access it not allowed to fail. In contrast, field *values*
+ // don't need this allowance, since the API allows for uninitialized fields.
+ auto Fields = Opts.ContextSensitiveOpts ? getObjectFields(Type)
+ : getReferencedFields(Type);
+ for (const FieldDecl *Field : Fields)
+ FieldLocs.insert({Field, &createStorageLocation(Field->getType())});
return takeOwnership(
std::make_unique<AggregateStorageLocation>(Type, std::move(FieldLocs)));
}
@@ -43,7 +62,7 @@ StorageLocation &
DataflowAnalysisContext::getStableStorageLocation(const VarDecl &D) {
if (auto *Loc = getStorageLocation(D))
return *Loc;
- auto &Loc = getStableStorageLocation(D.getType());
+ auto &Loc = createStorageLocation(D.getType());
setStorageLocation(D, Loc);
return Loc;
}
@@ -52,7 +71,7 @@ StorageLocation &
DataflowAnalysisContext::getStableStorageLocation(const Expr &E) {
if (auto *Loc = getStorageLocation(E))
return *Loc;
- auto &Loc = getStableStorageLocation(E.getType());
+ auto &Loc = createStorageLocation(E.getType());
setStorageLocation(E, Loc);
return Loc;
}
@@ -63,7 +82,7 @@ DataflowAnalysisContext::getOrCreateNullPointerValue(QualType PointeeType) {
PointeeType.isNull() ? PointeeType : PointeeType.getCanonicalType();
auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr);
if (Res.second) {
- auto &PointeeLoc = getStableStorageLocation(CanonicalPointeeType);
+ auto &PointeeLoc = createStorageLocation(CanonicalPointeeType);
Res.first->second =
&takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
}
@@ -335,6 +354,27 @@ void DataflowAnalysisContext::dumpFlowCondition(AtomicBoolValue &Token) {
llvm::dbgs() << debugString(Constraints, AtomNames);
}
+const ControlFlowContext *
+DataflowAnalysisContext::getControlFlowContext(const FunctionDecl *F) {
+ // Canonicalize the key:
+ F = F->getDefinition();
+ if (F == nullptr)
+ return nullptr;
+ auto It = FunctionContexts.find(F);
+ if (It != FunctionContexts.end())
+ return &It->second;
+
+ if (Stmt *Body = F->getBody()) {
+ auto CFCtx = ControlFlowContext::build(F, *Body, F->getASTContext());
+ // FIXME: Handle errors.
+ assert(CFCtx);
+ auto Result = FunctionContexts.insert({F, std::move(*CFCtx)});
+ return &Result.first->second;
+ }
+
+ return nullptr;
+}
+
} // namespace dataflow
} // namespace clang
diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
index f6f71e34b892..cc3992805cc7 100644
--- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
@@ -20,6 +20,7 @@
#include "clang/Analysis/FlowSensitive/Value.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
@@ -48,43 +49,66 @@ llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
return Result;
}
-static bool areEquivalentIndirectionValues(Value *Val1, Value *Val2) {
- if (auto *IndVal1 = dyn_cast<ReferenceValue>(Val1)) {
- auto *IndVal2 = cast<ReferenceValue>(Val2);
- return &IndVal1->getReferentLoc() == &IndVal2->getReferentLoc();
- }
- if (auto *IndVal1 = dyn_cast<PointerValue>(Val1)) {
- auto *IndVal2 = cast<PointerValue>(Val2);
- return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc();
+static bool compareDistinctValues(QualType Type, Value &Val1,
+ const Environment &Env1, Value &Val2,
+ const Environment &Env2,
+ Environment::ValueModel &Model) {
+ // Note: Potentially costly, but, for booleans, we could check whether both
+ // can be proven equivalent in their respective environments.
+
+ // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
+ // and implement separate, join/widen specific handling for
+ // reference/pointers.
+ switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
+ case ComparisonResult::Same:
+ return true;
+ case ComparisonResult::Different:
+ return false;
+ case ComparisonResult::Unknown:
+ switch (Val1.getKind()) {
+ case Value::Kind::Integer:
+ case Value::Kind::Reference:
+ case Value::Kind::Pointer:
+ case Value::Kind::Struct:
+ // FIXME: this choice intentionally introduces unsoundness to allow
+ // for convergence. Once we have widening support for the
+ // reference/pointer and struct built-in models, this should be
+ // `false`.
+ return true;
+ default:
+ return false;
+ }
}
- return false;
-}
-
-/// Returns true if and only if `Val1` is equivalent to `Val2`.
-static bool equivalentValues(QualType Type, Value *Val1,
- const Environment &Env1, Value *Val2,
- const Environment &Env2,
- Environment::ValueModel &Model) {
- return Val1 == Val2 || areEquivalentIndirectionValues(Val1, Val2) ||
- Model.compareEquivalent(Type, *Val1, Env1, *Val2, Env2);
+ llvm_unreachable("All cases covered in switch");
}
/// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
/// respectively, of the same type `Type`. Merging generally produces a single
/// value that (soundly) approximates the two inputs, although the actual
/// meaning depends on `Model`.
-static Value *mergeDistinctValues(QualType Type, Value *Val1,
- const Environment &Env1, Value *Val2,
+static Value *mergeDistinctValues(QualType Type, Value &Val1,
+ const Environment &Env1, Value &Val2,
const Environment &Env2,
Environment &MergedEnv,
Environment::ValueModel &Model) {
// Join distinct boolean values preserving information about the constraints
// in the respective path conditions.
- //
- // FIXME: Does not work for backedges, since the two (or more) paths will not
- // have mutually exclusive conditions.
- if (auto *Expr1 = dyn_cast<BoolValue>(Val1)) {
- auto *Expr2 = cast<BoolValue>(Val2);
+ if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
+ // FIXME: Checking both values should be unnecessary, since they should have
+ // a consistent shape. However, right now we can end up with BoolValue's in
+ // integer-typed variables due to our incorrect handling of
+ // boolean-to-integer casts (we just propagate the BoolValue to the result
+ // of the cast). So, a join can encounter an integer in one branch but a
+ // bool in the other.
+ // For example:
+ // ```
+ // std::optional<bool> o;
+ // int x;
+ // if (o.has_value())
+ // x = o.value();
+ // ```
+ auto *Expr1 = cast<BoolValue>(&Val1);
+ auto *Expr2 = cast<BoolValue>(&Val2);
auto &MergedVal = MergedEnv.makeAtomicBoolValue();
MergedEnv.addToFlowCondition(MergedEnv.makeOr(
MergedEnv.makeAnd(Env1.getFlowConditionToken(),
@@ -94,59 +118,99 @@ static Value *mergeDistinctValues(QualType Type, Value *Val1,
return &MergedVal;
}
- // FIXME: add unit tests that cover this statement.
- if (areEquivalentIndirectionValues(Val1, Val2)) {
- return Val1;
- }
-
// FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
// returns false to avoid storing unneeded values in `DACtx`.
+ // FIXME: Creating the value based on the type alone creates misshapen values
+ // for lvalues, since the type does not reflect the need for `ReferenceValue`.
if (Value *MergedVal = MergedEnv.createValue(Type))
- if (Model.merge(Type, *Val1, Env1, *Val2, Env2, *MergedVal, MergedEnv))
+ if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
return MergedVal;
return nullptr;
}
-/// Initializes a global storage value.
-static void initGlobalVar(const VarDecl &D, Environment &Env) {
- if (!D.hasGlobalStorage() ||
- Env.getStorageLocation(D, SkipPast::None) != nullptr)
- return;
+// When widening does not change `Current`, return value will equal `&Prev`.
+static Value &widenDistinctValues(QualType Type, Value &Prev,
+ const Environment &PrevEnv, Value &Current,
+ Environment &CurrentEnv,
+ Environment::ValueModel &Model) {
+ // Boolean-model widening.
+ if (isa<BoolValue>(&Prev)) {
+ assert(isa<BoolValue>(Current));
+ // Widen to Top, because we know they are different values. If previous was
+ // already Top, re-use that to (implicitly) indicate that no change occured.
+ if (isa<TopBoolValue>(Prev))
+ return Prev;
+ return CurrentEnv.makeTopBoolValue();
+ }
+
+ // FIXME: Add other built-in model widening.
- auto &Loc = Env.createStorageLocation(D);
- Env.setStorageLocation(D, Loc);
- if (auto *Val = Env.createValue(D.getType()))
- Env.setValue(Loc, *Val);
+ // Custom-model widening.
+ if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
+ return *W;
+
+ // Default of widening is a no-op: leave the current value unchanged.
+ return Current;
}
/// Initializes a global storage value.
-static void initGlobalVar(const Decl &D, Environment &Env) {
+static void insertIfGlobal(const Decl &D,
+ llvm::DenseSet<const FieldDecl *> &Fields,
+ llvm::DenseSet<const VarDecl *> &Vars) {
if (auto *V = dyn_cast<VarDecl>(&D))
- initGlobalVar(*V, Env);
-}
-
-/// Initializes global storage values that are declared or referenced from
-/// sub-statements of `S`.
-// FIXME: Add support for resetting globals after function calls to enable
-// the implementation of sound analyses.
-static void initGlobalVars(const Stmt &S, Environment &Env) {
- for (auto *Child : S.children()) {
+ if (V->hasGlobalStorage())
+ Vars.insert(V);
+}
+
+static void getFieldsAndGlobalVars(const Decl &D,
+ llvm::DenseSet<const FieldDecl *> &Fields,
+ llvm::DenseSet<const VarDecl *> &Vars) {
+ insertIfGlobal(D, Fields, Vars);
+ if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
+ for (const auto *B : Decomp->bindings())
+ if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
+ // FIXME: should we be using `E->getFoundDecl()`?
+ if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ Fields.insert(FD);
+}
+
+/// Traverses `S` and inserts into `Vars` any global storage values that are
+/// declared in or referenced from sub-statements.
+static void getFieldsAndGlobalVars(const Stmt &S,
+ llvm::DenseSet<const FieldDecl *> &Fields,
+ llvm::DenseSet<const VarDecl *> &Vars) {
+ for (auto *Child : S.children())
if (Child != nullptr)
- initGlobalVars(*Child, Env);
- }
+ getFieldsAndGlobalVars(*Child, Fields, Vars);
if (auto *DS = dyn_cast<DeclStmt>(&S)) {
- if (DS->isSingleDecl()) {
- initGlobalVar(*DS->getSingleDecl(), Env);
- } else {
+ if (DS->isSingleDecl())
+ getFieldsAndGlobalVars(*DS->getSingleDecl(), Fields, Vars);
+ else
for (auto *D : DS->getDeclGroup())
- initGlobalVar(*D, Env);
- }
+ getFieldsAndGlobalVars(*D, Fields, Vars);
} else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
- initGlobalVar(*E->getDecl(), Env);
+ insertIfGlobal(*E->getDecl(), Fields, Vars);
} else if (auto *E = dyn_cast<MemberExpr>(&S)) {
- initGlobalVar(*E->getMemberDecl(), Env);
+ // FIXME: should we be using `E->getFoundDecl()`?
+ const ValueDecl *VD = E->getMemberDecl();
+ insertIfGlobal(*VD, Fields, Vars);
+ if (const auto *FD = dyn_cast<FieldDecl>(VD))
+ Fields.insert(FD);
+ }
+}
+
+// FIXME: Add support for resetting globals after function calls to enable
+// the implementation of sound analyses.
+void Environment::initVars(llvm::DenseSet<const VarDecl *> Vars) {
+ for (const VarDecl *D : Vars) {
+ if (getStorageLocation(*D, SkipPast::None) != nullptr)
+ continue;
+ auto &Loc = createStorageLocation(*D);
+ setStorageLocation(*D, Loc);
+ if (auto *Val = createValue(D->getType()))
+ setValue(Loc, *Val);
}
}
@@ -154,9 +218,10 @@ Environment::Environment(DataflowAnalysisContext &DACtx)
: DACtx(&DACtx), FlowConditionToken(&DACtx.makeFlowConditionToken()) {}
Environment::Environment(const Environment &Other)
- : DACtx(Other.DACtx), DeclToLoc(Other.DeclToLoc),
- ExprToLoc(Other.ExprToLoc), LocToVal(Other.LocToVal),
- MemberLocToStruct(Other.MemberLocToStruct),
+ : DACtx(Other.DACtx), CallStack(Other.CallStack),
+ ReturnLoc(Other.ReturnLoc), ThisPointeeLoc(Other.ThisPointeeLoc),
+ DeclToLoc(Other.DeclToLoc), ExprToLoc(Other.ExprToLoc),
+ LocToVal(Other.LocToVal), MemberLocToStruct(Other.MemberLocToStruct),
FlowConditionToken(&DACtx->forkFlowCondition(*Other.FlowConditionToken)) {
}
@@ -169,9 +234,32 @@ Environment &Environment::operator=(const Environment &Other) {
Environment::Environment(DataflowAnalysisContext &DACtx,
const DeclContext &DeclCtx)
: Environment(DACtx) {
+ CallStack.push_back(&DeclCtx);
+
if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
assert(FuncDecl->getBody() != nullptr);
- initGlobalVars(*FuncDecl->getBody(), *this);
+
+ llvm::DenseSet<const FieldDecl *> Fields;
+ llvm::DenseSet<const VarDecl *> Vars;
+
+ // Look for global variable references in the constructor-initializers.
+ if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&DeclCtx)) {
+ for (const auto *Init : CtorDecl->inits()) {
+ if (const auto *M = Init->getAnyMember())
+ Fields.insert(M);
+ const Expr *E = Init->getInit();
+ assert(E != nullptr);
+ getFieldsAndGlobalVars(*E, Fields, Vars);
+ }
+ }
+ getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
+
+ // These have to be added before the lines that follow to ensure that
+ // `create*` work correctly for structs.
+ DACtx.addModeledFields(Fields);
+
+ initVars(Vars);
+
for (const auto *ParamDecl : FuncDecl->parameters()) {
assert(ParamDecl != nullptr);
auto &ParamLoc = createStorageLocation(*ParamDecl);
@@ -179,6 +267,9 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
if (Value *ParamVal = createValue(ParamDecl->getType()))
setValue(ParamLoc, *ParamVal);
}
+
+ QualType ReturnType = FuncDecl->getReturnType();
+ ReturnLoc = &createStorageLocation(ReturnType);
}
if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
@@ -187,59 +278,132 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
if (Parent->isLambda())
MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());
+ // FIXME: Initialize the ThisPointeeLoc of lambdas too.
if (MethodDecl && !MethodDecl->isStatic()) {
QualType ThisPointeeType = MethodDecl->getThisObjectType();
- // FIXME: Add support for union types.
- if (!ThisPointeeType->isUnionType()) {
- auto &ThisPointeeLoc = createStorageLocation(ThisPointeeType);
- DACtx.setThisPointeeStorageLocation(ThisPointeeLoc);
- if (Value *ThisPointeeVal = createValue(ThisPointeeType))
- setValue(ThisPointeeLoc, *ThisPointeeVal);
- }
+ ThisPointeeLoc = &createStorageLocation(ThisPointeeType);
+ if (Value *ThisPointeeVal = createValue(ThisPointeeType))
+ setValue(*ThisPointeeLoc, *ThisPointeeVal);
}
}
}
+bool Environment::canDescend(unsigned MaxDepth,
+ const DeclContext *Callee) const {
+ return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee);
+}
+
Environment Environment::pushCall(const CallExpr *Call) const {
Environment Env(*this);
- // FIXME: Currently this only works if the callee is never a method and the
- // same callee is never analyzed from multiple separate callsites. To
- // generalize this, we'll need to store a "context" field (probably a stack of
- // `const CallExpr *`s) in the `Environment`, and then change the
- // `DataflowAnalysisContext` class to hold a map from contexts to "frames",
- // where each frame stores its own version of what are currently the
- // `DeclToLoc`, `ExprToLoc`, and `ThisPointeeLoc` fields.
+ // FIXME: Support references here.
+ Env.ReturnLoc = getStorageLocation(*Call, SkipPast::Reference);
- const auto *FuncDecl = Call->getDirectCallee();
- assert(FuncDecl != nullptr);
- assert(FuncDecl->getBody() != nullptr);
- // FIXME: In order to allow the callee to reference globals, we probably need
- // to call `initGlobalVars` here in some way.
+ if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
+ if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
+ if (!isa<CXXThisExpr>(Arg))
+ Env.ThisPointeeLoc = getStorageLocation(*Arg, SkipPast::Reference);
+ // Otherwise (when the argument is `this`), retain the current
+ // environment's `ThisPointeeLoc`.
+ }
+ }
+
+ Env.pushCallInternal(Call->getDirectCallee(),
+ llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
+
+ return Env;
+}
- auto ParamIt = FuncDecl->param_begin();
- auto ArgIt = Call->arg_begin();
- auto ArgEnd = Call->arg_end();
+Environment Environment::pushCall(const CXXConstructExpr *Call) const {
+ Environment Env(*this);
+
+ // FIXME: Support references here.
+ Env.ReturnLoc = getStorageLocation(*Call, SkipPast::Reference);
+
+ Env.ThisPointeeLoc = Env.ReturnLoc;
+
+ Env.pushCallInternal(Call->getConstructor(),
+ llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
+
+ return Env;
+}
+
+void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
+ ArrayRef<const Expr *> Args) {
+ CallStack.push_back(FuncDecl);
+
+ // FIXME: Share this code with the constructor, rather than duplicating it.
+ llvm::DenseSet<const FieldDecl *> Fields;
+ llvm::DenseSet<const VarDecl *> Vars;
+ // Look for global variable references in the constructor-initializers.
+ if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
+ for (const auto *Init : CtorDecl->inits()) {
+ if (const auto *M = Init->getAnyMember())
+ Fields.insert(M);
+ const Expr *E = Init->getInit();
+ assert(E != nullptr);
+ getFieldsAndGlobalVars(*E, Fields, Vars);
+ }
+ }
+ getFieldsAndGlobalVars(*FuncDecl->getBody(), Fields, Vars);
+
+ // These have to be added before the lines that follow to ensure that
+ // `create*` work correctly for structs.
+ DACtx->addModeledFields(Fields);
+
+ initVars(Vars);
+
+ const auto *ParamIt = FuncDecl->param_begin();
// FIXME: Parameters don't always map to arguments 1:1; examples include
// overloaded operators implemented as member functions, and parameter packs.
- for (; ArgIt != ArgEnd; ++ParamIt, ++ArgIt) {
+ for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
assert(ParamIt != FuncDecl->param_end());
+ const Expr *Arg = Args[ArgIndex];
+ auto *ArgLoc = getStorageLocation(*Arg, SkipPast::Reference);
+ if (ArgLoc == nullptr)
+ continue;
+
const VarDecl *Param = *ParamIt;
- const Expr *Arg = *ArgIt;
- auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
- assert(ArgLoc != nullptr);
- Env.setStorageLocation(*Param, *ArgLoc);
+ auto &Loc = createStorageLocation(*Param);
+ setStorageLocation(*Param, Loc);
+
+ QualType ParamType = Param->getType();
+ if (ParamType->isReferenceType()) {
+ auto &Val = takeOwnership(std::make_unique<ReferenceValue>(*ArgLoc));
+ setValue(Loc, Val);
+ } else if (auto *ArgVal = getValue(*ArgLoc)) {
+ setValue(Loc, *ArgVal);
+ } else if (Value *Val = createValue(ParamType)) {
+ setValue(Loc, *Val);
+ }
}
+}
- return Env;
+void Environment::popCall(const Environment &CalleeEnv) {
+ // We ignore `DACtx` because it's already the same in both. We don't want the
+ // callee's `DeclCtx`, `ReturnLoc` or `ThisPointeeLoc`. We don't bring back
+ // `DeclToLoc` and `ExprToLoc` because we want to be able to later analyze the
+ // same callee in a different context, and `setStorageLocation` requires there
+ // to not already be a storage location assigned. Conceptually, these maps
+ // capture information from the local scope, so when popping that scope, we do
+ // not propagate the maps.
+ this->LocToVal = std::move(CalleeEnv.LocToVal);
+ this->MemberLocToStruct = std::move(CalleeEnv.MemberLocToStruct);
+ this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
}
bool Environment::equivalentTo(const Environment &Other,
Environment::ValueModel &Model) const {
assert(DACtx == Other.DACtx);
+ if (ReturnLoc != Other.ReturnLoc)
+ return false;
+
+ if (ThisPointeeLoc != Other.ThisPointeeLoc)
+ return false;
+
if (DeclToLoc != Other.DeclToLoc)
return false;
@@ -259,21 +423,91 @@ bool Environment::equivalentTo(const Environment &Other,
continue;
assert(It->second != nullptr);
- if (!equivalentValues(Loc->getType(), Val, *this, It->second, Other, Model))
+ if (!areEquivalentValues(*Val, *It->second) &&
+ !compareDistinctValues(Loc->getType(), *Val, *this, *It->second, Other,
+ Model))
return false;
}
return true;
}
+LatticeJoinEffect Environment::widen(const Environment &PrevEnv,
+ Environment::ValueModel &Model) {
+ assert(DACtx == PrevEnv.DACtx);
+ assert(ReturnLoc == PrevEnv.ReturnLoc);
+ assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
+ assert(CallStack == PrevEnv.CallStack);
+
+ auto Effect = LatticeJoinEffect::Unchanged;
+
+ // By the API, `PrevEnv` is a previous version of the environment for the same
+ // block, so we have some guarantees about its shape. In particular, it will
+ // be the result of a join or widen operation on previous values for this
+ // block. For `DeclToLoc` and `ExprToLoc`, join guarantees that these maps are
+ // subsets of the maps in `PrevEnv`. So, as long as we maintain this property
+ // here, we don't need change their current values to widen.
+ //
+ // FIXME: `MemberLocToStruct` does not share the above property, because
+ // `join` can cause the map size to increase (when we add fresh data in places
+ // of conflict). Once this issue with join is resolved, re-enable the
+ // assertion below or replace with something that captures the desired
+ // invariant.
+ assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
+ assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
+ // assert(MemberLocToStruct.size() <= PrevEnv.MemberLocToStruct.size());
+
+ llvm::DenseMap<const StorageLocation *, Value *> WidenedLocToVal;
+ for (auto &Entry : LocToVal) {
+ const StorageLocation *Loc = Entry.first;
+ assert(Loc != nullptr);
+
+ Value *Val = Entry.second;
+ assert(Val != nullptr);
+
+ auto PrevIt = PrevEnv.LocToVal.find(Loc);
+ if (PrevIt == PrevEnv.LocToVal.end())
+ continue;
+ assert(PrevIt->second != nullptr);
+
+ if (areEquivalentValues(*Val, *PrevIt->second)) {
+ WidenedLocToVal.insert({Loc, Val});
+ continue;
+ }
+
+ Value &WidenedVal = widenDistinctValues(Loc->getType(), *PrevIt->second,
+ PrevEnv, *Val, *this, Model);
+ WidenedLocToVal.insert({Loc, &WidenedVal});
+ if (&WidenedVal != PrevIt->second)
+ Effect = LatticeJoinEffect::Changed;
+ }
+ LocToVal = std::move(WidenedLocToVal);
+ // FIXME: update the equivalence calculation for `MemberLocToStruct`, once we
+ // have a systematic way of soundly comparing this map.
+ if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
+ ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
+ LocToVal.size() != PrevEnv.LocToVal.size() ||
+ MemberLocToStruct.size() != PrevEnv.MemberLocToStruct.size())
+ Effect = LatticeJoinEffect::Changed;
+
+ return Effect;
+}
+
LatticeJoinEffect Environment::join(const Environment &Other,
Environment::ValueModel &Model) {
assert(DACtx == Other.DACtx);
+ assert(ReturnLoc == Other.ReturnLoc);
+ assert(ThisPointeeLoc == Other.ThisPointeeLoc);
+ assert(CallStack == Other.CallStack);
auto Effect = LatticeJoinEffect::Unchanged;
Environment JoinedEnv(*DACtx);
+ JoinedEnv.CallStack = CallStack;
+ JoinedEnv.ReturnLoc = ReturnLoc;
+ JoinedEnv.ThisPointeeLoc = ThisPointeeLoc;
+
JoinedEnv.DeclToLoc = intersectDenseMaps(DeclToLoc, Other.DeclToLoc);
if (DeclToLoc.size() != JoinedEnv.DeclToLoc.size())
Effect = LatticeJoinEffect::Changed;
@@ -288,6 +522,8 @@ LatticeJoinEffect Environment::join(const Environment &Other,
Effect = LatticeJoinEffect::Changed;
// FIXME: set `Effect` as needed.
+ // FIXME: update join to detect backedges and simplify the flow condition
+ // accordingly.
JoinedEnv.FlowConditionToken = &DACtx->joinFlowConditions(
*FlowConditionToken, *Other.FlowConditionToken);
@@ -303,14 +539,17 @@ LatticeJoinEffect Environment::join(const Environment &Other,
continue;
assert(It->second != nullptr);
- if (Val == It->second) {
+ if (areEquivalentValues(*Val, *It->second)) {
JoinedEnv.LocToVal.insert({Loc, Val});
continue;
}
- if (Value *MergedVal = mergeDistinctValues(
- Loc->getType(), Val, *this, It->second, Other, JoinedEnv, Model))
+ if (Value *MergedVal =
+ mergeDistinctValues(Loc->getType(), *Val, *this, *It->second, Other,
+ JoinedEnv, Model)) {
JoinedEnv.LocToVal.insert({Loc, MergedVal});
+ Effect = LatticeJoinEffect::Changed;
+ }
}
if (LocToVal.size() != JoinedEnv.LocToVal.size())
Effect = LatticeJoinEffect::Changed;
@@ -321,7 +560,7 @@ LatticeJoinEffect Environment::join(const Environment &Other,
}
StorageLocation &Environment::createStorageLocation(QualType Type) {
- return DACtx->getStableStorageLocation(Type);
+ return DACtx->createStorageLocation(Type);
}
StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
@@ -363,7 +602,11 @@ StorageLocation *Environment::getStorageLocation(const Expr &E,
}
StorageLocation *Environment::getThisPointeeStorageLocation() const {
- return DACtx->getThisPointeeStorageLocation();
+ return ThisPointeeLoc;
+}
+
+StorageLocation *Environment::getReturnStorageLocation() const {
+ return ReturnLoc;
}
PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
@@ -377,9 +620,9 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
const QualType Type = AggregateLoc.getType();
- assert(Type->isStructureOrClassType());
+ assert(Type->isStructureOrClassType() || Type->isUnionType());
- for (const FieldDecl *Field : getObjectFields(Type)) {
+ for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
assert(Field != nullptr);
StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
@@ -450,6 +693,9 @@ Value *Environment::createValueUnlessSelfReferential(
}
if (Type->isIntegerType()) {
+ // FIXME: consider instead `return nullptr`, given that we do nothing useful
+ // with integers, and so distinguishing them serves no purpose, but could
+ // prevent convergence.
CreatedValuesCount++;
return &takeOwnership(std::make_unique<IntegerValue>());
}
@@ -488,12 +734,10 @@ Value *Environment::createValueUnlessSelfReferential(
return &takeOwnership(std::make_unique<PointerValue>(PointeeLoc));
}
- if (Type->isStructureOrClassType()) {
+ if (Type->isStructureOrClassType() || Type->isUnionType()) {
CreatedValuesCount++;
- // FIXME: Initialize only fields that are accessed in the context that is
- // being analyzed.
llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
- for (const FieldDecl *Field : getObjectFields(Type)) {
+ for (const FieldDecl *Field : DACtx->getReferencedFields(Type)) {
assert(Field != nullptr);
QualType FieldType = Field->getType();
@@ -546,9 +790,29 @@ bool Environment::flowConditionImplies(BoolValue &Val) const {
return DACtx->flowConditionImplies(*FlowConditionToken, Val);
}
-void Environment::dump() const {
+void Environment::dump(raw_ostream &OS) const {
+ // FIXME: add printing for remaining fields and allow caller to decide what
+ // fields are printed.
+ OS << "DeclToLoc:\n";
+ for (auto [D, L] : DeclToLoc)
+ OS << " [" << D->getName() << ", " << L << "]\n";
+
+ OS << "ExprToLoc:\n";
+ for (auto [E, L] : ExprToLoc)
+ OS << " [" << E << ", " << L << "]\n";
+
+ OS << "LocToVal:\n";
+ for (auto [L, V] : LocToVal) {
+ OS << " [" << L << ", " << V << ": " << *V << "]\n";
+ }
+
+ OS << "FlowConditionToken:\n";
DACtx->dumpFlowCondition(*FlowConditionToken);
}
+void Environment::dump() const {
+ dump(llvm::dbgs());
+}
+
} // namespace dataflow
} // namespace clang
diff --git a/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp b/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
index 714ad08643ed..d4886f154b33 100644
--- a/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
+++ b/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
@@ -18,6 +18,7 @@
#include "clang/Analysis/FlowSensitive/Value.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatAdapters.h"
@@ -31,7 +32,35 @@ using llvm::AlignStyle;
using llvm::fmt_pad;
using llvm::formatv;
-std::string debugString(Solver::Result::Assignment Assignment) {
+llvm::StringRef debugString(Value::Kind Kind) {
+ switch (Kind) {
+ case Value::Kind::Integer:
+ return "Integer";
+ case Value::Kind::Reference:
+ return "Reference";
+ case Value::Kind::Pointer:
+ return "Pointer";
+ case Value::Kind::Struct:
+ return "Struct";
+ case Value::Kind::AtomicBool:
+ return "AtomicBool";
+ case Value::Kind::TopBool:
+ return "TopBool";
+ case Value::Kind::Conjunction:
+ return "Conjunction";
+ case Value::Kind::Disjunction:
+ return "Disjunction";
+ case Value::Kind::Negation:
+ return "Negation";
+ case Value::Kind::Implication:
+ return "Implication";
+ case Value::Kind::Biconditional:
+ return "Biconditional";
+ }
+ llvm_unreachable("Unhandled value kind");
+}
+
+llvm::StringRef debugString(Solver::Result::Assignment Assignment) {
switch (Assignment) {
case Solver::Result::Assignment::AssignedFalse:
return "False";
@@ -41,7 +70,7 @@ std::string debugString(Solver::Result::Assignment Assignment) {
llvm_unreachable("Booleans can only be assigned true/false");
}
-std::string debugString(Solver::Result::Status Status) {
+llvm::StringRef debugString(Solver::Result::Status Status) {
switch (Status) {
case Solver::Result::Status::Satisfiable:
return "Satisfiable";
@@ -156,7 +185,7 @@ Constraints
auto StatusString = clang::dataflow::debugString(Result.getStatus());
auto Solution = Result.getSolution();
- auto SolutionString = Solution ? "\n" + debugString(Solution.value()) : "";
+ auto SolutionString = Solution ? "\n" + debugString(*Solution) : "";
return formatv(
Template,
diff --git a/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp
index 3910847316a5..f457964fb132 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/ChromiumCheckModel.cpp
@@ -50,7 +50,11 @@ bool isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl *> &CheckDecls,
return CheckDecls.contains(&D);
}
-bool ChromiumCheckModel::transfer(const Stmt *Stmt, Environment &Env) {
+bool ChromiumCheckModel::transfer(const CFGElement *Element, Environment &Env) {
+ auto CS = Element->getAs<CFGStmt>();
+ if (!CS)
+ return false;
+ auto Stmt = CS->getStmt();
if (const auto *Call = dyn_cast<CallExpr>(Stmt)) {
if (const auto *M = dyn_cast<CXXMethodDecl>(Call->getDirectCallee())) {
if (isCheckLikeMethod(CheckDecls, *M)) {
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index eef3cc813a4a..308dc25dad1f 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -18,15 +18,19 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Stmt.h"
#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
-#include "clang/Analysis/FlowSensitive/MatchSwitch.h"
#include "clang/Analysis/FlowSensitive/NoopLattice.h"
+#include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <memory>
+#include <optional>
#include <utility>
#include <vector>
@@ -55,7 +59,7 @@ auto hasOptionalType() { return hasType(optionalOrAliasType()); }
auto isOptionalMemberCallWithName(
llvm::StringRef MemberName,
- llvm::Optional<StatementMatcher> Ignorable = llvm::None) {
+ const std::optional<StatementMatcher> &Ignorable = std::nullopt) {
auto Exception = unless(Ignorable ? expr(anyOf(*Ignorable, cxxThisExpr()))
: cxxThisExpr());
return cxxMemberCallExpr(
@@ -65,7 +69,7 @@ auto isOptionalMemberCallWithName(
auto isOptionalOperatorCallWithName(
llvm::StringRef operator_name,
- llvm::Optional<StatementMatcher> Ignorable = llvm::None) {
+ const std::optional<StatementMatcher> &Ignorable = std::nullopt) {
return cxxOperatorCallExpr(
hasOverloadedOperatorName(operator_name),
callee(cxxMethodDecl(ofClass(optionalClass()))),
@@ -79,19 +83,30 @@ auto isMakeOptionalCall() {
hasOptionalType());
}
-auto hasNulloptType() {
- return hasType(namedDecl(
- hasAnyName("std::nullopt_t", "absl::nullopt_t", "base::nullopt_t")));
+auto nulloptTypeDecl() {
+ return namedDecl(
+ hasAnyName("std::nullopt_t", "absl::nullopt_t", "base::nullopt_t"));
}
+auto hasNulloptType() { return hasType(nulloptTypeDecl()); }
+
+// `optional` or `nullopt_t`
+auto hasAnyOptionalType() {
+ return hasType(hasUnqualifiedDesugaredType(
+ recordType(hasDeclaration(anyOf(nulloptTypeDecl(), optionalClass())))));
+}
+
+
auto inPlaceClass() {
return recordDecl(
hasAnyName("std::in_place_t", "absl::in_place_t", "base::in_place_t"));
}
auto isOptionalNulloptConstructor() {
- return cxxConstructExpr(hasOptionalType(), argumentCountIs(1),
- hasArgument(0, hasNulloptType()));
+ return cxxConstructExpr(
+ hasOptionalType(),
+ hasDeclaration(cxxConstructorDecl(parameterCountIs(1),
+ hasParameter(0, hasNulloptType()))));
}
auto isOptionalInPlaceConstructor() {
@@ -116,6 +131,11 @@ auto isOptionalValueOrConversionAssignment() {
argumentCountIs(2), hasArgument(1, unless(hasNulloptType())));
}
+auto isNulloptConstructor() {
+ return cxxConstructExpr(hasNulloptType(), argumentCountIs(1),
+ hasArgument(0, hasNulloptType()));
+}
+
auto isOptionalNulloptAssignment() {
return cxxOperatorCallExpr(hasOverloadedOperatorName("="),
callee(cxxMethodDecl(ofClass(optionalClass()))),
@@ -171,6 +191,27 @@ auto isCallReturningOptional() {
optionalOrAliasType(), referenceType(pointee(optionalOrAliasType()))))));
}
+template <typename L, typename R>
+auto isComparisonOperatorCall(L lhs_arg_matcher, R rhs_arg_matcher) {
+ return cxxOperatorCallExpr(
+ anyOf(hasOverloadedOperatorName("=="), hasOverloadedOperatorName("!=")),
+ argumentCountIs(2), hasArgument(0, lhs_arg_matcher),
+ hasArgument(1, rhs_arg_matcher));
+}
+
+// Ensures that `Expr` is mapped to a `BoolValue` and returns it.
+BoolValue &forceBoolValue(Environment &Env, const Expr &Expr) {
+ auto *Value = cast_or_null<BoolValue>(Env.getValue(Expr, SkipPast::None));
+ if (Value != nullptr)
+ return *Value;
+
+ auto &Loc = Env.createStorageLocation(Expr);
+ Value = &Env.makeAtomicBoolValue();
+ Env.setValue(Loc, *Value);
+ Env.setStorageLocation(Expr, Loc);
+ return *Value;
+}
+
/// Sets `HasValueVal` as the symbolic value that represents the "has_value"
/// property of the optional value `OptionalVal`.
void setHasValue(Value &OptionalVal, BoolValue &HasValueVal) {
@@ -207,7 +248,7 @@ QualType stripReference(QualType Type) {
}
/// Returns true if and only if `Type` is an optional type.
-bool IsOptionalType(QualType Type) {
+bool isOptionalType(QualType Type) {
if (!Type->isRecordType())
return false;
// FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call.
@@ -221,7 +262,7 @@ bool IsOptionalType(QualType Type) {
/// For example, if `Type` is `optional<optional<int>>`, the result of this
/// function will be 2.
int countOptionalWrappers(const ASTContext &ASTCtx, QualType Type) {
- if (!IsOptionalType(Type))
+ if (!isOptionalType(Type))
return 0;
return 1 + countOptionalWrappers(
ASTCtx,
@@ -356,16 +397,8 @@ void transferValueOrImpl(const clang::Expr *ValueOrPredExpr,
if (HasValueVal == nullptr)
return;
- auto *ExprValue = cast_or_null<BoolValue>(
- State.Env.getValue(*ValueOrPredExpr, SkipPast::None));
- if (ExprValue == nullptr) {
- auto &ExprLoc = State.Env.createStorageLocation(*ValueOrPredExpr);
- ExprValue = &State.Env.makeAtomicBoolValue();
- State.Env.setValue(ExprLoc, *ExprValue);
- State.Env.setStorageLocation(*ValueOrPredExpr, ExprLoc);
- }
-
- Env.addToFlowCondition(ModelPred(Env, *ExprValue, *HasValueVal));
+ Env.addToFlowCondition(
+ ModelPred(Env, forceBoolValue(Env, *ValueOrPredExpr), *HasValueVal));
}
void transferValueOrStringEmptyCall(const clang::Expr *ComparisonExpr,
@@ -410,21 +443,21 @@ void transferCallReturningOptional(const CallExpr *E,
Loc, createOptionalValue(State.Env, State.Env.makeAtomicBoolValue()));
}
-void assignOptionalValue(const Expr &E, LatticeTransferState &State,
+void assignOptionalValue(const Expr &E, Environment &Env,
BoolValue &HasValueVal) {
if (auto *OptionalLoc =
- State.Env.getStorageLocation(E, SkipPast::ReferenceThenPointer)) {
- State.Env.setValue(*OptionalLoc,
- createOptionalValue(State.Env, HasValueVal));
+ Env.getStorageLocation(E, SkipPast::ReferenceThenPointer)) {
+ Env.setValue(*OptionalLoc, createOptionalValue(Env, HasValueVal));
}
}
/// Returns a symbolic value for the "has_value" property of an `optional<T>`
/// value that is constructed/assigned from a value of type `U` or `optional<U>`
/// where `T` is constructible from `U`.
-BoolValue &value_orConversionHasValue(const FunctionDecl &F, const Expr &E,
- const MatchFinder::MatchResult &MatchRes,
- LatticeTransferState &State) {
+BoolValue &valueOrConversionHasValue(const FunctionDecl &F, const Expr &E,
+ const MatchFinder::MatchResult &MatchRes,
+ LatticeTransferState &State) {
+ assert(F.getTemplateSpecializationArgs() != nullptr);
assert(F.getTemplateSpecializationArgs()->size() > 0);
const int TemplateParamOptionalWrappersCount = countOptionalWrappers(
@@ -451,10 +484,10 @@ void transferValueOrConversionConstructor(
LatticeTransferState &State) {
assert(E->getNumArgs() > 0);
- assignOptionalValue(*E, State,
- value_orConversionHasValue(*E->getConstructor(),
- *E->getArg(0), MatchRes,
- State));
+ assignOptionalValue(*E, State.Env,
+ valueOrConversionHasValue(*E->getConstructor(),
+ *E->getArg(0), MatchRes,
+ State));
}
void transferAssignment(const CXXOperatorCallExpr *E, BoolValue &HasValueVal,
@@ -477,8 +510,8 @@ void transferValueOrConversionAssignment(
LatticeTransferState &State) {
assert(E->getNumArgs() > 1);
transferAssignment(E,
- value_orConversionHasValue(*E->getDirectCallee(),
- *E->getArg(1), MatchRes, State),
+ valueOrConversionHasValue(*E->getDirectCallee(),
+ *E->getArg(1), MatchRes, State),
State);
}
@@ -532,123 +565,209 @@ void transferStdSwapCall(const CallExpr *E, const MatchFinder::MatchResult &,
transferSwap(*OptionalLoc1, *OptionalLoc2, State);
}
-llvm::Optional<StatementMatcher>
+BoolValue &evaluateEquality(Environment &Env, BoolValue &EqVal, BoolValue &LHS,
+ BoolValue &RHS) {
+ // Logically, an optional<T> object is composed of two values - a `has_value`
+ // bit and a value of type T. Equality of optional objects compares both
+ // values. Therefore, merely comparing the `has_value` bits isn't sufficient:
+ // when two optional objects are engaged, the equality of their respective
+ // values of type T matters. Since we only track the `has_value` bits, we
+ // can't make any conclusions about equality when we know that two optional
+ // objects are engaged.
+ //
+ // We express this as two facts about the equality:
+ // a) EqVal => (LHS & RHS) v (!RHS & !LHS)
+ // If they are equal, then either both are set or both are unset.
+ // b) (!LHS & !RHS) => EqVal
+ // If neither is set, then they are equal.
+ // We rewrite b) as !EqVal => (LHS v RHS), for a more compact formula.
+ return Env.makeAnd(
+ Env.makeImplication(
+ EqVal, Env.makeOr(Env.makeAnd(LHS, RHS),
+ Env.makeAnd(Env.makeNot(LHS), Env.makeNot(RHS)))),
+ Env.makeImplication(Env.makeNot(EqVal), Env.makeOr(LHS, RHS)));
+}
+
+void transferOptionalAndOptionalCmp(const clang::CXXOperatorCallExpr *CmpExpr,
+ const MatchFinder::MatchResult &,
+ LatticeTransferState &State) {
+ Environment &Env = State.Env;
+ auto *CmpValue = &forceBoolValue(Env, *CmpExpr);
+ if (auto *LHasVal = getHasValue(
+ Env, Env.getValue(*CmpExpr->getArg(0), SkipPast::Reference)))
+ if (auto *RHasVal = getHasValue(
+ Env, Env.getValue(*CmpExpr->getArg(1), SkipPast::Reference))) {
+ if (CmpExpr->getOperator() == clang::OO_ExclaimEqual)
+ CmpValue = &State.Env.makeNot(*CmpValue);
+ Env.addToFlowCondition(
+ evaluateEquality(Env, *CmpValue, *LHasVal, *RHasVal));
+ }
+}
+
+void transferOptionalAndValueCmp(const clang::CXXOperatorCallExpr *CmpExpr,
+ const clang::Expr *E, Environment &Env) {
+ auto *CmpValue = &forceBoolValue(Env, *CmpExpr);
+ if (auto *HasVal = getHasValue(Env, Env.getValue(*E, SkipPast::Reference))) {
+ if (CmpExpr->getOperator() == clang::OO_ExclaimEqual)
+ CmpValue = &Env.makeNot(*CmpValue);
+ Env.addToFlowCondition(evaluateEquality(Env, *CmpValue, *HasVal,
+ Env.getBoolLiteralValue(true)));
+ }
+}
+
+std::optional<StatementMatcher>
ignorableOptional(const UncheckedOptionalAccessModelOptions &Options) {
- if (Options.IgnoreSmartPointerDereference)
- return memberExpr(hasObjectExpression(ignoringParenImpCasts(
- cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("->"),
- hasOverloadedOperatorName("*")),
- unless(hasArgument(0, expr(hasOptionalType())))))));
- return llvm::None;
+ if (Options.IgnoreSmartPointerDereference) {
+ auto SmartPtrUse = expr(ignoringParenImpCasts(cxxOperatorCallExpr(
+ anyOf(hasOverloadedOperatorName("->"), hasOverloadedOperatorName("*")),
+ unless(hasArgument(0, expr(hasOptionalType()))))));
+ return expr(
+ anyOf(SmartPtrUse, memberExpr(hasObjectExpression(SmartPtrUse))));
+ }
+ return std::nullopt;
}
StatementMatcher
-valueCall(llvm::Optional<StatementMatcher> &IgnorableOptional) {
+valueCall(const std::optional<StatementMatcher> &IgnorableOptional) {
return isOptionalMemberCallWithName("value", IgnorableOptional);
}
StatementMatcher
-valueOperatorCall(llvm::Optional<StatementMatcher> &IgnorableOptional) {
+valueOperatorCall(const std::optional<StatementMatcher> &IgnorableOptional) {
return expr(anyOf(isOptionalOperatorCallWithName("*", IgnorableOptional),
isOptionalOperatorCallWithName("->", IgnorableOptional)));
}
-auto buildTransferMatchSwitch(
- const UncheckedOptionalAccessModelOptions &Options) {
+auto buildTransferMatchSwitch() {
// FIXME: Evaluate the efficiency of matchers. If using matchers results in a
// lot of duplicated work (e.g. string comparisons), consider providing APIs
// that avoid it through memoization.
- auto IgnorableOptional = ignorableOptional(Options);
- return MatchSwitchBuilder<LatticeTransferState>()
+ return CFGMatchSwitchBuilder<LatticeTransferState>()
// Attach a symbolic "has_value" state to optional values that we see for
// the first time.
- .CaseOf<Expr>(
+ .CaseOfCFGStmt<Expr>(
expr(anyOf(declRefExpr(), memberExpr()), hasOptionalType()),
initializeOptionalReference)
// make_optional
- .CaseOf<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall)
+ .CaseOfCFGStmt<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall)
- // optional::optional
- .CaseOf<CXXConstructExpr>(
+ // optional::optional (in place)
+ .CaseOfCFGStmt<CXXConstructExpr>(
isOptionalInPlaceConstructor(),
[](const CXXConstructExpr *E, const MatchFinder::MatchResult &,
LatticeTransferState &State) {
- assignOptionalValue(*E, State, State.Env.getBoolLiteralValue(true));
+ assignOptionalValue(*E, State.Env,
+ State.Env.getBoolLiteralValue(true));
+ })
+ // nullopt_t::nullopt_t
+ .CaseOfCFGStmt<CXXConstructExpr>(
+ isNulloptConstructor(),
+ [](const CXXConstructExpr *E, const MatchFinder::MatchResult &,
+ LatticeTransferState &State) {
+ assignOptionalValue(*E, State.Env,
+ State.Env.getBoolLiteralValue(false));
})
- .CaseOf<CXXConstructExpr>(
+ // optional::optional(nullopt_t)
+ .CaseOfCFGStmt<CXXConstructExpr>(
isOptionalNulloptConstructor(),
[](const CXXConstructExpr *E, const MatchFinder::MatchResult &,
LatticeTransferState &State) {
- assignOptionalValue(*E, State,
+ assignOptionalValue(*E, State.Env,
State.Env.getBoolLiteralValue(false));
})
- .CaseOf<CXXConstructExpr>(isOptionalValueOrConversionConstructor(),
- transferValueOrConversionConstructor)
+ // optional::optional (value/conversion)
+ .CaseOfCFGStmt<CXXConstructExpr>(isOptionalValueOrConversionConstructor(),
+ transferValueOrConversionConstructor)
+
// optional::operator=
- .CaseOf<CXXOperatorCallExpr>(isOptionalValueOrConversionAssignment(),
- transferValueOrConversionAssignment)
- .CaseOf<CXXOperatorCallExpr>(isOptionalNulloptAssignment(),
- transferNulloptAssignment)
+ .CaseOfCFGStmt<CXXOperatorCallExpr>(
+ isOptionalValueOrConversionAssignment(),
+ transferValueOrConversionAssignment)
+ .CaseOfCFGStmt<CXXOperatorCallExpr>(isOptionalNulloptAssignment(),
+ transferNulloptAssignment)
// optional::value
- .CaseOf<CXXMemberCallExpr>(
- valueCall(IgnorableOptional),
+ .CaseOfCFGStmt<CXXMemberCallExpr>(
+ valueCall(std::nullopt),
[](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &,
LatticeTransferState &State) {
transferUnwrapCall(E, E->getImplicitObjectArgument(), State);
})
// optional::operator*, optional::operator->
- .CaseOf<CallExpr>(valueOperatorCall(IgnorableOptional),
- [](const CallExpr *E, const MatchFinder::MatchResult &,
- LatticeTransferState &State) {
- transferUnwrapCall(E, E->getArg(0), State);
- })
+ .CaseOfCFGStmt<CallExpr>(valueOperatorCall(std::nullopt),
+ [](const CallExpr *E,
+ const MatchFinder::MatchResult &,
+ LatticeTransferState &State) {
+ transferUnwrapCall(E, E->getArg(0), State);
+ })
// optional::has_value
- .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("has_value"),
- transferOptionalHasValueCall)
+ .CaseOfCFGStmt<CXXMemberCallExpr>(
+ isOptionalMemberCallWithName("has_value"),
+ transferOptionalHasValueCall)
// optional::operator bool
- .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("operator bool"),
- transferOptionalHasValueCall)
+ .CaseOfCFGStmt<CXXMemberCallExpr>(
+ isOptionalMemberCallWithName("operator bool"),
+ transferOptionalHasValueCall)
// optional::emplace
- .CaseOf<CXXMemberCallExpr>(
+ .CaseOfCFGStmt<CXXMemberCallExpr>(
isOptionalMemberCallWithName("emplace"),
[](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &,
LatticeTransferState &State) {
- assignOptionalValue(*E->getImplicitObjectArgument(), State,
+ assignOptionalValue(*E->getImplicitObjectArgument(), State.Env,
State.Env.getBoolLiteralValue(true));
})
// optional::reset
- .CaseOf<CXXMemberCallExpr>(
+ .CaseOfCFGStmt<CXXMemberCallExpr>(
isOptionalMemberCallWithName("reset"),
[](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &,
LatticeTransferState &State) {
- assignOptionalValue(*E->getImplicitObjectArgument(), State,
+ assignOptionalValue(*E->getImplicitObjectArgument(), State.Env,
State.Env.getBoolLiteralValue(false));
})
// optional::swap
- .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("swap"),
- transferSwapCall)
+ .CaseOfCFGStmt<CXXMemberCallExpr>(isOptionalMemberCallWithName("swap"),
+ transferSwapCall)
// std::swap
- .CaseOf<CallExpr>(isStdSwapCall(), transferStdSwapCall)
+ .CaseOfCFGStmt<CallExpr>(isStdSwapCall(), transferStdSwapCall)
// opt.value_or("").empty()
- .CaseOf<Expr>(isValueOrStringEmptyCall(), transferValueOrStringEmptyCall)
+ .CaseOfCFGStmt<Expr>(isValueOrStringEmptyCall(),
+ transferValueOrStringEmptyCall)
// opt.value_or(X) != X
- .CaseOf<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
+ .CaseOfCFGStmt<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
+
+ // Comparisons (==, !=):
+ .CaseOfCFGStmt<CXXOperatorCallExpr>(
+ isComparisonOperatorCall(hasAnyOptionalType(), hasAnyOptionalType()),
+ transferOptionalAndOptionalCmp)
+ .CaseOfCFGStmt<CXXOperatorCallExpr>(
+ isComparisonOperatorCall(hasOptionalType(),
+ unless(hasAnyOptionalType())),
+ [](const clang::CXXOperatorCallExpr *Cmp,
+ const MatchFinder::MatchResult &, LatticeTransferState &State) {
+ transferOptionalAndValueCmp(Cmp, Cmp->getArg(0), State.Env);
+ })
+ .CaseOfCFGStmt<CXXOperatorCallExpr>(
+ isComparisonOperatorCall(unless(hasAnyOptionalType()),
+ hasOptionalType()),
+ [](const clang::CXXOperatorCallExpr *Cmp,
+ const MatchFinder::MatchResult &, LatticeTransferState &State) {
+ transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env);
+ })
// returns optional
- .CaseOf<CallExpr>(isCallReturningOptional(),
- transferCallReturningOptional)
+ .CaseOfCFGStmt<CallExpr>(isCallReturningOptional(),
+ transferCallReturningOptional)
.Build();
}
@@ -677,9 +796,9 @@ auto buildDiagnoseMatchSwitch(
// lot of duplicated work (e.g. string comparisons), consider providing APIs
// that avoid it through memoization.
auto IgnorableOptional = ignorableOptional(Options);
- return MatchSwitchBuilder<const Environment, std::vector<SourceLocation>>()
+ return CFGMatchSwitchBuilder<const Environment, std::vector<SourceLocation>>()
// optional::value
- .CaseOf<CXXMemberCallExpr>(
+ .CaseOfCFGStmt<CXXMemberCallExpr>(
valueCall(IgnorableOptional),
[](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &,
const Environment &Env) {
@@ -687,7 +806,7 @@ auto buildDiagnoseMatchSwitch(
})
// optional::operator*, optional::operator->
- .CaseOf<CallExpr>(
+ .CaseOfCFGStmt<CallExpr>(
valueOperatorCall(IgnorableOptional),
[](const CallExpr *E, const MatchFinder::MatchResult &,
const Environment &Env) {
@@ -703,23 +822,31 @@ UncheckedOptionalAccessModel::optionalClassDecl() {
return optionalClass();
}
-UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(
- ASTContext &Ctx, UncheckedOptionalAccessModelOptions Options)
+UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(ASTContext &Ctx)
: DataflowAnalysis<UncheckedOptionalAccessModel, NoopLattice>(Ctx),
- TransferMatchSwitch(buildTransferMatchSwitch(Options)) {}
+ TransferMatchSwitch(buildTransferMatchSwitch()) {}
-void UncheckedOptionalAccessModel::transfer(const Stmt *S, NoopLattice &L,
- Environment &Env) {
+void UncheckedOptionalAccessModel::transfer(const CFGElement *Elt,
+ NoopLattice &L, Environment &Env) {
LatticeTransferState State(L, Env);
- TransferMatchSwitch(*S, getASTContext(), State);
-}
-
-bool UncheckedOptionalAccessModel::compareEquivalent(QualType Type,
- const Value &Val1,
- const Environment &Env1,
- const Value &Val2,
- const Environment &Env2) {
- return isNonEmptyOptional(Val1, Env1) == isNonEmptyOptional(Val2, Env2);
+ TransferMatchSwitch(*Elt, getASTContext(), State);
+}
+
+ComparisonResult UncheckedOptionalAccessModel::compare(
+ QualType Type, const Value &Val1, const Environment &Env1,
+ const Value &Val2, const Environment &Env2) {
+ if (!isOptionalType(Type))
+ return ComparisonResult::Unknown;
+ bool MustNonEmpty1 = isNonEmptyOptional(Val1, Env1);
+ bool MustNonEmpty2 = isNonEmptyOptional(Val2, Env2);
+ if (MustNonEmpty1 && MustNonEmpty2) return ComparisonResult::Same;
+ // If exactly one is true, then they're different, no reason to check whether
+ // they're definitely empty.
+ if (MustNonEmpty1 || MustNonEmpty2) return ComparisonResult::Different;
+ // Check if they're both definitely empty.
+ return (isEmptyOptional(Val1, Env1) && isEmptyOptional(Val2, Env2))
+ ? ComparisonResult::Same
+ : ComparisonResult::Different;
}
bool UncheckedOptionalAccessModel::merge(QualType Type, const Value &Val1,
@@ -728,25 +855,57 @@ bool UncheckedOptionalAccessModel::merge(QualType Type, const Value &Val1,
const Environment &Env2,
Value &MergedVal,
Environment &MergedEnv) {
- if (!IsOptionalType(Type))
+ if (!isOptionalType(Type))
return true;
-
+ // FIXME: uses same approach as join for `BoolValues`. Requires non-const
+ // values, though, so will require updating the interface.
auto &HasValueVal = MergedEnv.makeAtomicBoolValue();
- if (isNonEmptyOptional(Val1, Env1) && isNonEmptyOptional(Val2, Env2))
+ bool MustNonEmpty1 = isNonEmptyOptional(Val1, Env1);
+ bool MustNonEmpty2 = isNonEmptyOptional(Val2, Env2);
+ if (MustNonEmpty1 && MustNonEmpty2)
MergedEnv.addToFlowCondition(HasValueVal);
- else if (isEmptyOptional(Val1, Env1) && isEmptyOptional(Val2, Env2))
+ else if (
+ // Only make the costly calls to `isEmptyOptional` if we got "unknown"
+ // (false) for both calls to `isNonEmptyOptional`.
+ !MustNonEmpty1 && !MustNonEmpty2 && isEmptyOptional(Val1, Env1) &&
+ isEmptyOptional(Val2, Env2))
MergedEnv.addToFlowCondition(MergedEnv.makeNot(HasValueVal));
setHasValue(MergedVal, HasValueVal);
return true;
}
+Value *UncheckedOptionalAccessModel::widen(QualType Type, Value &Prev,
+ const Environment &PrevEnv,
+ Value &Current,
+ Environment &CurrentEnv) {
+ switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
+ case ComparisonResult::Same:
+ return &Prev;
+ case ComparisonResult::Different:
+ if (auto *PrevHasVal =
+ cast_or_null<BoolValue>(Prev.getProperty("has_value"))) {
+ if (isa<TopBoolValue>(PrevHasVal))
+ return &Prev;
+ }
+ if (auto *CurrentHasVal =
+ cast_or_null<BoolValue>(Current.getProperty("has_value"))) {
+ if (isa<TopBoolValue>(CurrentHasVal))
+ return &Current;
+ }
+ return &createOptionalValue(CurrentEnv, CurrentEnv.makeTopBoolValue());
+ case ComparisonResult::Unknown:
+ return nullptr;
+ }
+ llvm_unreachable("all cases covered in switch");
+}
+
UncheckedOptionalAccessDiagnoser::UncheckedOptionalAccessDiagnoser(
UncheckedOptionalAccessModelOptions Options)
: DiagnoseMatchSwitch(buildDiagnoseMatchSwitch(Options)) {}
std::vector<SourceLocation> UncheckedOptionalAccessDiagnoser::diagnose(
- ASTContext &Context, const Stmt *Stmt, const Environment &Env) {
- return DiagnoseMatchSwitch(*Stmt, Context, Env);
+ ASTContext &Ctx, const CFGElement *Elt, const Environment &Env) {
+ return DiagnoseMatchSwitch(*Elt, Ctx, Env);
}
} // namespace dataflow
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index bbf7526adce9..0e6c484b67e7 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -28,6 +28,7 @@
#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <memory>
#include <tuple>
@@ -46,11 +47,91 @@ static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
return Env.makeAtomicBoolValue();
}
+// Functionally updates `V` such that any instances of `TopBool` are replaced
+// with fresh atomic bools. Note: This implementation assumes that `B` is a
+// tree; if `B` is a DAG, it will lose any sharing between subvalues that was
+// present in the original .
+static BoolValue &unpackValue(BoolValue &V, Environment &Env);
+
+template <typename Derived, typename M>
+BoolValue &unpackBinaryBoolValue(Environment &Env, BoolValue &B, M build) {
+ auto &V = *cast<Derived>(&B);
+ BoolValue &Left = V.getLeftSubValue();
+ BoolValue &Right = V.getRightSubValue();
+ BoolValue &ULeft = unpackValue(Left, Env);
+ BoolValue &URight = unpackValue(Right, Env);
+
+ if (&ULeft == &Left && &URight == &Right)
+ return V;
+
+ return (Env.*build)(ULeft, URight);
+}
+
+static BoolValue &unpackValue(BoolValue &V, Environment &Env) {
+ switch (V.getKind()) {
+ case Value::Kind::Integer:
+ case Value::Kind::Reference:
+ case Value::Kind::Pointer:
+ case Value::Kind::Struct:
+ llvm_unreachable("BoolValue cannot have any of these kinds.");
+
+ case Value::Kind::AtomicBool:
+ return V;
+
+ case Value::Kind::TopBool:
+ // Unpack `TopBool` into a fresh atomic bool.
+ return Env.makeAtomicBoolValue();
+
+ case Value::Kind::Negation: {
+ auto &N = *cast<NegationValue>(&V);
+ BoolValue &Sub = N.getSubVal();
+ BoolValue &USub = unpackValue(Sub, Env);
+
+ if (&USub == &Sub)
+ return V;
+ return Env.makeNot(USub);
+ }
+ case Value::Kind::Conjunction:
+ return unpackBinaryBoolValue<ConjunctionValue>(Env, V,
+ &Environment::makeAnd);
+ case Value::Kind::Disjunction:
+ return unpackBinaryBoolValue<DisjunctionValue>(Env, V,
+ &Environment::makeOr);
+ case Value::Kind::Implication:
+ return unpackBinaryBoolValue<ImplicationValue>(
+ Env, V, &Environment::makeImplication);
+ case Value::Kind::Biconditional:
+ return unpackBinaryBoolValue<BiconditionalValue>(Env, V,
+ &Environment::makeIff);
+ }
+ llvm_unreachable("All reachable cases in switch return");
+}
+
+// Unpacks the value (if any) associated with `E` and updates `E` to the new
+// value, if any unpacking occured.
+static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) {
+ // FIXME: this is too flexible: it _allows_ a reference, while it should
+ // _require_ one, since lvalues should always be wrapped in `ReferenceValue`.
+ auto *Loc = Env.getStorageLocation(E, SkipPast::Reference);
+ if (Loc == nullptr)
+ return nullptr;
+ auto *Val = Env.getValue(*Loc);
+
+ auto *B = dyn_cast_or_null<BoolValue>(Val);
+ if (B == nullptr)
+ return Val;
+
+ auto &UnpackedVal = unpackValue(*B, Env);
+ if (&UnpackedVal == Val)
+ return Val;
+ Env.setValue(*Loc, UnpackedVal);
+ return &UnpackedVal;
+}
+
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
public:
- TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
- TransferOptions Options)
- : StmtToEnv(StmtToEnv), Env(Env), Options(Options) {}
+ TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
+ : StmtToEnv(StmtToEnv), Env(Env) {}
void VisitBinaryOperator(const BinaryOperator *S) {
const Expr *LHS = S->getLHS();
@@ -109,12 +190,15 @@ public:
}
void VisitDeclRefExpr(const DeclRefExpr *S) {
- assert(S->getDecl() != nullptr);
- auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
+ const ValueDecl *VD = S->getDecl();
+ assert(VD != nullptr);
+ auto *DeclLoc = Env.getStorageLocation(*VD, SkipPast::None);
if (DeclLoc == nullptr)
return;
- if (S->getDecl()->getType()->isReferenceType()) {
+ if (VD->getType()->isReferenceType()) {
+ assert(isa_and_nonnull<ReferenceValue>(Env.getValue((*DeclLoc))) &&
+ "reference-typed declarations map to `ReferenceValue`s");
Env.setStorageLocation(*S, *DeclLoc);
} else {
auto &Loc = Env.createStorageLocation(*S);
@@ -133,8 +217,15 @@ public:
if (D.hasGlobalStorage())
return;
- auto &Loc = Env.createStorageLocation(D);
- Env.setStorageLocation(D, Loc);
+ // The storage location for `D` could have been created earlier, before the
+ // variable's declaration statement (for example, in the case of
+ // BindingDecls).
+ auto *MaybeLoc = Env.getStorageLocation(D, SkipPast::None);
+ if (MaybeLoc == nullptr) {
+ MaybeLoc = &Env.createStorageLocation(D);
+ Env.setStorageLocation(D, *MaybeLoc);
+ }
+ auto &Loc = *MaybeLoc;
const Expr *InitExpr = D.getInit();
if (InitExpr == nullptr) {
@@ -178,24 +269,30 @@ public:
// needs to be evaluated after initializing the values in the storage for
// VarDecl, as the bindings refer to them.
// FIXME: Add support for ArraySubscriptExpr.
- // FIXME: Consider adding AST nodes that are used for structured bindings
- // to the CFG.
+ // FIXME: Consider adding AST nodes used in BindingDecls to the CFG.
for (const auto *B : Decomp->bindings()) {
- auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding());
- if (ME == nullptr)
- continue;
-
- auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());
- if (DE == nullptr)
- continue;
-
- // ME and its base haven't been visited because they aren't included in
- // the statements of the CFG basic block.
- VisitDeclRefExpr(DE);
- VisitMemberExpr(ME);
-
- if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference))
- Env.setStorageLocation(*B, *Loc);
+ if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) {
+ auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());
+ if (DE == nullptr)
+ continue;
+
+ // ME and its base haven't been visited because they aren't included
+ // in the statements of the CFG basic block.
+ VisitDeclRefExpr(DE);
+ VisitMemberExpr(ME);
+
+ if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference))
+ Env.setStorageLocation(*B, *Loc);
+ } else if (auto *VD = B->getHoldingVar()) {
+ // Holding vars are used to back the BindingDecls of tuple-like
+ // types. The holding var declarations appear *after* this statement,
+ // so we have to create a location for them here to share with `B`. We
+ // don't visit the binding, because we know it will be a DeclRefExpr
+ // to `VD`.
+ auto &VDLoc = Env.createStorageLocation(*VD);
+ Env.setStorageLocation(*VD, VDLoc);
+ Env.setStorageLocation(*B, VDLoc);
+ }
}
}
}
@@ -222,7 +319,9 @@ public:
}
case CK_LValueToRValue: {
- auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
+ // When an L-value is used as an R-value, it may result in sharing, so we
+ // need to unpack any nested `Top`s.
+ auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env);
if (SubExprVal == nullptr)
break;
@@ -332,6 +431,32 @@ public:
std::make_unique<PointerValue>(*ThisPointeeLoc)));
}
+ void VisitReturnStmt(const ReturnStmt *S) {
+ if (!Env.getAnalysisOptions().ContextSensitiveOpts)
+ return;
+
+ auto *Ret = S->getRetValue();
+ if (Ret == nullptr)
+ return;
+
+ auto *Val = Env.getValue(*Ret, SkipPast::None);
+ if (Val == nullptr)
+ return;
+
+ // FIXME: Support reference-type returns.
+ if (Val->getKind() == Value::Kind::Reference)
+ return;
+
+ auto *Loc = Env.getReturnStorageLocation();
+ assert(Loc != nullptr);
+ // FIXME: Support reference-type returns.
+ if (Loc->getType()->isReferenceType())
+ return;
+
+ // FIXME: Model NRVO.
+ Env.setValue(*Loc, *Val);
+ }
+
void VisitMemberExpr(const MemberExpr *S) {
ValueDecl *Member = S->getMemberDecl();
assert(Member != nullptr);
@@ -340,6 +465,10 @@ public:
if (Member->isFunctionOrFunctionTemplate())
return;
+ // FIXME: if/when we add support for modeling enums, use that support here.
+ if (isa<EnumConstantDecl>(Member))
+ return;
+
if (auto *D = dyn_cast<VarDecl>(Member)) {
if (D->hasGlobalStorage()) {
auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None);
@@ -347,6 +476,8 @@ public:
return;
if (VarDeclLoc->getType()->isReferenceType()) {
+ assert(isa_and_nonnull<ReferenceValue>(Env.getValue((*VarDeclLoc))) &&
+ "reference-typed declarations map to `ReferenceValue`s");
Env.setStorageLocation(*S, *VarDeclLoc);
} else {
auto &Loc = Env.createStorageLocation(*S);
@@ -365,13 +496,24 @@ public:
if (BaseLoc == nullptr)
return;
- // FIXME: Add support for union types.
- if (BaseLoc->getType()->isUnionType())
- return;
-
auto &MemberLoc = BaseLoc->getChild(*Member);
if (MemberLoc.getType()->isReferenceType()) {
- Env.setStorageLocation(*S, MemberLoc);
+ // Based on its type, `MemberLoc` must be mapped either to nothing or to a
+ // `ReferenceValue`. For the former, we won't set a storage location for
+ // this expression, so as to maintain an invariant lvalue expressions;
+ // namely, that their location maps to a `ReferenceValue`. In this,
+ // lvalues are unlike other expressions, where it is valid for their
+ // location to map to nothing (because they are not modeled).
+ //
+ // Note: we need this invariant for lvalues so that, when accessing a
+ // value, we can distinguish an rvalue from an lvalue. An alternative
+ // design, which takes the expression's value category into account, would
+ // avoid the need for this invariant.
+ if (auto *V = Env.getValue(MemberLoc)) {
+ assert(isa<ReferenceValue>(V) &&
+ "reference-typed declarations map to `ReferenceValue`s");
+ Env.setStorageLocation(*S, MemberLoc);
+ }
} else {
auto &Loc = Env.createStorageLocation(*S);
Env.setStorageLocation(*S, Loc);
@@ -425,6 +567,8 @@ public:
Env.setStorageLocation(*S, Loc);
if (Value *Val = Env.createValue(S->getType()))
Env.setValue(Loc, *Val);
+
+ transferInlineCall(S, ConstructorDecl);
}
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
@@ -507,34 +651,7 @@ public:
return;
Env.setStorageLocation(*S, *ArgLoc);
} else if (const FunctionDecl *F = S->getDirectCallee()) {
- // This case is for context-sensitive analysis, which we only do if we
- // have the callee body available in the translation unit.
- if (!Options.ContextSensitive || F->getBody() == nullptr)
- return;
-
- auto &ASTCtx = F->getASTContext();
-
- // FIXME: Cache these CFGs.
- auto CFCtx = ControlFlowContext::build(F, F->getBody(), &ASTCtx);
- // FIXME: Handle errors here and below.
- assert(CFCtx);
- auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
-
- auto CalleeEnv = Env.pushCall(S);
-
- // FIXME: Use the same analysis as the caller for the callee.
- DataflowAnalysisOptions Options;
- auto Analysis = NoopAnalysis(ASTCtx, Options);
-
- auto BlockToOutputState =
- dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
- assert(BlockToOutputState);
- assert(ExitBlock < BlockToOutputState->size());
-
- auto ExitState = (*BlockToOutputState)[ExitBlock];
- assert(ExitState);
-
- Env = ExitState->Env;
+ transferInlineCall(S, F);
}
}
@@ -663,14 +780,59 @@ private:
return Env.makeAtomicBoolValue();
}
+ // If context sensitivity is enabled, try to analyze the body of the callee
+ // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`.
+ template <typename E>
+ void transferInlineCall(const E *S, const FunctionDecl *F) {
+ const auto &Options = Env.getAnalysisOptions();
+ if (!(Options.ContextSensitiveOpts &&
+ Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))
+ return;
+
+ const ControlFlowContext *CFCtx = Env.getControlFlowContext(F);
+ if (!CFCtx)
+ return;
+
+ // FIXME: We don't support context-sensitive analysis of recursion, so
+ // we should return early here if `F` is the same as the `FunctionDecl`
+ // holding `S` itself.
+
+ auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
+
+ if (const auto *NonConstructExpr = dyn_cast<CallExpr>(S)) {
+ // Note that it is important for the storage location of `S` to be set
+ // before `pushCall`, because the latter uses it to set the storage
+ // location for `return`.
+ auto &ReturnLoc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, ReturnLoc);
+ }
+ auto CalleeEnv = Env.pushCall(S);
+
+ // FIXME: Use the same analysis as the caller for the callee. Note,
+ // though, that doing so would require support for changing the analysis's
+ // ASTContext.
+ assert(CFCtx->getDecl() != nullptr &&
+ "ControlFlowContexts in the environment should always carry a decl");
+ auto Analysis = NoopAnalysis(CFCtx->getDecl()->getASTContext(),
+ DataflowAnalysisOptions{Options});
+
+ auto BlockToOutputState =
+ dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
+ assert(BlockToOutputState);
+ assert(ExitBlock < BlockToOutputState->size());
+
+ auto ExitState = (*BlockToOutputState)[ExitBlock];
+ assert(ExitState);
+
+ Env.popCall(ExitState->Env);
+ }
+
const StmtToEnvMap &StmtToEnv;
Environment &Env;
- TransferOptions Options;
};
-void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
- TransferOptions Options) {
- TransferVisitor(StmtToEnv, Env, Options).Visit(&S);
+void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
+ TransferVisitor(StmtToEnv, Env).Visit(&S);
}
} // namespace dataflow
diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
index fbb521763ee6..b125701212c9 100644
--- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
+++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
@@ -13,6 +13,7 @@
#include <algorithm>
#include <memory>
+#include <optional>
#include <system_error>
#include <utility>
#include <vector>
@@ -23,17 +24,18 @@
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
+#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/DataflowWorklist.h"
#include "clang/Analysis/FlowSensitive/Transfer.h"
#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
+
+#define DEBUG_TYPE "clang-dataflow"
namespace clang {
namespace dataflow {
@@ -42,7 +44,7 @@ class StmtToEnvMapImpl : public StmtToEnvMap {
public:
StmtToEnvMapImpl(
const ControlFlowContext &CFCtx,
- llvm::ArrayRef<llvm::Optional<TypeErasedDataflowAnalysisState>>
+ llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>>
BlockToState)
: CFCtx(CFCtx), BlockToState(BlockToState) {}
@@ -51,12 +53,12 @@ public:
assert(BlockIt != CFCtx.getStmtToBlock().end());
const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
assert(State);
- return &State.value().Env;
+ return &State->Env;
}
private:
const ControlFlowContext &CFCtx;
- llvm::ArrayRef<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockToState;
+ llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockToState;
};
/// Returns the index of `Block` in the successors of `Pred`.
@@ -69,57 +71,79 @@ static int blockIndexInPredecessor(const CFGBlock &Pred,
return BlockPos - Pred.succ_begin();
}
+static bool isLoopHead(const CFGBlock &B) {
+ if (const auto *T = B.getTerminatorStmt())
+ switch (T->getStmtClass()) {
+ case Stmt::WhileStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::ForStmtClass:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+// The return type of the visit functions in TerminatorVisitor. The first
+// element represents the terminator expression (that is the conditional
+// expression in case of a path split in the CFG). The second element
+// represents whether the condition was true or false.
+using TerminatorVisitorRetTy = std::pair<const Expr *, bool>;
+
/// Extends the flow condition of an environment based on a terminator
/// statement.
-class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> {
+class TerminatorVisitor
+ : public ConstStmtVisitor<TerminatorVisitor, TerminatorVisitorRetTy> {
public:
TerminatorVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
- int BlockSuccIdx, TransferOptions TransferOpts)
- : StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx),
- TransferOpts(TransferOpts) {}
+ int BlockSuccIdx)
+ : StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx) {}
- void VisitIfStmt(const IfStmt *S) {
+ TerminatorVisitorRetTy VisitIfStmt(const IfStmt *S) {
auto *Cond = S->getCond();
assert(Cond != nullptr);
- extendFlowCondition(*Cond);
+ return extendFlowCondition(*Cond);
}
- void VisitWhileStmt(const WhileStmt *S) {
+ TerminatorVisitorRetTy VisitWhileStmt(const WhileStmt *S) {
auto *Cond = S->getCond();
assert(Cond != nullptr);
- extendFlowCondition(*Cond);
+ return extendFlowCondition(*Cond);
}
- void VisitDoStmt(const DoStmt *S) {
+ TerminatorVisitorRetTy VisitDoStmt(const DoStmt *S) {
auto *Cond = S->getCond();
assert(Cond != nullptr);
- extendFlowCondition(*Cond);
+ return extendFlowCondition(*Cond);
}
- void VisitForStmt(const ForStmt *S) {
+ TerminatorVisitorRetTy VisitForStmt(const ForStmt *S) {
auto *Cond = S->getCond();
if (Cond != nullptr)
- extendFlowCondition(*Cond);
+ return extendFlowCondition(*Cond);
+ return {nullptr, false};
}
- void VisitBinaryOperator(const BinaryOperator *S) {
+ TerminatorVisitorRetTy VisitBinaryOperator(const BinaryOperator *S) {
assert(S->getOpcode() == BO_LAnd || S->getOpcode() == BO_LOr);
auto *LHS = S->getLHS();
assert(LHS != nullptr);
- extendFlowCondition(*LHS);
+ return extendFlowCondition(*LHS);
}
- void VisitConditionalOperator(const ConditionalOperator *S) {
+ TerminatorVisitorRetTy
+ VisitConditionalOperator(const ConditionalOperator *S) {
auto *Cond = S->getCond();
assert(Cond != nullptr);
- extendFlowCondition(*Cond);
+ return extendFlowCondition(*Cond);
}
private:
- void extendFlowCondition(const Expr &Cond) {
+ TerminatorVisitorRetTy extendFlowCondition(const Expr &Cond) {
// The terminator sub-expression might not be evaluated.
if (Env.getStorageLocation(Cond, SkipPast::None) == nullptr)
- transfer(StmtToEnv, Cond, Env, TransferOpts);
+ transfer(StmtToEnv, Cond, Env);
// FIXME: The flow condition must be an r-value, so `SkipPast::None` should
// suffice.
@@ -140,18 +164,42 @@ private:
Env.setValue(*Loc, *Val);
}
+ bool ConditionValue = true;
// The condition must be inverted for the successor that encompasses the
// "else" branch, if such exists.
- if (BlockSuccIdx == 1)
+ if (BlockSuccIdx == 1) {
Val = &Env.makeNot(*Val);
+ ConditionValue = false;
+ }
Env.addToFlowCondition(*Val);
+ return {&Cond, ConditionValue};
}
const StmtToEnvMap &StmtToEnv;
Environment &Env;
int BlockSuccIdx;
- TransferOptions TransferOpts;
+};
+
+/// Holds data structures required for running dataflow analysis.
+struct AnalysisContext {
+ AnalysisContext(const ControlFlowContext &CFCtx,
+ TypeErasedDataflowAnalysis &Analysis,
+ const Environment &InitEnv,
+ llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>>
+ BlockStates)
+ : CFCtx(CFCtx), Analysis(Analysis), InitEnv(InitEnv),
+ BlockStates(BlockStates) {}
+
+ /// Contains the CFG being analyzed.
+ const ControlFlowContext &CFCtx;
+ /// The analysis to be run.
+ TypeErasedDataflowAnalysis &Analysis;
+ /// Initial state to start the analysis.
+ const Environment &InitEnv;
+ /// Stores the state of a CFG block if it has been evaluated by the analysis.
+ /// The indices correspond to the block IDs.
+ llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockStates;
};
/// Computes the input state for a given basic block by joining the output
@@ -160,13 +208,10 @@ private:
/// Requirements:
///
/// All predecessors of `Block` except those with loop back edges must have
-/// already been transferred. States in `BlockStates` that are set to
-/// `llvm::None` represent basic blocks that are not evaluated yet.
-static TypeErasedDataflowAnalysisState computeBlockInputState(
- const ControlFlowContext &CFCtx,
- std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> &BlockStates,
- const CFGBlock &Block, const Environment &InitEnv,
- TypeErasedDataflowAnalysis &Analysis) {
+/// already been transferred. States in `AC.BlockStates` that are set to
+/// `std::nullopt` represent basic blocks that are not evaluated yet.
+static TypeErasedDataflowAnalysisState
+computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) {
llvm::DenseSet<const CFGBlock *> Preds;
Preds.insert(Block.pred_begin(), Block.pred_end());
if (Block.getTerminator().isTemporaryDtorsBranch()) {
@@ -193,15 +238,16 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
//
// See `NoreturnDestructorTest` for concrete examples.
if (Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) {
- auto StmtBlock = CFCtx.getStmtToBlock().find(Block.getTerminatorStmt());
- assert(StmtBlock != CFCtx.getStmtToBlock().end());
+ auto &StmtToBlock = AC.CFCtx.getStmtToBlock();
+ auto StmtBlock = StmtToBlock.find(Block.getTerminatorStmt());
+ assert(StmtBlock != StmtToBlock.end());
Preds.erase(StmtBlock->getSecond());
}
}
- llvm::Optional<TypeErasedDataflowAnalysisState> MaybeState;
- bool ApplyBuiltinTransfer = Analysis.applyBuiltinTransfer();
+ std::optional<TypeErasedDataflowAnalysisState> MaybeState;
+ auto &Analysis = AC.Analysis;
for (const CFGBlock *Pred : Preds) {
// Skip if the `Block` is unreachable or control flow cannot get past it.
if (!Pred || Pred->hasNoReturnElement())
@@ -209,19 +255,24 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
// Skip if `Pred` was not evaluated yet. This could happen if `Pred` has a
// loop back edge to `Block`.
- const llvm::Optional<TypeErasedDataflowAnalysisState> &MaybePredState =
- BlockStates[Pred->getBlockID()];
+ const std::optional<TypeErasedDataflowAnalysisState> &MaybePredState =
+ AC.BlockStates[Pred->getBlockID()];
if (!MaybePredState)
continue;
- TypeErasedDataflowAnalysisState PredState = MaybePredState.value();
- if (ApplyBuiltinTransfer) {
+ TypeErasedDataflowAnalysisState PredState = *MaybePredState;
+ if (Analysis.builtinOptions()) {
if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) {
- const StmtToEnvMapImpl StmtToEnv(CFCtx, BlockStates);
- TerminatorVisitor(StmtToEnv, PredState.Env,
- blockIndexInPredecessor(*Pred, Block),
- Analysis.builtinTransferOptions())
- .Visit(PredTerminatorStmt);
+ const StmtToEnvMapImpl StmtToEnv(AC.CFCtx, AC.BlockStates);
+ auto [Cond, CondValue] =
+ TerminatorVisitor(StmtToEnv, PredState.Env,
+ blockIndexInPredecessor(*Pred, Block))
+ .Visit(PredTerminatorStmt);
+ if (Cond != nullptr)
+ // FIXME: Call transferBranchTypeErased even if BuiltinTransferOpts
+ // are not set.
+ Analysis.transferBranchTypeErased(CondValue, Cond, PredState.Lattice,
+ PredState.Env);
}
}
@@ -236,110 +287,127 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
// FIXME: Consider passing `Block` to `Analysis.typeErasedInitialElement()`
// to enable building analyses like computation of dominators that
// initialize the state of each basic block differently.
- MaybeState.emplace(Analysis.typeErasedInitialElement(), InitEnv);
+ MaybeState.emplace(Analysis.typeErasedInitialElement(), AC.InitEnv);
}
return *MaybeState;
}
-/// Transfers `State` by evaluating `CfgStmt` in the context of `Analysis`.
-/// `HandleTransferredStmt` (if provided) will be applied to `CfgStmt`, after it
-/// is evaluated.
-static void transferCFGStmt(
- const ControlFlowContext &CFCtx,
- llvm::ArrayRef<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates,
- const CFGStmt &CfgStmt, TypeErasedDataflowAnalysis &Analysis,
- TypeErasedDataflowAnalysisState &State,
- std::function<void(const CFGStmt &,
- const TypeErasedDataflowAnalysisState &)>
- HandleTransferredStmt) {
- const Stmt *S = CfgStmt.getStmt();
+/// Built-in transfer function for `CFGStmt`.
+void builtinTransferStatement(const CFGStmt &Elt,
+ TypeErasedDataflowAnalysisState &InputState,
+ AnalysisContext &AC) {
+ const Stmt *S = Elt.getStmt();
assert(S != nullptr);
-
- if (Analysis.applyBuiltinTransfer())
- transfer(StmtToEnvMapImpl(CFCtx, BlockStates), *S, State.Env,
- Analysis.builtinTransferOptions());
- Analysis.transferTypeErased(S, State.Lattice, State.Env);
-
- if (HandleTransferredStmt != nullptr)
- HandleTransferredStmt(CfgStmt, State);
+ transfer(StmtToEnvMapImpl(AC.CFCtx, AC.BlockStates), *S, InputState.Env);
}
-/// Transfers `State` by evaluating `CfgInit`.
-static void transferCFGInitializer(const CFGInitializer &CfgInit,
- TypeErasedDataflowAnalysisState &State) {
- const auto &ThisLoc = *cast<AggregateStorageLocation>(
- State.Env.getThisPointeeStorageLocation());
+/// Built-in transfer function for `CFGInitializer`.
+void builtinTransferInitializer(const CFGInitializer &Elt,
+ TypeErasedDataflowAnalysisState &InputState) {
+ const CXXCtorInitializer *Init = Elt.getInitializer();
+ assert(Init != nullptr);
- const CXXCtorInitializer *Initializer = CfgInit.getInitializer();
- assert(Initializer != nullptr);
+ auto &Env = InputState.Env;
+ const auto &ThisLoc =
+ *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
- const FieldDecl *Member = Initializer->getMember();
+ const FieldDecl *Member = Init->getMember();
if (Member == nullptr)
// Not a field initializer.
return;
- auto *InitStmt = Initializer->getInit();
+ auto *InitStmt = Init->getInit();
assert(InitStmt != nullptr);
- auto *InitStmtLoc =
- State.Env.getStorageLocation(*InitStmt, SkipPast::Reference);
+ auto *InitStmtLoc = Env.getStorageLocation(*InitStmt, SkipPast::Reference);
if (InitStmtLoc == nullptr)
return;
- auto *InitStmtVal = State.Env.getValue(*InitStmtLoc);
+ auto *InitStmtVal = Env.getValue(*InitStmtLoc);
if (InitStmtVal == nullptr)
return;
if (Member->getType()->isReferenceType()) {
auto &MemberLoc = ThisLoc.getChild(*Member);
- State.Env.setValue(MemberLoc,
- State.Env.takeOwnership(
- std::make_unique<ReferenceValue>(*InitStmtLoc)));
+ Env.setValue(MemberLoc, Env.takeOwnership(std::make_unique<ReferenceValue>(
+ *InitStmtLoc)));
} else {
auto &MemberLoc = ThisLoc.getChild(*Member);
- State.Env.setValue(MemberLoc, *InitStmtVal);
+ Env.setValue(MemberLoc, *InitStmtVal);
+ }
+}
+
+void builtinTransfer(const CFGElement &Elt,
+ TypeErasedDataflowAnalysisState &State,
+ AnalysisContext &AC) {
+ switch (Elt.getKind()) {
+ case CFGElement::Statement:
+ builtinTransferStatement(Elt.castAs<CFGStmt>(), State, AC);
+ break;
+ case CFGElement::Initializer:
+ builtinTransferInitializer(Elt.castAs<CFGInitializer>(), State);
+ break;
+ default:
+ // FIXME: Evaluate other kinds of `CFGElement`.
+ break;
}
}
+/// Transfers `State` by evaluating each element in the `Block` based on the
+/// `AC.Analysis` specified.
+///
+/// Built-in transfer functions (if the option for `ApplyBuiltinTransfer` is set
+/// by the analysis) will be applied to the element before evaluation by the
+/// user-specified analysis.
+/// `PostVisitCFG` (if provided) will be applied to the element after evaluation
+/// by the user-specified analysis.
+TypeErasedDataflowAnalysisState
+transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC,
+ std::function<void(const CFGElement &,
+ const TypeErasedDataflowAnalysisState &)>
+ PostVisitCFG = nullptr) {
+ auto State = computeBlockInputState(Block, AC);
+ for (const auto &Element : Block) {
+ // Built-in analysis
+ if (AC.Analysis.builtinOptions()) {
+ builtinTransfer(Element, State, AC);
+ }
+
+ // User-provided analysis
+ AC.Analysis.transferTypeErased(&Element, State.Lattice, State.Env);
+
+ // Post processing
+ if (PostVisitCFG) {
+ PostVisitCFG(Element, State);
+ }
+ }
+ return State;
+}
+
TypeErasedDataflowAnalysisState transferBlock(
const ControlFlowContext &CFCtx,
- std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> &BlockStates,
+ llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockStates,
const CFGBlock &Block, const Environment &InitEnv,
TypeErasedDataflowAnalysis &Analysis,
- std::function<void(const CFGStmt &,
+ std::function<void(const CFGElement &,
const TypeErasedDataflowAnalysisState &)>
- HandleTransferredStmt) {
- TypeErasedDataflowAnalysisState State =
- computeBlockInputState(CFCtx, BlockStates, Block, InitEnv, Analysis);
- for (const CFGElement &Element : Block) {
- switch (Element.getKind()) {
- case CFGElement::Statement:
- transferCFGStmt(CFCtx, BlockStates, *Element.getAs<CFGStmt>(), Analysis,
- State, HandleTransferredStmt);
- break;
- case CFGElement::Initializer:
- if (Analysis.applyBuiltinTransfer())
- transferCFGInitializer(*Element.getAs<CFGInitializer>(), State);
- break;
- default:
- // FIXME: Evaluate other kinds of `CFGElement`.
- break;
- }
- }
- return State;
+ PostVisitCFG) {
+ AnalysisContext AC(CFCtx, Analysis, InitEnv, BlockStates);
+ return transferCFGBlock(Block, AC, PostVisitCFG);
}
-llvm::Expected<std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>>>
+llvm::Expected<std::vector<std::optional<TypeErasedDataflowAnalysisState>>>
runTypeErasedDataflowAnalysis(
const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis,
const Environment &InitEnv,
- std::function<void(const Stmt *, const TypeErasedDataflowAnalysisState &)>
- PostVisitStmt) {
+ std::function<void(const CFGElement &,
+ const TypeErasedDataflowAnalysisState &)>
+ PostVisitCFG) {
PostOrderCFGView POV(&CFCtx.getCFG());
ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV);
- std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates;
- BlockStates.resize(CFCtx.getCFG().size(), llvm::None);
+ std::vector<std::optional<TypeErasedDataflowAnalysisState>> BlockStates(
+ CFCtx.getCFG().size(), std::nullopt);
// The entry basic block doesn't contain statements so it can be skipped.
const CFGBlock &Entry = CFCtx.getCFG().getEntry();
@@ -347,6 +415,8 @@ runTypeErasedDataflowAnalysis(
InitEnv};
Worklist.enqueueSuccessors(&Entry);
+ AnalysisContext AC(CFCtx, Analysis, InitEnv, BlockStates);
+
// Bugs in lattices and transfer functions can prevent the analysis from
// converging. To limit the damage (infinite loops) that these bugs can cause,
// limit the number of iterations.
@@ -363,23 +433,44 @@ runTypeErasedDataflowAnalysis(
std::min(RelativeMaxIterations, AbsoluteMaxIterations);
uint32_t Iterations = 0;
while (const CFGBlock *Block = Worklist.dequeue()) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Processing Block " << Block->getBlockID() << "\n");
if (++Iterations > MaxIterations) {
return llvm::createStringError(std::errc::timed_out,
"maximum number of iterations reached");
}
- const llvm::Optional<TypeErasedDataflowAnalysisState> &OldBlockState =
+ const std::optional<TypeErasedDataflowAnalysisState> &OldBlockState =
BlockStates[Block->getBlockID()];
TypeErasedDataflowAnalysisState NewBlockState =
- transferBlock(CFCtx, BlockStates, *Block, InitEnv, Analysis);
-
- if (OldBlockState &&
- Analysis.isEqualTypeErased(OldBlockState.value().Lattice,
- NewBlockState.Lattice) &&
- OldBlockState->Env.equivalentTo(NewBlockState.Env, Analysis)) {
- // The state of `Block` didn't change after transfer so there's no need to
- // revisit its successors.
- continue;
+ transferCFGBlock(*Block, AC);
+ LLVM_DEBUG({
+ llvm::errs() << "New Env:\n";
+ NewBlockState.Env.dump();
+ });
+
+ if (OldBlockState) {
+ LLVM_DEBUG({
+ llvm::errs() << "Old Env:\n";
+ OldBlockState->Env.dump();
+ });
+ if (isLoopHead(*Block)) {
+ LatticeJoinEffect Effect1 = Analysis.widenTypeErased(
+ NewBlockState.Lattice, OldBlockState->Lattice);
+ LatticeJoinEffect Effect2 =
+ NewBlockState.Env.widen(OldBlockState->Env, Analysis);
+ if (Effect1 == LatticeJoinEffect::Unchanged &&
+ Effect2 == LatticeJoinEffect::Unchanged)
+ // The state of `Block` didn't change from widening so there's no need
+ // to revisit its successors.
+ continue;
+ } else if (Analysis.isEqualTypeErased(OldBlockState->Lattice,
+ NewBlockState.Lattice) &&
+ OldBlockState->Env.equivalentTo(NewBlockState.Env, Analysis)) {
+ // The state of `Block` didn't change after transfer so there's no need
+ // to revisit its successors.
+ continue;
+ }
}
BlockStates[Block->getBlockID()] = std::move(NewBlockState);
@@ -391,19 +482,14 @@ runTypeErasedDataflowAnalysis(
Worklist.enqueueSuccessors(Block);
}
// FIXME: Consider evaluating unreachable basic blocks (those that have a
- // state set to `llvm::None` at this point) to also analyze dead code.
+ // state set to `std::nullopt` at this point) to also analyze dead code.
- if (PostVisitStmt) {
+ if (PostVisitCFG) {
for (const CFGBlock *Block : CFCtx.getCFG()) {
// Skip blocks that were not evaluated.
if (!BlockStates[Block->getBlockID()])
continue;
- transferBlock(
- CFCtx, BlockStates, *Block, InitEnv, Analysis,
- [&PostVisitStmt](const clang::CFGStmt &Stmt,
- const TypeErasedDataflowAnalysisState &State) {
- PostVisitStmt(Stmt.getStmt(), State);
- });
+ transferCFGBlock(*Block, AC, PostVisitCFG);
}
}
diff --git a/clang/lib/Analysis/FlowSensitive/Value.cpp b/clang/lib/Analysis/FlowSensitive/Value.cpp
new file mode 100644
index 000000000000..59affa80bdce
--- /dev/null
+++ b/clang/lib/Analysis/FlowSensitive/Value.cpp
@@ -0,0 +1,56 @@
+//===-- Value.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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines support functions for the `Value` type.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/FlowSensitive/Value.h"
+#include "clang/Analysis/FlowSensitive/DebugSupport.h"
+#include "llvm/Support/Casting.h"
+
+namespace clang {
+namespace dataflow {
+
+static bool areEquivalentIndirectionValues(const Value &Val1,
+ const Value &Val2) {
+ if (auto *IndVal1 = dyn_cast<ReferenceValue>(&Val1)) {
+ auto *IndVal2 = cast<ReferenceValue>(&Val2);
+ return &IndVal1->getReferentLoc() == &IndVal2->getReferentLoc();
+ }
+ if (auto *IndVal1 = dyn_cast<PointerValue>(&Val1)) {
+ auto *IndVal2 = cast<PointerValue>(&Val2);
+ return &IndVal1->getPointeeLoc() == &IndVal2->getPointeeLoc();
+ }
+ return false;
+}
+
+bool areEquivalentValues(const Value &Val1, const Value &Val2) {
+ return &Val1 == &Val2 || (Val1.getKind() == Val2.getKind() &&
+ (isa<TopBoolValue>(&Val1) ||
+ areEquivalentIndirectionValues(Val1, Val2)));
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const Value &Val) {
+ switch (Val.getKind()) {
+ case Value::Kind::Reference: {
+ const auto *RV = cast<ReferenceValue>(&Val);
+ return OS << "Reference(" << &RV->getReferentLoc() << ")";
+ }
+ case Value::Kind::Pointer: {
+ const auto *PV = dyn_cast<PointerValue>(&Val);
+ return OS << "Pointer(" << &PV->getPointeeLoc() << ")";
+ }
+ // FIXME: support remaining cases.
+ default:
+ return OS << debugString(Val.getKind());
+ }
+}
+
+} // namespace dataflow
+} // namespace clang
diff --git a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
index cd1fd708a43a..caa1ed266c5f 100644
--- a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
+++ b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp
@@ -233,6 +233,11 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
UnprocessedSubVals.push(&B->getRightSubValue());
break;
}
+ case Value::Kind::TopBool:
+ // Nothing more to do. This `TopBool` instance has already been mapped
+ // to a fresh solver variable (`NextVar`, above) and is thereafter
+ // anonymous. The solver never sees `Top`.
+ break;
case Value::Kind::AtomicBool: {
Atomics[Var] = cast<AtomicBoolValue>(Val);
break;
diff --git a/clang/lib/Analysis/IssueHash.cpp b/clang/lib/Analysis/IssueHash.cpp
index 94816747668d..4d56e774b76a 100644
--- a/clang/lib/Analysis/IssueHash.cpp
+++ b/clang/lib/Analysis/IssueHash.cpp
@@ -21,6 +21,7 @@
#include "llvm/Support/Path.h"
#include <functional>
+#include <optional>
#include <sstream>
#include <string>
@@ -121,7 +122,7 @@ static std::string GetEnclosingDeclContextSignature(const Decl *D) {
return "";
}
-static StringRef GetNthLineOfFile(llvm::Optional<llvm::MemoryBufferRef> Buffer,
+static StringRef GetNthLineOfFile(std::optional<llvm::MemoryBufferRef> Buffer,
int Line) {
if (!Buffer)
return "";
@@ -146,7 +147,7 @@ static std::string NormalizeLine(const SourceManager &SM, const FullSourceLoc &L
col++;
SourceLocation StartOfLine =
SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
- Optional<llvm::MemoryBufferRef> Buffer =
+ std::optional<llvm::MemoryBufferRef> Buffer =
SM.getBufferOrNone(SM.getFileID(StartOfLine), StartOfLine);
if (!Buffer)
return {};
diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp
index ff7f3ebe28f8..6d03dd05ca3d 100644
--- a/clang/lib/Analysis/LiveVariables.cpp
+++ b/clang/lib/Analysis/LiveVariables.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <optional>
#include <vector>
using namespace clang;
@@ -490,7 +491,7 @@ LiveVariablesImpl::runOnBlock(const CFGBlock *block,
ei = block->rend(); it != ei; ++it) {
const CFGElement &elem = *it;
- if (Optional<CFGAutomaticObjDtor> Dtor =
+ if (std::optional<CFGAutomaticObjDtor> Dtor =
elem.getAs<CFGAutomaticObjDtor>()) {
val.liveDecls = DSetFact.add(val.liveDecls, Dtor->getVarDecl());
continue;
diff --git a/clang/lib/Analysis/MacroExpansionContext.cpp b/clang/lib/Analysis/MacroExpansionContext.cpp
index 290510691891..564e359668a5 100644
--- a/clang/lib/Analysis/MacroExpansionContext.cpp
+++ b/clang/lib/Analysis/MacroExpansionContext.cpp
@@ -8,6 +8,7 @@
#include "clang/Analysis/MacroExpansionContext.h"
#include "llvm/Support/Debug.h"
+#include <optional>
#define DEBUG_TYPE "macro-expansion-context"
@@ -96,14 +97,14 @@ void MacroExpansionContext::registerForPreprocessor(Preprocessor &NewPP) {
PP->setTokenWatcher([this](const Token &Tok) { onTokenLexed(Tok); });
}
-Optional<StringRef>
+std::optional<StringRef>
MacroExpansionContext::getExpandedText(SourceLocation MacroExpansionLoc) const {
if (MacroExpansionLoc.isMacroID())
- return llvm::None;
+ return std::nullopt;
- // If there was no macro expansion at that location, return None.
+ // If there was no macro expansion at that location, return std::nullopt.
if (ExpansionRanges.find_as(MacroExpansionLoc) == ExpansionRanges.end())
- return llvm::None;
+ return std::nullopt;
// There was macro expansion, but resulted in no tokens, return empty string.
const auto It = ExpandedTokens.find_as(MacroExpansionLoc);
@@ -114,14 +115,14 @@ MacroExpansionContext::getExpandedText(SourceLocation MacroExpansionLoc) const {
return It->getSecond().str();
}
-Optional<StringRef>
+std::optional<StringRef>
MacroExpansionContext::getOriginalText(SourceLocation MacroExpansionLoc) const {
if (MacroExpansionLoc.isMacroID())
- return llvm::None;
+ return std::nullopt;
const auto It = ExpansionRanges.find_as(MacroExpansionLoc);
if (It == ExpansionRanges.end())
- return llvm::None;
+ return std::nullopt;
assert(It->getFirst() != It->getSecond() &&
"Every macro expansion must cover a non-empty range.");
diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp
index bb5f116d6940..ac1306fd8071 100644
--- a/clang/lib/Analysis/PathDiagnostic.cpp
+++ b/clang/lib/Analysis/PathDiagnostic.cpp
@@ -32,8 +32,6 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -45,6 +43,7 @@
#include <cassert>
#include <cstring>
#include <memory>
+#include <optional>
#include <utility>
#include <vector>
@@ -226,9 +225,10 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
Diags.InsertNode(D.release());
}
-static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
+static std::optional<bool> comparePath(const PathPieces &X,
+ const PathPieces &Y);
-static Optional<bool>
+static std::optional<bool>
compareControlFlow(const PathDiagnosticControlFlowPiece &X,
const PathDiagnosticControlFlowPiece &Y) {
FullSourceLoc XSL = X.getStartLocation().asLocation();
@@ -239,16 +239,16 @@ compareControlFlow(const PathDiagnosticControlFlowPiece &X,
FullSourceLoc YEL = Y.getEndLocation().asLocation();
if (XEL != YEL)
return XEL.isBeforeInTranslationUnitThan(YEL);
- return None;
+ return std::nullopt;
}
-static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
- const PathDiagnosticMacroPiece &Y) {
+static std::optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
+ const PathDiagnosticMacroPiece &Y) {
return comparePath(X.subPieces, Y.subPieces);
}
-static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
- const PathDiagnosticCallPiece &Y) {
+static std::optional<bool> compareCall(const PathDiagnosticCallPiece &X,
+ const PathDiagnosticCallPiece &Y) {
FullSourceLoc X_CEL = X.callEnter.asLocation();
FullSourceLoc Y_CEL = Y.callEnter.asLocation();
if (X_CEL != Y_CEL)
@@ -264,8 +264,8 @@ static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
return comparePath(X.path, Y.path);
}
-static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
- const PathDiagnosticPiece &Y) {
+static std::optional<bool> comparePiece(const PathDiagnosticPiece &X,
+ const PathDiagnosticPiece &Y) {
if (X.getKind() != Y.getKind())
return X.getKind() < Y.getKind();
@@ -305,25 +305,24 @@ static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
case PathDiagnosticPiece::Event:
case PathDiagnosticPiece::Note:
case PathDiagnosticPiece::PopUp:
- return None;
+ return std::nullopt;
}
llvm_unreachable("all cases handled");
}
-static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
+static std::optional<bool> comparePath(const PathPieces &X,
+ const PathPieces &Y) {
if (X.size() != Y.size())
return X.size() < Y.size();
PathPieces::const_iterator X_I = X.begin(), X_end = X.end();
PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end();
- for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
- Optional<bool> b = comparePiece(**X_I, **Y_I);
- if (b)
- return b.value();
- }
+ for (; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I)
+ if (std::optional<bool> b = comparePiece(**X_I, **Y_I))
+ return *b;
- return None;
+ return std::nullopt;
}
static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) {
@@ -343,7 +342,7 @@ static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) {
return XFE && !YFE;
int NameCmp = XFE->getName().compare(YFE->getName());
if (NameCmp != 0)
- return NameCmp == -1;
+ return NameCmp < 0;
// Last resort: Compare raw file IDs that are possibly expansions.
return XL.getFileID() < YL.getFileID();
}
@@ -365,9 +364,10 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
return X.getVerboseDescription() < Y.getVerboseDescription();
if (X.getShortDescription() != Y.getShortDescription())
return X.getShortDescription() < Y.getShortDescription();
- auto CompareDecls = [&XL](const Decl *D1, const Decl *D2) -> Optional<bool> {
+ auto CompareDecls = [&XL](const Decl *D1,
+ const Decl *D2) -> std::optional<bool> {
if (D1 == D2)
- return None;
+ return std::nullopt;
if (!D1)
return true;
if (!D2)
@@ -379,7 +379,7 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
return compareCrossTUSourceLocs(FullSourceLoc(D1L, SM),
FullSourceLoc(D2L, SM));
}
- return None;
+ return std::nullopt;
};
if (auto Result = CompareDecls(X.getDeclWithIssue(), Y.getDeclWithIssue()))
return *Result;
@@ -395,9 +395,7 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
if (*XI != *YI)
return (*XI) < (*YI);
}
- Optional<bool> b = comparePath(X.path, Y.path);
- assert(b);
- return b.value();
+ return *comparePath(X.path, Y.path);
}
void PathDiagnosticConsumer::FlushDiagnostics(
@@ -665,7 +663,7 @@ PathDiagnosticLocation
PathDiagnosticLocation::create(const ProgramPoint& P,
const SourceManager &SMng) {
const Stmt* S = nullptr;
- if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
+ if (std::optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
const CFGBlock *BSrc = BE->getSrc();
if (BSrc->getTerminator().isVirtualBaseBranch()) {
// TODO: VirtualBaseBranches should also appear for destructors.
@@ -685,22 +683,23 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
P.getLocationContext()->getDecl(), SMng);
}
}
- } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
+ } else if (std::optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
S = SP->getStmt();
if (P.getAs<PostStmtPurgeDeadSymbols>())
return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
- } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
+ } else if (std::optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
SMng);
- } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) {
+ } else if (std::optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) {
return PathDiagnosticLocation(PIC->getLocation(), SMng);
- } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
+ } else if (std::optional<PostImplicitCall> PIE =
+ P.getAs<PostImplicitCall>()) {
return PathDiagnosticLocation(PIE->getLocation(), SMng);
- } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
+ } else if (std::optional<CallEnter> CE = P.getAs<CallEnter>()) {
return getLocationForCaller(CE->getCalleeContext(),
CE->getLocationContext(),
SMng);
- } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
+ } else if (std::optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
return getLocationForCaller(CEE->getCalleeContext(),
CEE->getLocationContext(),
SMng);
@@ -710,8 +709,8 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
CEB->getLocationContext());
return PathDiagnosticLocation(
CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);
- } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
- if (Optional<CFGElement> BlockFront = BE->getFirstElement()) {
+ } else if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
+ if (std::optional<CFGElement> BlockFront = BE->getFirstElement()) {
if (auto StmtElt = BlockFront->getAs<CFGStmt>()) {
return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
} else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) {
@@ -723,7 +722,8 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
return PathDiagnosticLocation(
BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng);
- } else if (Optional<FunctionExitPoint> FE = P.getAs<FunctionExitPoint>()) {
+ } else if (std::optional<FunctionExitPoint> FE =
+ P.getAs<FunctionExitPoint>()) {
return PathDiagnosticLocation(FE->getStmt(), SMng,
FE->getLocationContext());
} else {
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp
index 1b7d774aeb40..5cc63bb17b09 100644
--- a/clang/lib/Analysis/ReachableCode.cpp
+++ b/clang/lib/Analysis/ReachableCode.cpp
@@ -24,6 +24,7 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
@@ -73,7 +74,7 @@ static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S,
// (e.g. a CFGBlock containing only a goto).
return false;
}
- if (Optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) {
if (const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) {
return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(C);
}
@@ -88,7 +89,7 @@ static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
const CFGBlock *Current = B;
while (true) {
for (const CFGElement &CE : llvm::reverse(*Current)) {
- if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
if (RS == S)
return true;
@@ -218,7 +219,7 @@ static bool isConfigurationValue(const Stmt *S,
return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
case Stmt::ObjCBoolLiteralExprClass:
IgnoreYES_NO = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Stmt::CXXBoolLiteralExprClass:
case Stmt::IntegerLiteralClass: {
const Expr *E = cast<Expr>(S);
@@ -299,6 +300,12 @@ static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
if (isa<BinaryOperator>(Term)) {
return isConfigurationValue(Term, PP);
}
+ // Do not treat constexpr if statement successors as unreachable in warnings
+ // since the point of these statements is to determine branches at compile
+ // time.
+ if (const auto *IS = dyn_cast<IfStmt>(Term);
+ IS != nullptr && IS->isConstexpr())
+ return true;
}
const Stmt *Cond = B->getTerminatorCondition(/* stripParens */ false);
@@ -333,7 +340,7 @@ static unsigned scanFromBlock(const CFGBlock *Start,
// This allows us to potentially uncover some "always unreachable" code
// within the "sometimes unreachable" code.
// Look at the successors and mark then reachable.
- Optional<bool> TreatAllSuccessorsAsReachable;
+ std::optional<bool> TreatAllSuccessorsAsReachable;
if (!IncludeSometimesUnreachableEdges)
TreatAllSuccessorsAsReachable = false;
@@ -455,7 +462,7 @@ static bool isValidDeadStmt(const Stmt *S) {
const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
- if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
if (isValidDeadStmt(S))
return S;
diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp
index 9098cf370d4f..468e94b23c3a 100644
--- a/clang/lib/Analysis/RetainSummaryManager.cpp
+++ b/clang/lib/Analysis/RetainSummaryManager.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -32,7 +33,7 @@ constexpr static bool isOneOf() {
/// rest of varargs.
template <class T, class P, class... ToCompare>
constexpr static bool isOneOf() {
- return std::is_same<T, P>::value || isOneOf<T, ToCompare...>();
+ return std::is_same_v<T, P> || isOneOf<T, ToCompare...>();
}
namespace {
@@ -65,13 +66,13 @@ struct GeneralizedConsumedAttr {
}
template <class T>
-Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
- QualType QT) {
+std::optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
+ QualType QT) {
ObjKind K;
if (isOneOf<T, CFConsumedAttr, CFReturnsRetainedAttr,
CFReturnsNotRetainedAttr>()) {
if (!TrackObjCAndCFObjects)
- return None;
+ return std::nullopt;
K = ObjKind::CF;
} else if (isOneOf<T, NSConsumedAttr, NSConsumesSelfAttr,
@@ -79,19 +80,19 @@ Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
NSReturnsNotRetainedAttr, NSConsumesSelfAttr>()) {
if (!TrackObjCAndCFObjects)
- return None;
+ return std::nullopt;
if (isOneOf<T, NSReturnsRetainedAttr, NSReturnsAutoreleasedAttr,
NSReturnsNotRetainedAttr>() &&
!cocoa::isCocoaObjectRef(QT))
- return None;
+ return std::nullopt;
K = ObjKind::ObjC;
} else if (isOneOf<T, OSConsumedAttr, OSConsumesThisAttr,
OSReturnsNotRetainedAttr, OSReturnsRetainedAttr,
OSReturnsRetainedOnZeroAttr,
OSReturnsRetainedOnNonZeroAttr>()) {
if (!TrackOSObjects)
- return None;
+ return std::nullopt;
K = ObjKind::OS;
} else if (isOneOf<T, GeneralizedReturnsNotRetainedAttr,
GeneralizedReturnsRetainedAttr,
@@ -102,12 +103,12 @@ Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
}
if (D->hasAttr<T>())
return K;
- return None;
+ return std::nullopt;
}
template <class T1, class T2, class... Others>
-Optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
- QualType QT) {
+std::optional<ObjKind> RetainSummaryManager::hasAnyEnabledAttrOf(const Decl *D,
+ QualType QT) {
if (auto Out = hasAnyEnabledAttrOf<T1>(D, QT))
return Out;
return hasAnyEnabledAttrOf<T2, Others...>(D, QT);
@@ -718,13 +719,13 @@ bool RetainSummaryManager::isTrustedReferenceCountImplementation(
return hasRCAnnotation(FD, "rc_ownership_trusted_implementation");
}
-Optional<RetainSummaryManager::BehaviorSummary>
+std::optional<RetainSummaryManager::BehaviorSummary>
RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
bool &hasTrustedImplementationAnnotation) {
IdentifierInfo *II = FD->getIdentifier();
if (!II)
- return None;
+ return std::nullopt;
StringRef FName = II->getName();
FName = FName.substr(FName.find_first_not_of('_'));
@@ -741,7 +742,7 @@ RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
FName == "CMBufferQueueDequeueIfDataReadyAndRetain") {
// Part of: <rdar://problem/39390714>.
// These are not retain. They just return something and retain it.
- return None;
+ return std::nullopt;
}
if (CE->getNumArgs() == 1 &&
(cocoa::isRefType(ResultTy, "CF", FName) ||
@@ -781,7 +782,7 @@ RetainSummaryManager::canEval(const CallExpr *CE, const FunctionDecl *FD,
return BehaviorSummary::NoOp;
}
- return None;
+ return std::nullopt;
}
const RetainSummary *
@@ -864,7 +865,7 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
-Optional<RetEffect>
+std::optional<RetEffect>
RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
const Decl *D) {
if (hasAnyEnabledAttrOf<NSReturnsRetainedAttr>(D, RetTy))
@@ -885,14 +886,14 @@ RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
if (auto RE = getRetEffectFromAnnotations(RetTy, PD))
return RE;
- return None;
+ return std::nullopt;
}
/// \return Whether the chain of typedefs starting from @c QT
/// has a typedef with a given name @c Name.
static bool hasTypedefNamed(QualType QT,
StringRef Name) {
- while (auto *T = dyn_cast<TypedefType>(QT)) {
+ while (auto *T = QT->getAs<TypedefType>()) {
const auto &Context = T->getDecl()->getASTContext();
if (T->getDecl()->getIdentifier() == &Context.Idents.get(Name))
return true;
@@ -990,7 +991,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
applyParamAnnotationEffect(*pi, parm_idx, FD, Template);
QualType RetTy = FD->getReturnType();
- if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
+ if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
Template->setRetEffect(*RetE);
if (hasAnyEnabledAttrOf<OSConsumesThisAttr>(FD, RetTy))
@@ -1017,7 +1018,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
applyParamAnnotationEffect(*pi, parm_idx, MD, Template);
QualType RetTy = MD->getReturnType();
- if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
+ if (std::optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
Template->setRetEffect(*RetE);
}
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp
index 32d950864ce7..899c6018895e 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -40,7 +40,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -53,6 +52,7 @@
#include <functional>
#include <iterator>
#include <memory>
+#include <optional>
#include <string>
#include <type_traits>
#include <utility>
@@ -820,7 +820,7 @@ static void findBlockLocations(CFG *CFGraph,
for (CFGBlock::const_reverse_iterator BI = CurrBlock->rbegin(),
BE = CurrBlock->rend(); BI != BE; ++BI) {
// FIXME: Handle other CFGElement kinds.
- if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> CS = BI->getAs<CFGStmt>()) {
CurrBlockInfo->ExitLoc = CS->getStmt()->getBeginLoc();
break;
}
@@ -832,7 +832,7 @@ static void findBlockLocations(CFG *CFGraph,
// of the first statement in the block.
for (const auto &BI : *CurrBlock) {
// FIXME: Handle other CFGElement kinds.
- if (Optional<CFGStmt> CS = BI.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> CS = BI.getAs<CFGStmt>()) {
CurrBlockInfo->EntryLoc = CS->getStmt()->getBeginLoc();
break;
}
@@ -1029,7 +1029,7 @@ public:
template <typename AttrType>
void getMutexIDs(CapExprSet &Mtxs, AttrType *Attr, const Expr *Exp,
- const NamedDecl *D, VarDecl *SelfDecl = nullptr);
+ const NamedDecl *D, til::SExpr *Self = nullptr);
template <class AttrType>
void getMutexIDs(CapExprSet &Mtxs, AttrType *Attr, const Expr *Exp,
@@ -1220,7 +1220,7 @@ bool ThreadSafetyAnalyzer::inCurrentScope(const CapabilityExpr &CapE) {
if (const auto *LP = dyn_cast<til::LiteralPtr>(SExp)) {
const ValueDecl *VD = LP->clangDecl();
// Variables defined in a function are always inaccessible.
- if (!VD->isDefinedOutsideFunctionOrMethod())
+ if (!VD || !VD->isDefinedOutsideFunctionOrMethod())
return false;
// For now we consider static class members to be inaccessible.
if (isa<CXXRecordDecl>(VD->getDeclContext()))
@@ -1311,10 +1311,10 @@ void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, const CapabilityExpr &Cp,
template <typename AttrType>
void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr,
const Expr *Exp, const NamedDecl *D,
- VarDecl *SelfDecl) {
+ til::SExpr *Self) {
if (Attr->args_size() == 0) {
// The mutex held is the "this" object.
- CapabilityExpr Cp = SxBuilder.translateAttrExpr(nullptr, D, Exp, SelfDecl);
+ CapabilityExpr Cp = SxBuilder.translateAttrExpr(nullptr, D, Exp, Self);
if (Cp.isInvalid()) {
warnInvalidLock(Handler, nullptr, D, Exp, Cp.getKind());
return;
@@ -1326,7 +1326,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr,
}
for (const auto *Arg : Attr->args()) {
- CapabilityExpr Cp = SxBuilder.translateAttrExpr(Arg, D, Exp, SelfDecl);
+ CapabilityExpr Cp = SxBuilder.translateAttrExpr(Arg, D, Exp, Self);
if (Cp.isInvalid()) {
warnInvalidLock(Handler, nullptr, D, Exp, Cp.getKind());
continue;
@@ -1529,21 +1529,26 @@ class BuildLockset : public ConstStmtVisitor<BuildLockset> {
ThreadSafetyAnalyzer *Analyzer;
FactSet FSet;
+ /// Maps constructed objects to `this` placeholder prior to initialization.
+ llvm::SmallDenseMap<const Expr *, til::LiteralPtr *> ConstructedObjects;
LocalVariableMap::Context LVarCtx;
unsigned CtxIndex;
// helper functions
void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK,
- SourceLocation Loc);
- void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp);
+ til::LiteralPtr *Self, SourceLocation Loc);
+ void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp,
+ til::LiteralPtr *Self, SourceLocation Loc);
void checkAccess(const Expr *Exp, AccessKind AK,
ProtectedOperationKind POK = POK_VarAccess);
void checkPtAccess(const Expr *Exp, AccessKind AK,
ProtectedOperationKind POK = POK_VarAccess);
- void handleCall(const Expr *Exp, const NamedDecl *D, VarDecl *VD = nullptr);
+ void handleCall(const Expr *Exp, const NamedDecl *D,
+ til::LiteralPtr *Self = nullptr,
+ SourceLocation Loc = SourceLocation());
void examineArguments(const FunctionDecl *FD,
CallExpr::const_arg_iterator ArgBegin,
CallExpr::const_arg_iterator ArgEnd,
@@ -1560,6 +1565,7 @@ public:
void VisitCallExpr(const CallExpr *Exp);
void VisitCXXConstructExpr(const CXXConstructExpr *Exp);
void VisitDeclStmt(const DeclStmt *S);
+ void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Exp);
};
} // namespace
@@ -1569,10 +1575,12 @@ public:
void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
AccessKind AK, Expr *MutexExp,
ProtectedOperationKind POK,
+ til::LiteralPtr *Self,
SourceLocation Loc) {
LockKind LK = getLockKindFromAccessKind(AK);
- CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
+ CapabilityExpr Cp =
+ Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp, Self);
if (Cp.isInvalid()) {
warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, Cp.getKind());
return;
@@ -1629,8 +1637,10 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
/// Warn if the LSet contains the given lock.
void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr *Exp,
- Expr *MutexExp) {
- CapabilityExpr Cp = Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp);
+ Expr *MutexExp, til::LiteralPtr *Self,
+ SourceLocation Loc) {
+ CapabilityExpr Cp =
+ Analyzer->SxBuilder.translateAttrExpr(MutexExp, D, Exp, Self);
if (Cp.isInvalid()) {
warnInvalidLock(Analyzer->Handler, MutexExp, D, Exp, Cp.getKind());
return;
@@ -1641,7 +1651,7 @@ void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr *Exp,
const FactEntry *LDat = FSet.findLock(Analyzer->FactMan, Cp);
if (LDat) {
Analyzer->Handler.handleFunExcludesLock(Cp.getKind(), D->getNameAsString(),
- Cp.toString(), Exp->getExprLoc());
+ Cp.toString(), Loc);
}
}
@@ -1711,7 +1721,7 @@ void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK,
}
for (const auto *I : D->specific_attrs<GuardedByAttr>())
- warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK, Loc);
+ warnIfMutexNotHeld(D, Exp, AK, I->getArg(), POK, nullptr, Loc);
}
/// Checks pt_guarded_by and pt_guarded_var attributes.
@@ -1748,7 +1758,8 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK,
Analyzer->Handler.handleNoMutexHeld(D, PtPOK, AK, Exp->getExprLoc());
for (auto const *I : D->specific_attrs<PtGuardedByAttr>())
- warnIfMutexNotHeld(D, Exp, AK, I->getArg(), PtPOK, Exp->getExprLoc());
+ warnIfMutexNotHeld(D, Exp, AK, I->getArg(), PtPOK, nullptr,
+ Exp->getExprLoc());
}
/// Process a function call, method call, constructor call,
@@ -1761,21 +1772,35 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK,
/// and check that the appropriate locks are held. Non-const method calls with
/// the same signature as const method calls can be also treated as reads.
///
+/// \param Exp The call expression.
+/// \param D The callee declaration.
+/// \param Self If \p Exp = nullptr, the implicit this argument.
+/// \param Loc If \p Exp = nullptr, the location.
void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
- VarDecl *VD) {
- SourceLocation Loc = Exp->getExprLoc();
+ til::LiteralPtr *Self, SourceLocation Loc) {
CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd;
CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove;
CapExprSet ScopedReqsAndExcludes;
// Figure out if we're constructing an object of scoped lockable class
- bool isScopedVar = false;
- if (VD) {
- if (const auto *CD = dyn_cast<const CXXConstructorDecl>(D)) {
- const CXXRecordDecl* PD = CD->getParent();
- if (PD && PD->hasAttr<ScopedLockableAttr>())
- isScopedVar = true;
+ CapabilityExpr Scp;
+ if (Exp) {
+ assert(!Self);
+ const auto *TagT = Exp->getType()->getAs<TagType>();
+ if (TagT && Exp->isPRValue()) {
+ std::pair<til::LiteralPtr *, StringRef> Placeholder =
+ Analyzer->SxBuilder.createThisPlaceholder(Exp);
+ [[maybe_unused]] auto inserted =
+ ConstructedObjects.insert({Exp, Placeholder.first});
+ assert(inserted.second && "Are we visiting the same expression again?");
+ if (isa<CXXConstructExpr>(Exp))
+ Self = Placeholder.first;
+ if (TagT->getDecl()->hasAttr<ScopedLockableAttr>())
+ Scp = CapabilityExpr(Placeholder.first, Placeholder.second, false);
}
+
+ assert(Loc.isInvalid());
+ Loc = Exp->getExprLoc();
}
for(const Attr *At : D->attrs()) {
@@ -1786,7 +1811,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
const auto *A = cast<AcquireCapabilityAttr>(At);
Analyzer->getMutexIDs(A->isShared() ? SharedLocksToAdd
: ExclusiveLocksToAdd,
- A, Exp, D, VD);
+ A, Exp, D, Self);
break;
}
@@ -1797,7 +1822,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
const auto *A = cast<AssertExclusiveLockAttr>(At);
CapExprSet AssertLocks;
- Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
+ Analyzer->getMutexIDs(AssertLocks, A, Exp, D, Self);
for (const auto &AssertLock : AssertLocks)
Analyzer->addLock(
FSet, std::make_unique<LockableFactEntry>(
@@ -1808,7 +1833,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
const auto *A = cast<AssertSharedLockAttr>(At);
CapExprSet AssertLocks;
- Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
+ Analyzer->getMutexIDs(AssertLocks, A, Exp, D, Self);
for (const auto &AssertLock : AssertLocks)
Analyzer->addLock(
FSet, std::make_unique<LockableFactEntry>(
@@ -1819,7 +1844,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
case attr::AssertCapability: {
const auto *A = cast<AssertCapabilityAttr>(At);
CapExprSet AssertLocks;
- Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
+ Analyzer->getMutexIDs(AssertLocks, A, Exp, D, Self);
for (const auto &AssertLock : AssertLocks)
Analyzer->addLock(FSet, std::make_unique<LockableFactEntry>(
AssertLock,
@@ -1833,11 +1858,11 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
case attr::ReleaseCapability: {
const auto *A = cast<ReleaseCapabilityAttr>(At);
if (A->isGeneric())
- Analyzer->getMutexIDs(GenericLocksToRemove, A, Exp, D, VD);
+ Analyzer->getMutexIDs(GenericLocksToRemove, A, Exp, D, Self);
else if (A->isShared())
- Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, VD);
+ Analyzer->getMutexIDs(SharedLocksToRemove, A, Exp, D, Self);
else
- Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, VD);
+ Analyzer->getMutexIDs(ExclusiveLocksToRemove, A, Exp, D, Self);
break;
}
@@ -1845,10 +1870,10 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
const auto *A = cast<RequiresCapabilityAttr>(At);
for (auto *Arg : A->args()) {
warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, Arg,
- POK_FunctionCall, Exp->getExprLoc());
+ POK_FunctionCall, Self, Loc);
// use for adopting a lock
- if (isScopedVar)
- Analyzer->getMutexIDs(ScopedReqsAndExcludes, A, Exp, D, VD);
+ if (!Scp.shouldIgnore())
+ Analyzer->getMutexIDs(ScopedReqsAndExcludes, A, Exp, D, Self);
}
break;
}
@@ -1856,10 +1881,10 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
case attr::LocksExcluded: {
const auto *A = cast<LocksExcludedAttr>(At);
for (auto *Arg : A->args()) {
- warnIfMutexHeld(D, Exp, Arg);
+ warnIfMutexHeld(D, Exp, Arg, Self, Loc);
// use for deferring a lock
- if (isScopedVar)
- Analyzer->getMutexIDs(ScopedReqsAndExcludes, A, Exp, D, VD);
+ if (!Scp.shouldIgnore())
+ Analyzer->getMutexIDs(ScopedReqsAndExcludes, A, Exp, D, Self);
}
break;
}
@@ -1882,7 +1907,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
// Add locks.
FactEntry::SourceKind Source =
- isScopedVar ? FactEntry::Managed : FactEntry::Acquired;
+ !Scp.shouldIgnore() ? FactEntry::Managed : FactEntry::Acquired;
for (const auto &M : ExclusiveLocksToAdd)
Analyzer->addLock(FSet, std::make_unique<LockableFactEntry>(M, LK_Exclusive,
Loc, Source));
@@ -1890,15 +1915,9 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
Analyzer->addLock(
FSet, std::make_unique<LockableFactEntry>(M, LK_Shared, Loc, Source));
- if (isScopedVar) {
+ if (!Scp.shouldIgnore()) {
// Add the managing object as a dummy mutex, mapped to the underlying mutex.
- SourceLocation MLoc = VD->getLocation();
- DeclRefExpr DRE(VD->getASTContext(), VD, false, VD->getType(), VK_LValue,
- VD->getLocation());
- // FIXME: does this store a pointer to DRE?
- CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE, nullptr);
-
- auto ScopedEntry = std::make_unique<ScopedLockableFactEntry>(Scp, MLoc);
+ auto ScopedEntry = std::make_unique<ScopedLockableFactEntry>(Scp, Loc);
for (const auto &M : ExclusiveLocksToAdd)
ScopedEntry->addLock(M);
for (const auto &M : SharedLocksToAdd)
@@ -2013,7 +2032,7 @@ void BuildLockset::VisitCallExpr(const CallExpr *Exp) {
case OO_LessLessEqual:
case OO_GreaterGreaterEqual:
checkAccess(OE->getArg(1), AK_Read);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OO_PlusPlus:
case OO_MinusMinus:
checkAccess(OE->getArg(0), AK_Written);
@@ -2026,7 +2045,7 @@ void BuildLockset::VisitCallExpr(const CallExpr *Exp) {
// Grrr. operator* can be multiplication...
checkPtAccess(OE->getArg(0), AK_Read);
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default: {
// TODO: get rid of this, and rely on pass-by-ref instead.
const Expr *Obj = OE->getArg(0);
@@ -2058,33 +2077,21 @@ void BuildLockset::VisitCXXConstructExpr(const CXXConstructExpr *Exp) {
} else {
examineArguments(D, Exp->arg_begin(), Exp->arg_end());
}
+ if (D && D->hasAttrs())
+ handleCall(Exp, D);
}
-static CXXConstructorDecl *
-findConstructorForByValueReturn(const CXXRecordDecl *RD) {
- // Prefer a move constructor over a copy constructor. If there's more than
- // one copy constructor or more than one move constructor, we arbitrarily
- // pick the first declared such constructor rather than trying to guess which
- // one is more appropriate.
- CXXConstructorDecl *CopyCtor = nullptr;
- for (auto *Ctor : RD->ctors()) {
- if (Ctor->isDeleted())
- continue;
- if (Ctor->isMoveConstructor())
- return Ctor;
- if (!CopyCtor && Ctor->isCopyConstructor())
- CopyCtor = Ctor;
- }
- return CopyCtor;
-}
-
-static Expr *buildFakeCtorCall(CXXConstructorDecl *CD, ArrayRef<Expr *> Args,
- SourceLocation Loc) {
- ASTContext &Ctx = CD->getASTContext();
- return CXXConstructExpr::Create(Ctx, Ctx.getRecordType(CD->getParent()), Loc,
- CD, true, Args, false, false, false, false,
- CXXConstructExpr::CK_Complete,
- SourceRange(Loc, Loc));
+static const Expr *UnpackConstruction(const Expr *E) {
+ if (auto *CE = dyn_cast<CastExpr>(E))
+ if (CE->getCastKind() == CK_NoOp)
+ E = CE->getSubExpr()->IgnoreParens();
+ if (auto *CE = dyn_cast<CastExpr>(E))
+ if (CE->getCastKind() == CK_ConstructorConversion ||
+ CE->getCastKind() == CK_UserDefinedConversion)
+ E = CE->getSubExpr();
+ if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = BTE->getSubExpr();
+ return E;
}
void BuildLockset::VisitDeclStmt(const DeclStmt *S) {
@@ -2093,7 +2100,7 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) {
for (auto *D : S->getDeclGroup()) {
if (auto *VD = dyn_cast_or_null<VarDecl>(D)) {
- Expr *E = VD->getInit();
+ const Expr *E = VD->getInit();
if (!E)
continue;
E = E->IgnoreParens();
@@ -2101,37 +2108,29 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) {
// handle constructors that involve temporaries
if (auto *EWC = dyn_cast<ExprWithCleanups>(E))
E = EWC->getSubExpr()->IgnoreParens();
- if (auto *CE = dyn_cast<CastExpr>(E))
- if (CE->getCastKind() == CK_NoOp ||
- CE->getCastKind() == CK_ConstructorConversion ||
- CE->getCastKind() == CK_UserDefinedConversion)
- E = CE->getSubExpr()->IgnoreParens();
- if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E))
- E = BTE->getSubExpr()->IgnoreParens();
-
- if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
- const auto *CtorD = dyn_cast_or_null<NamedDecl>(CE->getConstructor());
- if (!CtorD || !CtorD->hasAttrs())
- continue;
- handleCall(E, CtorD, VD);
- } else if (isa<CallExpr>(E) && E->isPRValue()) {
- // If the object is initialized by a function call that returns a
- // scoped lockable by value, use the attributes on the copy or move
- // constructor to figure out what effect that should have on the
- // lockset.
- // FIXME: Is this really the best way to handle this situation?
- auto *RD = E->getType()->getAsCXXRecordDecl();
- if (!RD || !RD->hasAttr<ScopedLockableAttr>())
- continue;
- CXXConstructorDecl *CtorD = findConstructorForByValueReturn(RD);
- if (!CtorD || !CtorD->hasAttrs())
- continue;
- handleCall(buildFakeCtorCall(CtorD, {E}, E->getBeginLoc()), CtorD, VD);
+ E = UnpackConstruction(E);
+
+ if (auto Object = ConstructedObjects.find(E);
+ Object != ConstructedObjects.end()) {
+ Object->second->setClangDecl(VD);
+ ConstructedObjects.erase(Object);
}
}
}
}
+void BuildLockset::VisitMaterializeTemporaryExpr(
+ const MaterializeTemporaryExpr *Exp) {
+ if (const ValueDecl *ExtD = Exp->getExtendingDecl()) {
+ if (auto Object =
+ ConstructedObjects.find(UnpackConstruction(Exp->getSubExpr()));
+ Object != ConstructedObjects.end()) {
+ Object->second->setClangDecl(ExtD);
+ ConstructedObjects.erase(Object);
+ }
+ }
+}
+
/// Given two facts merging on a join point, possibly warn and decide whether to
/// keep or replace.
///
@@ -2217,7 +2216,7 @@ static bool neverReturns(const CFGBlock *B) {
return false;
CFGElement Last = B->back();
- if (Optional<CFGStmt> S = Last.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> S = Last.getAs<CFGStmt>()) {
if (isa<CXXThrowExpr>(S->getStmt()))
return true;
}
@@ -2404,19 +2403,33 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
LocksetBuilder.Visit(CS.getStmt());
break;
}
- // Ignore BaseDtor, MemberDtor, and TemporaryDtor for now.
+ // Ignore BaseDtor and MemberDtor for now.
case CFGElement::AutomaticObjectDtor: {
CFGAutomaticObjDtor AD = BI.castAs<CFGAutomaticObjDtor>();
const auto *DD = AD.getDestructorDecl(AC.getASTContext());
if (!DD->hasAttrs())
break;
- // Create a dummy expression,
- auto *VD = const_cast<VarDecl *>(AD.getVarDecl());
- DeclRefExpr DRE(VD->getASTContext(), VD, false,
- VD->getType().getNonReferenceType(), VK_LValue,
- AD.getTriggerStmt()->getEndLoc());
- LocksetBuilder.handleCall(&DRE, DD);
+ LocksetBuilder.handleCall(nullptr, DD,
+ SxBuilder.createVariable(AD.getVarDecl()),
+ AD.getTriggerStmt()->getEndLoc());
+ break;
+ }
+ case CFGElement::TemporaryDtor: {
+ auto TD = BI.castAs<CFGTemporaryDtor>();
+
+ // Clean up constructed object even if there are no attributes to
+ // keep the number of objects in limbo as small as possible.
+ if (auto Object = LocksetBuilder.ConstructedObjects.find(
+ TD.getBindTemporaryExpr()->getSubExpr());
+ Object != LocksetBuilder.ConstructedObjects.end()) {
+ const auto *DD = TD.getDestructorDecl(AC.getASTContext());
+ if (DD->hasAttrs())
+ // TODO: the location here isn't quite correct.
+ LocksetBuilder.handleCall(nullptr, DD, Object->second,
+ TD.getBindTemporaryExpr()->getEndLoc());
+ LocksetBuilder.ConstructedObjects.erase(Object);
+ }
break;
}
default:
diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp
index 66413f84907a..a771149f1591 100644
--- a/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -115,19 +115,22 @@ static StringRef ClassifyDiagnostic(QualType VDT) {
/// \param D The declaration to which the attribute is attached.
/// \param DeclExp An expression involving the Decl to which the attribute
/// is attached. E.g. the call to a function.
+/// \param Self S-expression to substitute for a \ref CXXThisExpr.
CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
const NamedDecl *D,
const Expr *DeclExp,
- VarDecl *SelfDecl) {
+ til::SExpr *Self) {
// If we are processing a raw attribute expression, with no substitutions.
- if (!DeclExp)
+ if (!DeclExp && !Self)
return translateAttrExpr(AttrExp, nullptr);
CallingContext Ctx(nullptr, D);
// Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
// for formal parameters when we call buildMutexID later.
- if (const auto *ME = dyn_cast<MemberExpr>(DeclExp)) {
+ if (!DeclExp)
+ /* We'll use Self. */;
+ else if (const auto *ME = dyn_cast<MemberExpr>(DeclExp)) {
Ctx.SelfArg = ME->getBase();
Ctx.SelfArrow = ME->isArrow();
} else if (const auto *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
@@ -142,29 +145,24 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
Ctx.SelfArg = nullptr; // Will be set below
Ctx.NumArgs = CE->getNumArgs();
Ctx.FunArgs = CE->getArgs();
- } else if (D && isa<CXXDestructorDecl>(D)) {
- // There's no such thing as a "destructor call" in the AST.
- Ctx.SelfArg = DeclExp;
}
- // Hack to handle constructors, where self cannot be recovered from
- // the expression.
- if (SelfDecl && !Ctx.SelfArg) {
- DeclRefExpr SelfDRE(SelfDecl->getASTContext(), SelfDecl, false,
- SelfDecl->getType(), VK_LValue,
- SelfDecl->getLocation());
- Ctx.SelfArg = &SelfDRE;
+ if (Self) {
+ assert(!Ctx.SelfArg && "Ambiguous self argument");
+ Ctx.SelfArg = Self;
// If the attribute has no arguments, then assume the argument is "this".
if (!AttrExp)
- return translateAttrExpr(Ctx.SelfArg, nullptr);
+ return CapabilityExpr(
+ Self, ClassifyDiagnostic(cast<CXXMethodDecl>(D)->getThisObjectType()),
+ false);
else // For most attributes.
return translateAttrExpr(AttrExp, &Ctx);
}
// If the attribute has no arguments, then assume the argument is "this".
if (!AttrExp)
- return translateAttrExpr(Ctx.SelfArg, nullptr);
+ return translateAttrExpr(cast<const Expr *>(Ctx.SelfArg), nullptr);
else // For most attributes.
return translateAttrExpr(AttrExp, &Ctx);
}
@@ -218,6 +216,16 @@ CapabilityExpr SExprBuilder::translateAttrExpr(const Expr *AttrExp,
return CapabilityExpr(E, Kind, Neg);
}
+til::LiteralPtr *SExprBuilder::createVariable(const VarDecl *VD) {
+ return new (Arena) til::LiteralPtr(VD);
+}
+
+std::pair<til::LiteralPtr *, StringRef>
+SExprBuilder::createThisPlaceholder(const Expr *Exp) {
+ return {new (Arena) til::LiteralPtr(nullptr),
+ ClassifyDiagnostic(Exp->getType())};
+}
+
// Translate a clang statement or expression to a TIL expression.
// Also performs substitution of variables; Ctx provides the context.
// Dispatches on the type of S.
@@ -327,8 +335,12 @@ til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
CallingContext *Ctx) {
// Substitute for 'this'
- if (Ctx && Ctx->SelfArg)
- return translate(Ctx->SelfArg, Ctx->Prev);
+ if (Ctx && Ctx->SelfArg) {
+ if (const auto *SelfArg = dyn_cast<const Expr *>(Ctx->SelfArg))
+ return translate(SelfArg, Ctx->Prev);
+ else
+ return cast<til::SExpr *>(Ctx->SelfArg);
+ }
assert(SelfVar && "We have no variable for 'this'!");
return SelfVar;
}
@@ -637,7 +649,7 @@ SExprBuilder::translateAbstractConditionalOperator(
til::SExpr *
SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
DeclGroupRef DGrp = S->getDeclGroup();
- for (auto I : DGrp) {
+ for (auto *I : DGrp) {
if (auto *VD = dyn_cast_or_null<VarDecl>(I)) {
Expr *E = VD->getInit();
til::SExpr* SE = translate(E, Ctx);
diff --git a/clang/lib/Analysis/UninitializedValues.cpp b/clang/lib/Analysis/UninitializedValues.cpp
index 7f44685355e0..2437095a22cf 100644
--- a/clang/lib/Analysis/UninitializedValues.cpp
+++ b/clang/lib/Analysis/UninitializedValues.cpp
@@ -28,14 +28,13 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PackedVector.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include <algorithm>
#include <cassert>
+#include <optional>
using namespace clang;
@@ -46,7 +45,8 @@ static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
!vd->isExceptionVariable() && !vd->isInitCapture() &&
!vd->isImplicit() && vd->getDeclContext() == dc) {
QualType ty = vd->getType();
- return ty->isScalarType() || ty->isVectorType() || ty->isRecordType();
+ return ty->isScalarType() || ty->isVectorType() || ty->isRecordType() ||
+ ty->isRVVType();
}
return false;
}
@@ -70,7 +70,7 @@ public:
unsigned size() const { return map.size(); }
/// Returns the bit vector index for a given declaration.
- Optional<unsigned> getValueIndex(const VarDecl *d) const;
+ std::optional<unsigned> getValueIndex(const VarDecl *d) const;
};
} // namespace
@@ -86,10 +86,10 @@ void DeclToIndex::computeMap(const DeclContext &dc) {
}
}
-Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
+std::optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
if (I == map.end())
- return None;
+ return std::nullopt;
return I->second;
}
@@ -147,9 +147,8 @@ public:
Value getValue(const CFGBlock *block, const CFGBlock *dstBlock,
const VarDecl *vd) {
- const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
- assert(idx);
- return getValueVector(block)[idx.value()];
+ std::optional<unsigned> idx = declToIndex.getValueIndex(vd);
+ return getValueVector(block)[*idx];
}
};
@@ -208,9 +207,7 @@ void CFGBlockValues::resetScratch() {
}
ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
- const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
- assert(idx);
- return scratch[idx.value()];
+ return scratch[*declToIndex.getValueIndex(vd)];
}
//------------------------------------------------------------------------====//
@@ -861,7 +858,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
// Apply the transfer function.
TransferFunctions tf(vals, cfg, block, ac, classification, handler);
for (const auto &I : *block) {
- if (Optional<CFGStmt> cs = I.getAs<CFGStmt>())
+ if (std::optional<CFGStmt> cs = I.getAs<CFGStmt>())
tf.Visit(const_cast<Stmt *>(cs->getStmt()));
}
CFGTerminator terminator = block->getTerminator();
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
new file mode 100644
index 000000000000..2f1417487967
--- /dev/null
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -0,0 +1,695 @@
+//===- UnsafeBufferUsage.cpp - Replace pointers with modern 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/Analysis/Analyses/UnsafeBufferUsage.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/SmallVector.h"
+#include <memory>
+#include <optional>
+
+using namespace llvm;
+using namespace clang;
+using namespace ast_matchers;
+
+namespace clang::ast_matchers {
+// A `RecursiveASTVisitor` that traverses all descendants of a given node "n"
+// except for those belonging to a different callable of "n".
+class MatchDescendantVisitor
+ : public RecursiveASTVisitor<MatchDescendantVisitor> {
+public:
+ typedef RecursiveASTVisitor<MatchDescendantVisitor> VisitorBase;
+
+ // Creates an AST visitor that matches `Matcher` on all
+ // descendants of a given node "n" except for the ones
+ // belonging to a different callable of "n".
+ MatchDescendantVisitor(const internal::DynTypedMatcher *Matcher,
+ internal::ASTMatchFinder *Finder,
+ internal::BoundNodesTreeBuilder *Builder,
+ internal::ASTMatchFinder::BindKind Bind)
+ : Matcher(Matcher), Finder(Finder), Builder(Builder), Bind(Bind),
+ Matches(false) {}
+
+ // Returns true if a match is found in a subtree of `DynNode`, which belongs
+ // to the same callable of `DynNode`.
+ bool findMatch(const DynTypedNode &DynNode) {
+ Matches = false;
+ if (const Stmt *StmtNode = DynNode.get<Stmt>()) {
+ TraverseStmt(const_cast<Stmt *>(StmtNode));
+ *Builder = ResultBindings;
+ return Matches;
+ }
+ return false;
+ }
+
+ // The following are overriding methods from the base visitor class.
+ // They are public only to allow CRTP to work. They are *not *part
+ // of the public API of this class.
+
+ // For the matchers so far used in safe buffers, we only need to match
+ // `Stmt`s. To override more as needed.
+
+ bool TraverseDecl(Decl *Node) {
+ if (!Node)
+ return true;
+ if (!match(*Node))
+ return false;
+ // To skip callables:
+ if (isa<FunctionDecl, BlockDecl, ObjCMethodDecl>(Node))
+ return true;
+ // Traverse descendants
+ return VisitorBase::TraverseDecl(Node);
+ }
+
+ bool TraverseStmt(Stmt *Node, DataRecursionQueue *Queue = nullptr) {
+ if (!Node)
+ return true;
+ if (!match(*Node))
+ return false;
+ // To skip callables:
+ if (isa<LambdaExpr>(Node))
+ return true;
+ return VisitorBase::TraverseStmt(Node);
+ }
+
+ bool shouldVisitTemplateInstantiations() const { return true; }
+ bool shouldVisitImplicitCode() const {
+ // TODO: let's ignore implicit code for now
+ return false;
+ }
+
+private:
+ // Sets 'Matched' to true if 'Matcher' matches 'Node'
+ //
+ // Returns 'true' if traversal should continue after this function
+ // returns, i.e. if no match is found or 'Bind' is 'BK_All'.
+ template <typename T> bool match(const T &Node) {
+ internal::BoundNodesTreeBuilder RecursiveBuilder(*Builder);
+
+ if (Matcher->matches(DynTypedNode::create(Node), Finder,
+ &RecursiveBuilder)) {
+ ResultBindings.addMatch(RecursiveBuilder);
+ Matches = true;
+ if (Bind != internal::ASTMatchFinder::BK_All)
+ return false; // Abort as soon as a match is found.
+ }
+ return true;
+ }
+
+ const internal::DynTypedMatcher *const Matcher;
+ internal::ASTMatchFinder *const Finder;
+ internal::BoundNodesTreeBuilder *const Builder;
+ internal::BoundNodesTreeBuilder ResultBindings;
+ const internal::ASTMatchFinder::BindKind Bind;
+ bool Matches;
+};
+
+AST_MATCHER_P(Stmt, forEveryDescendant, internal::Matcher<Stmt>, innerMatcher) {
+ const DynTypedMatcher &DTM = static_cast<DynTypedMatcher>(innerMatcher);
+
+ MatchDescendantVisitor Visitor(&DTM, Finder, Builder, ASTMatchFinder::BK_All);
+ return Visitor.findMatch(DynTypedNode::create(Node));
+}
+} // namespace clang::ast_matchers
+
+namespace {
+// Because the analysis revolves around variables and their types, we'll need to
+// track uses of variables (aka DeclRefExprs).
+using DeclUseList = SmallVector<const DeclRefExpr *, 1>;
+
+// Convenience typedef.
+using FixItList = SmallVector<FixItHint, 4>;
+
+// Defined below.
+class Strategy;
+} // namespace
+
+// Because we're dealing with raw pointers, let's define what we mean by that.
+static auto hasPointerType() {
+ return hasType(hasCanonicalType(pointerType()));
+}
+
+static auto hasArrayType() {
+ return hasType(hasCanonicalType(arrayType()));
+}
+
+namespace {
+/// Gadget is an individual operation in the code that may be of interest to
+/// this analysis. Each (non-abstract) subclass corresponds to a specific
+/// rigid AST structure that constitutes an operation on a pointer-type object.
+/// Discovery of a gadget in the code corresponds to claiming that we understand
+/// what this part of code is doing well enough to potentially improve it.
+/// Gadgets can be warning (immediately deserving a warning) or fixable (not
+/// always deserving a warning per se, but requires our attention to identify
+/// it warrants a fixit).
+class Gadget {
+public:
+ enum class Kind {
+#define GADGET(x) x,
+#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
+ };
+
+ /// Common type of ASTMatchers used for discovering gadgets.
+ /// Useful for implementing the static matcher() methods
+ /// that are expected from all non-abstract subclasses.
+ using Matcher = decltype(stmt());
+
+ Gadget(Kind K) : K(K) {}
+
+ Kind getKind() const { return K; }
+
+ virtual bool isWarningGadget() const = 0;
+ virtual const Stmt *getBaseStmt() const = 0;
+
+ /// Returns the list of pointer-type variables on which this gadget performs
+ /// its operation. Typically, there's only one variable. This isn't a list
+ /// of all DeclRefExprs in the gadget's AST!
+ virtual DeclUseList getClaimedVarUseSites() const = 0;
+
+ virtual ~Gadget() = default;
+
+private:
+ Kind K;
+};
+
+
+/// Warning gadgets correspond to unsafe code patterns that warrants
+/// an immediate warning.
+class WarningGadget : public Gadget {
+public:
+ WarningGadget(Kind K) : Gadget(K) {}
+
+ static bool classof(const Gadget *G) { return G->isWarningGadget(); }
+ bool isWarningGadget() const final { return true; }
+};
+
+/// Fixable gadgets correspond to code patterns that aren't always unsafe but need to be
+/// properly recognized in order to emit fixes. For example, if a raw pointer-type
+/// variable is replaced by a safe C++ container, every use of such variable must be
+/// carefully considered and possibly updated.
+class FixableGadget : public Gadget {
+public:
+ FixableGadget(Kind K) : Gadget(K) {}
+
+ static bool classof(const Gadget *G) { return !G->isWarningGadget(); }
+ bool isWarningGadget() const final { return false; }
+
+ /// Returns a fixit that would fix the current gadget according to
+ /// the current strategy. Returns None if the fix cannot be produced;
+ /// returns an empty list if no fixes are necessary.
+ virtual std::optional<FixItList> getFixits(const Strategy &) const {
+ return std::nullopt;
+ }
+};
+
+using FixableGadgetList = std::vector<std::unique_ptr<FixableGadget>>;
+using WarningGadgetList = std::vector<std::unique_ptr<WarningGadget>>;
+
+/// An increment of a pointer-type value is unsafe as it may run the pointer
+/// out of bounds.
+class IncrementGadget : public WarningGadget {
+ static constexpr const char *const OpTag = "op";
+ const UnaryOperator *Op;
+
+public:
+ IncrementGadget(const MatchFinder::MatchResult &Result)
+ : WarningGadget(Kind::Increment),
+ Op(Result.Nodes.getNodeAs<UnaryOperator>(OpTag)) {}
+
+ static bool classof(const Gadget *G) {
+ return G->getKind() == Kind::Increment;
+ }
+
+ static Matcher matcher() {
+ return stmt(unaryOperator(
+ hasOperatorName("++"),
+ hasUnaryOperand(ignoringParenImpCasts(hasPointerType()))
+ ).bind(OpTag));
+ }
+
+ const UnaryOperator *getBaseStmt() const override { return Op; }
+
+ DeclUseList getClaimedVarUseSites() const override {
+ SmallVector<const DeclRefExpr *, 2> Uses;
+ if (const auto *DRE =
+ dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
+ Uses.push_back(DRE);
+ }
+
+ return std::move(Uses);
+ }
+};
+
+/// A decrement of a pointer-type value is unsafe as it may run the pointer
+/// out of bounds.
+class DecrementGadget : public WarningGadget {
+ static constexpr const char *const OpTag = "op";
+ const UnaryOperator *Op;
+
+public:
+ DecrementGadget(const MatchFinder::MatchResult &Result)
+ : WarningGadget(Kind::Decrement),
+ Op(Result.Nodes.getNodeAs<UnaryOperator>(OpTag)) {}
+
+ static bool classof(const Gadget *G) {
+ return G->getKind() == Kind::Decrement;
+ }
+
+ static Matcher matcher() {
+ return stmt(unaryOperator(
+ hasOperatorName("--"),
+ hasUnaryOperand(ignoringParenImpCasts(hasPointerType()))
+ ).bind(OpTag));
+ }
+
+ const UnaryOperator *getBaseStmt() const override { return Op; }
+
+ DeclUseList getClaimedVarUseSites() const override {
+ if (const auto *DRE =
+ dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts())) {
+ return {DRE};
+ }
+
+ return {};
+ }
+};
+
+/// Array subscript expressions on raw pointers as if they're arrays. Unsafe as
+/// it doesn't have any bounds checks for the array.
+class ArraySubscriptGadget : public WarningGadget {
+ static constexpr const char *const ArraySubscrTag = "arraySubscr";
+ const ArraySubscriptExpr *ASE;
+
+public:
+ ArraySubscriptGadget(const MatchFinder::MatchResult &Result)
+ : WarningGadget(Kind::ArraySubscript),
+ ASE(Result.Nodes.getNodeAs<ArraySubscriptExpr>(ArraySubscrTag)) {}
+
+ static bool classof(const Gadget *G) {
+ return G->getKind() == Kind::ArraySubscript;
+ }
+
+ static Matcher matcher() {
+ // FIXME: What if the index is integer literal 0? Should this be
+ // a safe gadget in this case?
+ // clang-format off
+ return stmt(arraySubscriptExpr(
+ hasBase(ignoringParenImpCasts(
+ anyOf(hasPointerType(), hasArrayType()))),
+ unless(hasIndex(integerLiteral(equals(0)))))
+ .bind(ArraySubscrTag));
+ // clang-format on
+ }
+
+ const ArraySubscriptExpr *getBaseStmt() const override { return ASE; }
+
+ DeclUseList getClaimedVarUseSites() const override {
+ if (const auto *DRE =
+ dyn_cast<DeclRefExpr>(ASE->getBase()->IgnoreParenImpCasts())) {
+ return {DRE};
+ }
+
+ return {};
+ }
+};
+
+/// A pointer arithmetic expression of one of the forms:
+/// \code
+/// ptr + n | n + ptr | ptr - n | ptr += n | ptr -= n
+/// \endcode
+class PointerArithmeticGadget : public WarningGadget {
+ static constexpr const char *const PointerArithmeticTag = "ptrAdd";
+ static constexpr const char *const PointerArithmeticPointerTag = "ptrAddPtr";
+ const BinaryOperator *PA; // pointer arithmetic expression
+ const Expr * Ptr; // the pointer expression in `PA`
+
+public:
+ PointerArithmeticGadget(const MatchFinder::MatchResult &Result)
+ : WarningGadget(Kind::PointerArithmetic),
+ PA(Result.Nodes.getNodeAs<BinaryOperator>(PointerArithmeticTag)),
+ Ptr(Result.Nodes.getNodeAs<Expr>(PointerArithmeticPointerTag)) {}
+
+ static bool classof(const Gadget *G) {
+ return G->getKind() == Kind::PointerArithmetic;
+ }
+
+ static Matcher matcher() {
+ auto HasIntegerType = anyOf(
+ hasType(isInteger()), hasType(enumType()));
+ auto PtrAtRight = allOf(hasOperatorName("+"),
+ hasRHS(expr(hasPointerType()).bind(PointerArithmeticPointerTag)),
+ hasLHS(HasIntegerType));
+ auto PtrAtLeft = allOf(
+ anyOf(hasOperatorName("+"), hasOperatorName("-"),
+ hasOperatorName("+="), hasOperatorName("-=")),
+ hasLHS(expr(hasPointerType()).bind(PointerArithmeticPointerTag)),
+ hasRHS(HasIntegerType));
+
+ return stmt(binaryOperator(anyOf(PtrAtLeft, PtrAtRight)).bind(PointerArithmeticTag));
+ }
+
+ const Stmt *getBaseStmt() const override { return PA; }
+
+ DeclUseList getClaimedVarUseSites() const override {
+ if (const auto *DRE =
+ dyn_cast<DeclRefExpr>(Ptr->IgnoreParenImpCasts())) {
+ return {DRE};
+ }
+
+ return {};
+ }
+ // FIXME: pointer adding zero should be fine
+ //FIXME: this gadge will need a fix-it
+};
+} // namespace
+
+namespace {
+// An auxiliary tracking facility for the fixit analysis. It helps connect
+// declarations to its and make sure we've covered all uses with our analysis
+// before we try to fix the declaration.
+class DeclUseTracker {
+ using UseSetTy = SmallSet<const DeclRefExpr *, 16>;
+ using DefMapTy = DenseMap<const VarDecl *, const DeclStmt *>;
+
+ // Allocate on the heap for easier move.
+ std::unique_ptr<UseSetTy> Uses{std::make_unique<UseSetTy>()};
+ DefMapTy Defs{};
+
+public:
+ DeclUseTracker() = default;
+ DeclUseTracker(const DeclUseTracker &) = delete; // Let's avoid copies.
+ DeclUseTracker(DeclUseTracker &&) = default;
+ DeclUseTracker &operator=(DeclUseTracker &&) = default;
+
+ // Start tracking a freshly discovered DRE.
+ void discoverUse(const DeclRefExpr *DRE) { Uses->insert(DRE); }
+
+ // Stop tracking the DRE as it's been fully figured out.
+ void claimUse(const DeclRefExpr *DRE) {
+ assert(Uses->count(DRE) &&
+ "DRE not found or claimed by multiple matchers!");
+ Uses->erase(DRE);
+ }
+
+ // A variable is unclaimed if at least one use is unclaimed.
+ bool hasUnclaimedUses(const VarDecl *VD) const {
+ // FIXME: Can this be less linear? Maybe maintain a map from VDs to DREs?
+ return any_of(*Uses, [VD](const DeclRefExpr *DRE) {
+ return DRE->getDecl()->getCanonicalDecl() == VD->getCanonicalDecl();
+ });
+ }
+
+ void discoverDecl(const DeclStmt *DS) {
+ for (const Decl *D : DS->decls()) {
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ // FIXME: Assertion temporarily disabled due to a bug in
+ // ASTMatcher internal behavior in presence of GNU
+ // statement-expressions. We need to properly investigate this
+ // because it can screw up our algorithm in other ways.
+ // assert(Defs.count(VD) == 0 && "Definition already discovered!");
+ Defs[VD] = DS;
+ }
+ }
+ }
+
+ const DeclStmt *lookupDecl(const VarDecl *VD) const {
+ auto It = Defs.find(VD);
+ assert(It != Defs.end() && "Definition never discovered!");
+ return It->second;
+ }
+};
+} // namespace
+
+namespace {
+// Strategy is a map from variables to the way we plan to emit fixes for
+// these variables. It is figured out gradually by trying different fixes
+// for different variables depending on gadgets in which these variables
+// participate.
+class Strategy {
+public:
+ enum class Kind {
+ Wontfix, // We don't plan to emit a fixit for this variable.
+ Span, // We recommend replacing the variable with std::span.
+ Iterator, // We recommend replacing the variable with std::span::iterator.
+ Array, // We recommend replacing the variable with std::array.
+ Vector // We recommend replacing the variable with std::vector.
+ };
+
+private:
+ using MapTy = llvm::DenseMap<const VarDecl *, Kind>;
+
+ MapTy Map;
+
+public:
+ Strategy() = default;
+ Strategy(const Strategy &) = delete; // Let's avoid copies.
+ Strategy(Strategy &&) = default;
+
+ void set(const VarDecl *VD, Kind K) {
+ Map[VD] = K;
+ }
+
+ Kind lookup(const VarDecl *VD) const {
+ auto I = Map.find(VD);
+ if (I == Map.end())
+ return Kind::Wontfix;
+
+ return I->second;
+ }
+};
+} // namespace
+
+/// Scan the function and return a list of gadgets found with provided kits.
+static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker> findGadgets(const Decl *D) {
+
+ struct GadgetFinderCallback : MatchFinder::MatchCallback {
+ FixableGadgetList FixableGadgets;
+ WarningGadgetList WarningGadgets;
+ DeclUseTracker Tracker;
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ // In debug mode, assert that we've found exactly one gadget.
+ // This helps us avoid conflicts in .bind() tags.
+#if NDEBUG
+#define NEXT return
+#else
+ [[maybe_unused]] int numFound = 0;
+#define NEXT ++numFound
+#endif
+
+ if (const auto *DRE = Result.Nodes.getNodeAs<DeclRefExpr>("any_dre")) {
+ Tracker.discoverUse(DRE);
+ NEXT;
+ }
+
+ if (const auto *DS = Result.Nodes.getNodeAs<DeclStmt>("any_ds")) {
+ Tracker.discoverDecl(DS);
+ NEXT;
+ }
+
+ // Figure out which matcher we've found, and call the appropriate
+ // subclass constructor.
+ // FIXME: Can we do this more logarithmically?
+#define FIXABLE_GADGET(name) \
+ if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
+ FixableGadgets.push_back(std::make_unique<name ## Gadget>(Result)); \
+ NEXT; \
+ }
+#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
+#define WARNING_GADGET(name) \
+ if (Result.Nodes.getNodeAs<Stmt>(#name)) { \
+ WarningGadgets.push_back(std::make_unique<name ## Gadget>(Result)); \
+ NEXT; \
+ }
+#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
+
+ assert(numFound >= 1 && "Gadgets not found in match result!");
+ assert(numFound <= 1 && "Conflicting bind tags in gadgets!");
+ }
+ };
+
+ MatchFinder M;
+ GadgetFinderCallback CB;
+
+ // clang-format off
+ M.addMatcher(
+ stmt(forEveryDescendant(
+ stmt(anyOf(
+ // Add Gadget::matcher() for every gadget in the registry.
+#define GADGET(x) \
+ x ## Gadget::matcher().bind(#x),
+#include "clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def"
+ // In parallel, match all DeclRefExprs so that to find out
+ // whether there are any uncovered by gadgets.
+ declRefExpr(anyOf(hasPointerType(), hasArrayType()),
+ to(varDecl())).bind("any_dre"),
+ // Also match DeclStmts because we'll need them when fixing
+ // their underlying VarDecls that otherwise don't have
+ // any backreferences to DeclStmts.
+ declStmt().bind("any_ds")
+ ))
+ // FIXME: Idiomatically there should be a forCallable(equalsNode(D))
+ // here, to make sure that the statement actually belongs to the
+ // function and not to a nested function. However, forCallable uses
+ // ParentMap which can't be used before the AST is fully constructed.
+ // The original problem doesn't sound like it needs ParentMap though,
+ // maybe there's a more direct solution?
+ )),
+ &CB
+ );
+ // clang-format on
+
+ M.match(*D->getBody(), D->getASTContext());
+
+ // Gadgets "claim" variables they're responsible for. Once this loop finishes,
+ // the tracker will only track DREs that weren't claimed by any gadgets,
+ // i.e. not understood by the analysis.
+ for (const auto &G : CB.FixableGadgets) {
+ for (const auto *DRE : G->getClaimedVarUseSites()) {
+ CB.Tracker.claimUse(DRE);
+ }
+ }
+
+ return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets), std::move(CB.Tracker)};
+}
+
+struct WarningGadgetSets {
+ std::map<const VarDecl *, std::set<std::unique_ptr<WarningGadget>>> byVar;
+ // These Gadgets are not related to pointer variables (e. g. temporaries).
+ llvm::SmallVector<std::unique_ptr<WarningGadget>, 16> noVar;
+};
+
+static WarningGadgetSets
+groupWarningGadgetsByVar(WarningGadgetList &&AllUnsafeOperations) {
+ WarningGadgetSets result;
+ // If some gadgets cover more than one
+ // variable, they'll appear more than once in the map.
+ for (auto &G : AllUnsafeOperations) {
+ DeclUseList ClaimedVarUseSites = G->getClaimedVarUseSites();
+
+ bool AssociatedWithVarDecl = false;
+ for (const DeclRefExpr *DRE : ClaimedVarUseSites) {
+ if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ result.byVar[VD].emplace(std::move(G));
+ AssociatedWithVarDecl = true;
+ }
+ }
+
+ if (!AssociatedWithVarDecl) {
+ result.noVar.emplace_back(std::move(G));
+ continue;
+ }
+ }
+ return result;
+}
+
+struct FixableGadgetSets {
+ std::map<const VarDecl *, std::set<std::unique_ptr<FixableGadget>>> byVar;
+};
+
+static FixableGadgetSets
+groupFixablesByVar(FixableGadgetList &&AllFixableOperations) {
+ FixableGadgetSets FixablesForUnsafeVars;
+ for (auto &F : AllFixableOperations) {
+ DeclUseList DREs = F->getClaimedVarUseSites();
+
+ for (const DeclRefExpr *DRE : DREs) {
+ if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ FixablesForUnsafeVars.byVar[VD].emplace(std::move(F));
+ }
+ }
+ }
+ return FixablesForUnsafeVars;
+}
+
+static std::map<const VarDecl *, FixItList>
+getFixIts(FixableGadgetSets &FixablesForUnsafeVars, const Strategy &S) {
+ std::map<const VarDecl *, FixItList> FixItsForVariable;
+ for (const auto &[VD, Fixables] : FixablesForUnsafeVars.byVar) {
+ // TODO fixVariable - fixit for the variable itself
+ bool ImpossibleToFix = false;
+ llvm::SmallVector<FixItHint, 16> FixItsForVD;
+ for (const auto &F : Fixables) {
+ llvm::Optional<FixItList> Fixits = F->getFixits(S);
+ if (!Fixits) {
+ ImpossibleToFix = true;
+ break;
+ } else {
+ const FixItList CorrectFixes = Fixits.value();
+ FixItsForVD.insert(FixItsForVD.end(), CorrectFixes.begin(),
+ CorrectFixes.end());
+ }
+ }
+ if (ImpossibleToFix)
+ FixItsForVariable.erase(VD);
+ else
+ FixItsForVariable[VD].insert(FixItsForVariable[VD].end(),
+ FixItsForVD.begin(), FixItsForVD.end());
+ }
+ return FixItsForVariable;
+}
+
+static Strategy
+getNaiveStrategy(const llvm::SmallVectorImpl<const VarDecl *> &UnsafeVars) {
+ Strategy S;
+ for (const VarDecl *VD : UnsafeVars) {
+ S.set(VD, Strategy::Kind::Span);
+ }
+ return S;
+}
+
+void clang::checkUnsafeBufferUsage(const Decl *D,
+ UnsafeBufferUsageHandler &Handler) {
+ assert(D && D->getBody());
+
+ WarningGadgetSets UnsafeOps;
+ FixableGadgetSets FixablesForUnsafeVars;
+ DeclUseTracker Tracker;
+
+ {
+ auto [FixableGadgets, WarningGadgets, TrackerRes] = findGadgets(D);
+ UnsafeOps = groupWarningGadgetsByVar(std::move(WarningGadgets));
+ FixablesForUnsafeVars = groupFixablesByVar(std::move(FixableGadgets));
+ Tracker = std::move(TrackerRes);
+ }
+
+ // Filter out non-local vars and vars with unclaimed DeclRefExpr-s.
+ for (auto it = FixablesForUnsafeVars.byVar.cbegin();
+ it != FixablesForUnsafeVars.byVar.cend();) {
+ // FIXME: Support ParmVarDecl as well.
+ if (!it->first->isLocalVarDecl() || Tracker.hasUnclaimedUses(it->first)) {
+ it = FixablesForUnsafeVars.byVar.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ llvm::SmallVector<const VarDecl *, 16> UnsafeVars;
+ for (const auto &[VD, ignore] : FixablesForUnsafeVars.byVar)
+ UnsafeVars.push_back(VD);
+
+ Strategy NaiveStrategy = getNaiveStrategy(UnsafeVars);
+ std::map<const VarDecl *, FixItList> FixItsForVariable =
+ getFixIts(FixablesForUnsafeVars, NaiveStrategy);
+
+ // FIXME Detect overlapping FixIts.
+
+ for (const auto &G : UnsafeOps.noVar) {
+ Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/false);
+ }
+
+ for (const auto &[VD, WarningGadgets] : UnsafeOps.byVar) {
+ auto FixItsIt = FixItsForVariable.find(VD);
+ Handler.handleFixableVariable(VD, FixItsIt != FixItsForVariable.end()
+ ? std::move(FixItsIt->second)
+ : FixItList{});
+ for (const auto &G : WarningGadgets) {
+ Handler.handleUnsafeOperation(G->getBaseStmt(), /*IsRelatedToDecl=*/true);
+ }
+ }
+}
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index 960c9773d192..a961e68f4ac1 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -2,7 +2,6 @@
#include "clang/Basic/AttrSubjectMatchRules.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/IdentifierTable.h"
-#include "llvm/ADT/StringSwitch.h"
using namespace clang;
int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
diff --git a/clang/lib/Basic/BuiltinTargetFeatures.h b/clang/lib/Basic/BuiltinTargetFeatures.h
index 4d3358de5076..9754acda2a68 100644
--- a/clang/lib/Basic/BuiltinTargetFeatures.h
+++ b/clang/lib/Basic/BuiltinTargetFeatures.h
@@ -54,7 +54,7 @@ class TargetFeatures {
case ')':
--InParentheses;
assert(InParentheses >= 0 && "Parentheses are not in pair");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case '|':
case ',':
if (InParentheses == 0) {
diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp
index b42e8f416cfc..74081a7c2ec6 100644
--- a/clang/lib/Basic/Builtins.cpp
+++ b/clang/lib/Basic/Builtins.cpp
@@ -18,14 +18,26 @@
#include "llvm/ADT/StringRef.h"
using namespace clang;
-static const Builtin::Info BuiltinInfo[] = {
- { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES,nullptr},
+const char *HeaderDesc::getName() const {
+ switch (ID) {
+#define HEADER(ID, NAME) \
+ case ID: \
+ return NAME;
+#include "clang/Basic/BuiltinHeaders.def"
+#undef HEADER
+ };
+ llvm_unreachable("Unknown HeaderDesc::HeaderID enum");
+}
+
+static constexpr Builtin::Info BuiltinInfo[] = {
+ {"not a builtin function", nullptr, nullptr, nullptr, HeaderDesc::NO_HEADER,
+ ALL_LANGUAGES},
#define BUILTIN(ID, TYPE, ATTRS) \
- { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr },
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \
- { #ID, TYPE, ATTRS, nullptr, LANGS, nullptr },
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANGS},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \
- { #ID, TYPE, ATTRS, HEADER, LANGS, nullptr },
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, LANGS},
#include "clang/Basic/Builtins.def"
};
@@ -63,37 +75,51 @@ bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) {
/// Is this builtin supported according to the given language options?
static bool builtinIsSupported(const Builtin::Info &BuiltinInfo,
const LangOptions &LangOpts) {
- bool BuiltinsUnsupported =
- LangOpts.NoBuiltin && strchr(BuiltinInfo.Attributes, 'f') != nullptr;
- bool CorBuiltinsUnsupported =
- !LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG);
- bool MathBuiltinsUnsupported =
- LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName &&
- llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h");
- bool GnuModeUnsupported = !LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG);
- bool MSModeUnsupported =
- !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG);
- bool ObjCUnsupported = !LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG;
- bool OclCUnsupported =
- !LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES);
- bool OclGASUnsupported =
- !LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS);
- bool OclPipeUnsupported =
- !LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE);
+ /* Builtins Unsupported */
+ if (LangOpts.NoBuiltin && strchr(BuiltinInfo.Attributes, 'f') != nullptr)
+ return false;
+ /* CorBuiltins Unsupported */
+ if (!LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG))
+ return false;
+ /* MathBuiltins Unsupported */
+ if (LangOpts.NoMathBuiltin && BuiltinInfo.Header.ID == HeaderDesc::MATH_H)
+ return false;
+ /* GnuMode Unsupported */
+ if (!LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG))
+ return false;
+ /* MSMode Unsupported */
+ if (!LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG))
+ return false;
+ /* ObjC Unsupported */
+ if (!LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG)
+ return false;
+ /* OpenCLC Unsupported */
+ if (!LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES))
+ return false;
+ /* OopenCL GAS Unsupported */
+ if (!LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS))
+ return false;
+ /* OpenCL Pipe Unsupported */
+ if (!LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE))
+ return false;
+
// Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher
// support is indicated with language option for blocks.
- bool OclDSEUnsupported =
- (LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) &&
- (BuiltinInfo.Langs & OCL_DSE);
- bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG;
- bool CUDAUnsupported = !LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG;
- bool CPlusPlusUnsupported =
- !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG;
- return !BuiltinsUnsupported && !CorBuiltinsUnsupported &&
- !MathBuiltinsUnsupported && !OclCUnsupported && !OclGASUnsupported &&
- !OclPipeUnsupported && !OclDSEUnsupported && !OpenMPUnsupported &&
- !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported &&
- !CPlusPlusUnsupported && !CUDAUnsupported;
+
+ /* OpenCL DSE Unsupported */
+ if ((LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) &&
+ (BuiltinInfo.Langs & OCL_DSE))
+ return false;
+ /* OpenMP Unsupported */
+ if (!LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG)
+ return false;
+ /* CUDA Unsupported */
+ if (!LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG)
+ return false;
+ /* CPlusPlus Unsupported */
+ if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG)
+ return false;
+ return true;
}
/// initializeBuiltins - Mark the identifiers for all the builtins with their
@@ -209,6 +235,7 @@ bool Builtin::Context::performsCallback(unsigned ID,
bool Builtin::Context::canBeRedeclared(unsigned ID) const {
return ID == Builtin::NotBuiltin || ID == Builtin::BI__va_start ||
+ ID == Builtin::BI__builtin_assume_aligned ||
(!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) ||
isInStdNamespace(ID);
}
diff --git a/clang/lib/Basic/CLWarnings.cpp b/clang/lib/Basic/CLWarnings.cpp
index 0cf367d9f7f6..5449d8f59fcf 100644
--- a/clang/lib/Basic/CLWarnings.cpp
+++ b/clang/lib/Basic/CLWarnings.cpp
@@ -12,10 +12,11 @@
#include "clang/Basic/CLWarnings.h"
#include "clang/Basic/DiagnosticCategories.h"
+#include <optional>
using namespace clang;
-llvm::Optional<diag::Group>
+std::optional<diag::Group>
clang::diagGroupFromCLWarningID(unsigned CLWarningID) {
switch (CLWarningID) {
case 4005: return diag::Group::MacroRedefined;
diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp
index d75cc410f2d9..b4cf6cbe95f8 100644
--- a/clang/lib/Basic/Cuda.cpp
+++ b/clang/lib/Basic/Cuda.cpp
@@ -1,71 +1,68 @@
#include "clang/Basic/Cuda.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/VersionTuple.h"
namespace clang {
-const char *CudaVersionToString(CudaVersion V) {
- switch (V) {
- case CudaVersion::UNKNOWN:
- return "unknown";
- case CudaVersion::CUDA_70:
- return "7.0";
- case CudaVersion::CUDA_75:
- return "7.5";
- case CudaVersion::CUDA_80:
- return "8.0";
- case CudaVersion::CUDA_90:
- return "9.0";
- case CudaVersion::CUDA_91:
- return "9.1";
- case CudaVersion::CUDA_92:
- return "9.2";
- case CudaVersion::CUDA_100:
- return "10.0";
- case CudaVersion::CUDA_101:
- return "10.1";
- case CudaVersion::CUDA_102:
- return "10.2";
- case CudaVersion::CUDA_110:
- return "11.0";
- case CudaVersion::CUDA_111:
- return "11.1";
- case CudaVersion::CUDA_112:
- return "11.2";
- case CudaVersion::CUDA_113:
- return "11.3";
- case CudaVersion::CUDA_114:
- return "11.4";
- case CudaVersion::CUDA_115:
- return "11.5";
- case CudaVersion::NEW:
- return "";
+struct CudaVersionMapEntry {
+ const char *Name;
+ CudaVersion Version;
+ llvm::VersionTuple TVersion;
+};
+#define CUDA_ENTRY(major, minor) \
+ { \
+#major "." #minor, CudaVersion::CUDA_##major##minor, \
+ llvm::VersionTuple(major, minor) \
}
- llvm_unreachable("invalid enum");
+
+static const CudaVersionMapEntry CudaNameVersionMap[] = {
+ CUDA_ENTRY(7, 0),
+ CUDA_ENTRY(7, 5),
+ CUDA_ENTRY(8, 0),
+ CUDA_ENTRY(9, 0),
+ CUDA_ENTRY(9, 1),
+ CUDA_ENTRY(9, 2),
+ CUDA_ENTRY(10, 0),
+ CUDA_ENTRY(10, 1),
+ CUDA_ENTRY(10, 2),
+ CUDA_ENTRY(11, 0),
+ CUDA_ENTRY(11, 1),
+ CUDA_ENTRY(11, 2),
+ CUDA_ENTRY(11, 3),
+ CUDA_ENTRY(11, 4),
+ CUDA_ENTRY(11, 5),
+ CUDA_ENTRY(11, 6),
+ CUDA_ENTRY(11, 7),
+ CUDA_ENTRY(11, 8),
+ {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits<int>::max())},
+ {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone.
+};
+#undef CUDA_ENTRY
+
+const char *CudaVersionToString(CudaVersion V) {
+ for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
+ if (I->Version == V)
+ return I->Name;
+
+ return CudaVersionToString(CudaVersion::UNKNOWN);
}
CudaVersion CudaStringToVersion(const llvm::Twine &S) {
- return llvm::StringSwitch<CudaVersion>(S.str())
- .Case("7.0", CudaVersion::CUDA_70)
- .Case("7.5", CudaVersion::CUDA_75)
- .Case("8.0", CudaVersion::CUDA_80)
- .Case("9.0", CudaVersion::CUDA_90)
- .Case("9.1", CudaVersion::CUDA_91)
- .Case("9.2", CudaVersion::CUDA_92)
- .Case("10.0", CudaVersion::CUDA_100)
- .Case("10.1", CudaVersion::CUDA_101)
- .Case("10.2", CudaVersion::CUDA_102)
- .Case("11.0", CudaVersion::CUDA_110)
- .Case("11.1", CudaVersion::CUDA_111)
- .Case("11.2", CudaVersion::CUDA_112)
- .Case("11.3", CudaVersion::CUDA_113)
- .Case("11.4", CudaVersion::CUDA_114)
- .Case("11.5", CudaVersion::CUDA_115)
- .Default(CudaVersion::UNKNOWN);
+ std::string VS = S.str();
+ for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
+ if (I->Name == VS)
+ return I->Version;
+ return CudaVersion::UNKNOWN;
+}
+
+CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
+ for (auto *I = CudaNameVersionMap; I->Version != CudaVersion::UNKNOWN; ++I)
+ if (I->TVersion == Version)
+ return I->Version;
+ return CudaVersion::UNKNOWN;
}
namespace {
@@ -91,6 +88,9 @@ static const CudaArchToStringMap arch_names[] = {
SM(70), SM(72), // Volta
SM(75), // Turing
SM(80), SM(86), // Ampere
+ SM(87), // Jetson/Drive AGX Orin
+ SM(89), // Ada Lovelace
+ SM(90), // Hopper
GFX(600), // gfx600
GFX(601), // gfx601
GFX(602), // gfx602
@@ -196,6 +196,11 @@ CudaVersion MinVersionForCudaArch(CudaArch A) {
return CudaVersion::CUDA_110;
case CudaArch::SM_86:
return CudaVersion::CUDA_111;
+ case CudaArch::SM_87:
+ return CudaVersion::CUDA_114;
+ case CudaArch::SM_89:
+ case CudaArch::SM_90:
+ return CudaVersion::CUDA_118;
default:
llvm_unreachable("invalid enum");
}
@@ -219,44 +224,6 @@ CudaVersion MaxVersionForCudaArch(CudaArch A) {
}
}
-CudaVersion ToCudaVersion(llvm::VersionTuple Version) {
- int IVer = Version.getMajor() * 10 + Version.getMinor().value_or(0);
- switch(IVer) {
- case 70:
- return CudaVersion::CUDA_70;
- case 75:
- return CudaVersion::CUDA_75;
- case 80:
- return CudaVersion::CUDA_80;
- case 90:
- return CudaVersion::CUDA_90;
- case 91:
- return CudaVersion::CUDA_91;
- case 92:
- return CudaVersion::CUDA_92;
- case 100:
- return CudaVersion::CUDA_100;
- case 101:
- return CudaVersion::CUDA_101;
- case 102:
- return CudaVersion::CUDA_102;
- case 110:
- return CudaVersion::CUDA_110;
- case 111:
- return CudaVersion::CUDA_111;
- case 112:
- return CudaVersion::CUDA_112;
- case 113:
- return CudaVersion::CUDA_113;
- case 114:
- return CudaVersion::CUDA_114;
- case 115:
- return CudaVersion::CUDA_115;
- default:
- return CudaVersion::UNKNOWN;
- }
-}
-
bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) {
return CudaFeatureEnabled(ToCudaVersion(Version), Feature);
}
diff --git a/clang/lib/Basic/DarwinSDKInfo.cpp b/clang/lib/Basic/DarwinSDKInfo.cpp
index 64bcb45a4cd8..00aa5f9e63cd 100644
--- a/clang/lib/Basic/DarwinSDKInfo.cpp
+++ b/clang/lib/Basic/DarwinSDKInfo.cpp
@@ -11,12 +11,13 @@
#include "llvm/Support/JSON.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
+#include <optional>
using namespace clang;
-Optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
+std::optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
const VersionTuple &Key, const VersionTuple &MinimumValue,
- Optional<VersionTuple> MaximumValue) const {
+ std::optional<VersionTuple> MaximumValue) const {
if (Key < MinimumKeyVersion)
return MinimumValue;
if (Key > MaximumKeyVersion)
@@ -29,11 +30,11 @@ Optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
// the major-only check.
if (Key.getMinor())
return map(VersionTuple(Key.getMajor()), MinimumValue, MaximumValue);
- // If this a major only key, return None for a missing entry.
- return None;
+ // If this a major only key, return std::nullopt for a missing entry.
+ return std::nullopt;
}
-Optional<DarwinSDKInfo::RelatedTargetVersionMapping>
+std::optional<DarwinSDKInfo::RelatedTargetVersionMapping>
DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
const llvm::json::Object &Obj, VersionTuple MaximumDeploymentTarget) {
VersionTuple Min = VersionTuple(std::numeric_limits<unsigned>::max());
@@ -45,7 +46,7 @@ DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
llvm::VersionTuple KeyVersion;
llvm::VersionTuple ValueVersion;
if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val))
- return None;
+ return std::nullopt;
Mapping[KeyVersion.normalize()] = ValueVersion;
if (KeyVersion < Min)
Min = KeyVersion;
@@ -56,32 +57,33 @@ DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
}
}
if (Mapping.empty())
- return None;
+ return std::nullopt;
return RelatedTargetVersionMapping(
Min, Max, MinValue, MaximumDeploymentTarget, std::move(Mapping));
}
-static Optional<VersionTuple> getVersionKey(const llvm::json::Object &Obj,
- StringRef Key) {
+static std::optional<VersionTuple> getVersionKey(const llvm::json::Object &Obj,
+ StringRef Key) {
auto Value = Obj.getString(Key);
if (!Value)
- return None;
+ return std::nullopt;
VersionTuple Version;
if (Version.tryParse(*Value))
- return None;
+ return std::nullopt;
return Version;
}
-Optional<DarwinSDKInfo>
+std::optional<DarwinSDKInfo>
DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) {
auto Version = getVersionKey(*Obj, "Version");
if (!Version)
- return None;
+ return std::nullopt;
auto MaximumDeploymentVersion =
getVersionKey(*Obj, "MaximumDeploymentTarget");
if (!MaximumDeploymentVersion)
- return None;
- llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>>
+ return std::nullopt;
+ llvm::DenseMap<OSEnvPair::StorageType,
+ std::optional<RelatedTargetVersionMapping>>
VersionMappings;
if (const auto *VM = Obj->getObject("VersionMap")) {
// FIXME: Generalize this out beyond iOS-deriving targets.
@@ -107,7 +109,7 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) {
auto VersionMap = RelatedTargetVersionMapping::parseJSON(
*Mapping, *MaximumDeploymentVersion);
if (!VersionMap)
- return None;
+ return std::nullopt;
VersionMappings[OSEnvPair::macOStoMacCatalystPair().Value] =
std::move(VersionMap);
}
@@ -115,7 +117,7 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) {
auto VersionMap = RelatedTargetVersionMapping::parseJSON(
*Mapping, *MaximumDeploymentVersion);
if (!VersionMap)
- return None;
+ return std::nullopt;
VersionMappings[OSEnvPair::macCatalystToMacOSPair().Value] =
std::move(VersionMap);
}
@@ -126,7 +128,7 @@ DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) {
std::move(VersionMappings));
}
-Expected<Optional<DarwinSDKInfo>>
+Expected<std::optional<DarwinSDKInfo>>
clang::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) {
llvm::SmallString<256> Filepath = SDKRootPath;
llvm::sys::path::append(Filepath, "SDKSettings.json");
@@ -134,7 +136,7 @@ clang::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) {
VFS.getBufferForFile(Filepath);
if (!File) {
// If the file couldn't be read, assume it just doesn't exist.
- return None;
+ return std::nullopt;
}
Expected<llvm::json::Value> Result =
llvm::json::parse(File.get()->getBuffer());
diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp
index 8e2593b103d1..ac08e98a278d 100644
--- a/clang/lib/Basic/DiagnosticIDs.cpp
+++ b/clang/lib/Basic/DiagnosticIDs.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
#include <map>
+#include <optional>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -202,7 +203,7 @@ const StaticDiagInfoRec StaticDiagInfo[] = {
} // namespace
-static const unsigned StaticDiagInfoSize = llvm::array_lengthof(StaticDiagInfo);
+static const unsigned StaticDiagInfoSize = std::size(StaticDiagInfo);
/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID,
/// or null if the ID is invalid.
@@ -317,7 +318,7 @@ static const StaticDiagCategoryRec CategoryNameTable[] = {
/// getNumberOfCategories - Return the number of categories
unsigned DiagnosticIDs::getNumberOfCategories() {
- return llvm::array_lengthof(CategoryNameTable) - 1;
+ return std::size(CategoryNameTable) - 1;
}
/// getCategoryNameFromID - Given a category ID, return the name of the
@@ -546,7 +547,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
if (Result == diag::Severity::Ignored)
return Result;
- // Honor -w: this disables all messages which which are not Error/Fatal by
+ // Honor -w: this disables all messages which are not Error/Fatal by
// default (disregarding attempts to upgrade severity from Warning to Error),
// as well as disabling all messages which are currently mapped to Warning
// (whether by default or downgraded from Error via e.g. -Wno-error or #pragma
@@ -634,19 +635,19 @@ StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) {
return OptionTable[static_cast<int>(Group)].getName();
}
-llvm::Optional<diag::Group>
+std::optional<diag::Group>
DiagnosticIDs::getGroupForWarningOption(StringRef Name) {
const auto *Found = llvm::partition_point(
OptionTable, [=](const WarningOption &O) { return O.getName() < Name; });
if (Found == std::end(OptionTable) || Found->getName() != Name)
- return llvm::None;
+ return std::nullopt;
return static_cast<diag::Group>(Found - OptionTable);
}
-llvm::Optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {
+std::optional<diag::Group> DiagnosticIDs::getGroupForDiag(unsigned DiagID) {
if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID))
return static_cast<diag::Group>(Info->getOptionGroupIndex());
- return llvm::None;
+ return std::nullopt;
}
/// getWarningOptionForDiag - Return the lowest-level warning option that
@@ -703,7 +704,7 @@ static bool getDiagnosticsInGroup(diag::Flavor Flavor,
bool
DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group,
SmallVectorImpl<diag::kind> &Diags) const {
- if (llvm::Optional<diag::Group> G = getGroupForWarningOption(Group))
+ if (std::optional<diag::Group> G = getGroupForWarningOption(Group))
return ::getDiagnosticsInGroup(
Flavor, &OptionTable[static_cast<unsigned>(*G)], Diags);
return true;
diff --git a/clang/lib/Basic/DiagnosticOptions.cpp b/clang/lib/Basic/DiagnosticOptions.cpp
index 68571f2cf94f..12e47ea0231e 100644
--- a/clang/lib/Basic/DiagnosticOptions.cpp
+++ b/clang/lib/Basic/DiagnosticOptions.cpp
@@ -17,7 +17,7 @@
namespace clang {
raw_ostream &operator<<(raw_ostream &Out, DiagnosticLevelMask M) {
- using UT = std::underlying_type<DiagnosticLevelMask>::type;
+ using UT = std::underlying_type_t<DiagnosticLevelMask>;
return Out << static_cast<UT>(M);
}
diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp
index b66780a1d1d1..e8d0f20019eb 100644
--- a/clang/lib/Basic/FileManager.cpp
+++ b/clang/lib/Basic/FileManager.cpp
@@ -31,6 +31,7 @@
#include <climits>
#include <cstdint>
#include <cstdlib>
+#include <optional>
#include <string>
#include <utility>
@@ -123,7 +124,7 @@ FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) {
DirName != llvm::sys::path::root_path(DirName) &&
llvm::sys::path::is_separator(DirName.back()))
DirName = DirName.substr(0, DirName.size()-1);
- Optional<std::string> DirNameStr;
+ std::optional<std::string> DirNameStr;
if (is_style_windows(llvm::sys::path::Style::native)) {
// Fixing a problem with "clang C:test.c" on Windows.
// Stat("C:") does not recognize "C:" as a valid directory
@@ -212,13 +213,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
if (!SeenFileInsertResult.first->second)
return llvm::errorCodeToError(
SeenFileInsertResult.first->second.getError());
- // Construct and return and FileEntryRef, unless it's a redirect to another
- // filename.
- FileEntryRef::MapValue Value = *SeenFileInsertResult.first->second;
- if (LLVM_LIKELY(Value.V.is<FileEntry *>()))
- return FileEntryRef(*SeenFileInsertResult.first);
- return FileEntryRef(*reinterpret_cast<const FileEntryRef::MapEntry *>(
- Value.V.get<const void *>()));
+ return FileEntryRef(*SeenFileInsertResult.first);
}
// We've not seen this before. Fill it in.
@@ -274,8 +269,8 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
if (!UFE)
UFE = new (FilesAlloc.Allocate()) FileEntry();
- if (Status.getName() == Filename) {
- // The name matches. Set the FileEntry.
+ if (!Status.ExposesExternalVFSPath || Status.getName() == Filename) {
+ // Use the requested name. Set the FileEntry.
NamedFileEnt->second = FileEntryRef::MapValue(*UFE, DirInfo);
} else {
// Name mismatch. We need a redirect. First grab the actual entry we want
@@ -292,25 +287,9 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
// filesystems behave and confuses parts of clang expect to see the
// name-as-accessed on the \a FileEntryRef.
//
- // Further, it isn't *just* external names, but will also give back absolute
- // paths when a relative path was requested - the check is comparing the
- // name from the status, which is passed an absolute path resolved from the
- // current working directory. `clang-apply-replacements` appears to depend
- // on this behaviour, though it's adjusting the working directory, which is
- // definitely not supported. Once that's fixed this hack should be able to
- // be narrowed to only when there's an externally mapped name given back.
- //
// A potential plan to remove this is as follows -
- // - Add API to determine if the name has been rewritten by the VFS.
- // - Fix `clang-apply-replacements` to pass down the absolute path rather
- // than changing the CWD. Narrow this hack down to just externally
- // mapped paths.
- // - Expose the requested filename. One possibility would be to allow
- // redirection-FileEntryRefs to be returned, rather than returning
- // the pointed-at-FileEntryRef, and customizing `getName()` to look
- // through the indirection.
// - Update callers such as `HeaderSearch::findUsableModuleForHeader()`
- // to explicitly use the requested filename rather than just using
+ // to explicitly use the `getNameAsRequested()` rather than just using
// `getName()`.
// - Add a `FileManager::getExternalPath` API for explicitly getting the
// remapped external filename when there is one available. Adopt it in
@@ -341,9 +320,6 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
// Cache the redirection in the previously-inserted entry, still available
// in the tentative return value.
NamedFileEnt->second = FileEntryRef::MapValue(Redirection);
-
- // Fix the tentative return value.
- NamedFileEnt = &Redirection;
}
FileEntryRef ReturnedRef(*NamedFileEnt);
@@ -495,11 +471,11 @@ FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size,
return FileEntryRef(NamedFileEnt);
}
-llvm::Optional<FileEntryRef> FileManager::getBypassFile(FileEntryRef VF) {
+OptionalFileEntryRef 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;
+ return std::nullopt;
if (!SeenBypassFileEntries)
SeenBypassFileEntries = std::make_unique<
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 82cee4aa052d..63b08d8d0459 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -13,6 +13,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
@@ -82,7 +83,7 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
// Constants for TokenKinds.def
namespace {
- enum {
+ enum TokenKey : unsigned {
KEYC99 = 0x1,
KEYCXX = 0x2,
KEYCXX11 = 0x4,
@@ -93,76 +94,155 @@ namespace {
KEYNOCXX = 0x80,
KEYBORLAND = 0x100,
KEYOPENCLC = 0x200,
- KEYC11 = 0x400,
+ KEYC2X = 0x400,
KEYNOMS18 = 0x800,
KEYNOOPENCL = 0x1000,
WCHARSUPPORT = 0x2000,
HALFSUPPORT = 0x4000,
CHAR8SUPPORT = 0x8000,
- KEYCONCEPTS = 0x10000,
- KEYOBJC = 0x20000,
- KEYZVECTOR = 0x40000,
- KEYCOROUTINES = 0x80000,
- KEYMODULES = 0x100000,
- KEYCXX20 = 0x200000,
- KEYOPENCLCXX = 0x400000,
- KEYMSCOMPAT = 0x800000,
- KEYSYCL = 0x1000000,
- KEYCUDA = 0x2000000,
- KEYMAX = KEYCUDA, // The maximum key
+ KEYOBJC = 0x10000,
+ KEYZVECTOR = 0x20000,
+ KEYCOROUTINES = 0x40000,
+ KEYMODULES = 0x80000,
+ KEYCXX20 = 0x100000,
+ KEYOPENCLCXX = 0x200000,
+ KEYMSCOMPAT = 0x400000,
+ KEYSYCL = 0x800000,
+ KEYCUDA = 0x1000000,
+ KEYHLSL = 0x2000000,
+ KEYMAX = KEYHLSL, // The maximum key
KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
};
- /// How a keyword is treated in the selected standard.
+ /// How a keyword is treated in the selected standard. This enum is ordered
+ /// intentionally so that the value that 'wins' is the most 'permissive'.
enum KeywordStatus {
+ KS_Unknown, // Not yet calculated. Used when figuring out the status.
KS_Disabled, // Disabled
+ KS_Future, // Is a keyword in future standard
KS_Extension, // Is an extension
KS_Enabled, // Enabled
- KS_Future // Is a keyword in future standard
};
} // namespace
+// This works on a single TokenKey flag and checks the LangOpts to get the
+// KeywordStatus based exclusively on this flag, so that it can be merged in
+// getKeywordStatus. Most should be enabled/disabled, but some might imply
+// 'future' versions, or extensions. Returns 'unknown' unless this is KNOWN to
+// be disabled, and the calling function makes it 'disabled' if no other flag
+// changes it. This is necessary for the KEYNOCXX and KEYNOOPENCL flags.
+static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
+ TokenKey Flag) {
+ // Flag is a single bit version of TokenKey (that is, not
+ // KEYALL/KEYALLCXX/etc), so we can check with == throughout this function.
+ assert((Flag & ~(Flag - 1)) == Flag && "Multiple bits set?");
+
+ switch (Flag) {
+ case KEYC99:
+ if (LangOpts.C99)
+ return KS_Enabled;
+ return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
+ case KEYC2X:
+ if (LangOpts.C2x)
+ return KS_Enabled;
+ return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
+ case KEYCXX:
+ return LangOpts.CPlusPlus ? KS_Enabled : KS_Unknown;
+ case KEYCXX11:
+ if (LangOpts.CPlusPlus11)
+ return KS_Enabled;
+ return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
+ case KEYCXX20:
+ if (LangOpts.CPlusPlus20)
+ return KS_Enabled;
+ return LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
+ case KEYGNU:
+ return LangOpts.GNUKeywords ? KS_Extension : KS_Unknown;
+ case KEYMS:
+ return LangOpts.MicrosoftExt ? KS_Extension : KS_Unknown;
+ case BOOLSUPPORT:
+ if (LangOpts.Bool) return KS_Enabled;
+ return !LangOpts.CPlusPlus ? KS_Future : KS_Unknown;
+ case KEYALTIVEC:
+ return LangOpts.AltiVec ? KS_Enabled : KS_Unknown;
+ case KEYBORLAND:
+ return LangOpts.Borland ? KS_Extension : KS_Unknown;
+ case KEYOPENCLC:
+ return LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus ? KS_Enabled
+ : KS_Unknown;
+ case WCHARSUPPORT:
+ return LangOpts.WChar ? KS_Enabled : KS_Unknown;
+ case HALFSUPPORT:
+ return LangOpts.Half ? KS_Enabled : KS_Unknown;
+ case CHAR8SUPPORT:
+ if (LangOpts.Char8) return KS_Enabled;
+ if (LangOpts.CPlusPlus20) return KS_Unknown;
+ if (LangOpts.CPlusPlus) return KS_Future;
+ return KS_Unknown;
+ case KEYOBJC:
+ // We treat bridge casts as objective-C keywords so we can warn on them
+ // in non-arc mode.
+ return LangOpts.ObjC ? KS_Enabled : KS_Unknown;
+ case KEYZVECTOR:
+ return LangOpts.ZVector ? KS_Enabled : KS_Unknown;
+ case KEYCOROUTINES:
+ return LangOpts.Coroutines ? KS_Enabled : KS_Unknown;
+ case KEYMODULES:
+ return LangOpts.ModulesTS ? KS_Enabled : KS_Unknown;
+ case KEYOPENCLCXX:
+ return LangOpts.OpenCLCPlusPlus ? KS_Enabled : KS_Unknown;
+ case KEYMSCOMPAT:
+ return LangOpts.MSVCCompat ? KS_Enabled : KS_Unknown;
+ case KEYSYCL:
+ return LangOpts.isSYCL() ? KS_Enabled : KS_Unknown;
+ case KEYCUDA:
+ return LangOpts.CUDA ? KS_Enabled : KS_Unknown;
+ case KEYHLSL:
+ return LangOpts.HLSL ? KS_Enabled : KS_Unknown;
+ case KEYNOCXX:
+ // This is enabled in all non-C++ modes, but might be enabled for other
+ // reasons as well.
+ return LangOpts.CPlusPlus ? KS_Unknown : KS_Enabled;
+ case KEYNOOPENCL:
+ // The disable behavior for this is handled in getKeywordStatus.
+ return KS_Unknown;
+ case KEYNOMS18:
+ // The disable behavior for this is handled in getKeywordStatus.
+ return KS_Unknown;
+ default:
+ llvm_unreachable("Unknown KeywordStatus flag");
+ }
+}
+
/// Translates flags as specified in TokenKinds.def into keyword status
/// in the given language standard.
static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
unsigned Flags) {
+ // KEYALL means always enabled, so special case this one.
if (Flags == KEYALL) return KS_Enabled;
- if (LangOpts.CPlusPlus && (Flags & KEYCXX)) return KS_Enabled;
- if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) return KS_Enabled;
- if (LangOpts.CPlusPlus20 && (Flags & KEYCXX20)) return KS_Enabled;
- if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled;
- if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension;
- if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension;
- if (LangOpts.MSVCCompat && (Flags & KEYMSCOMPAT)) return KS_Enabled;
- if (LangOpts.Borland && (Flags & KEYBORLAND)) return KS_Extension;
- if (LangOpts.Bool && (Flags & BOOLSUPPORT)) return KS_Enabled;
- if (LangOpts.Half && (Flags & HALFSUPPORT)) return KS_Enabled;
- if (LangOpts.WChar && (Flags & WCHARSUPPORT)) return KS_Enabled;
- if (LangOpts.Char8 && (Flags & CHAR8SUPPORT)) return KS_Enabled;
- if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) return KS_Enabled;
- if (LangOpts.ZVector && (Flags & KEYZVECTOR)) return KS_Enabled;
- if (LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLC))
- return KS_Enabled;
- if (LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLCXX)) return KS_Enabled;
- if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) return KS_Enabled;
- if (LangOpts.C11 && (Flags & KEYC11)) return KS_Enabled;
- // We treat bridge casts as objective-C keywords so we can warn on them
- // in non-arc mode.
- if (LangOpts.ObjC && (Flags & KEYOBJC)) return KS_Enabled;
- if (LangOpts.CPlusPlus20 && (Flags & KEYCONCEPTS)) return KS_Enabled;
- if (LangOpts.Coroutines && (Flags & KEYCOROUTINES)) return KS_Enabled;
- if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled;
- if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future;
- if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus20 && (Flags & CHAR8SUPPORT))
- return KS_Future;
- if (LangOpts.isSYCL() && (Flags & KEYSYCL))
- return KS_Enabled;
- if (LangOpts.CUDA && (Flags & KEYCUDA))
- return KS_Enabled;
- return KS_Disabled;
+ // These are tests that need to 'always win', as they are special in that they
+ // disable based on certain conditions.
+ if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)) return KS_Disabled;
+ if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
+ !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
+ return KS_Disabled;
+
+ KeywordStatus CurStatus = KS_Unknown;
+
+ while (Flags != 0) {
+ unsigned CurFlag = Flags & ~(Flags - 1);
+ Flags = Flags & ~CurFlag;
+ CurStatus = std::max(
+ CurStatus,
+ getKeywordStatusHelper(LangOpts, static_cast<TokenKey>(CurFlag)));
+ }
+
+ if (CurStatus == KS_Unknown)
+ return KS_Disabled;
+ return CurStatus;
}
/// AddKeyword - This method is used to associate a token ID with specific
@@ -173,15 +253,6 @@ static void AddKeyword(StringRef Keyword,
const LangOptions &LangOpts, IdentifierTable &Table) {
KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags);
- // Don't add this keyword under MSVCCompat.
- if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) &&
- !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
- return;
-
- // Don't add this keyword under OpenCL.
- if (LangOpts.OpenCL && (Flags & KEYNOOPENCL))
- return;
-
// Don't add this keyword if disabled in this language.
if (AddResult == KS_Disabled) return;
@@ -777,3 +848,35 @@ StringRef clang::getNullabilitySpelling(NullabilityKind kind,
}
llvm_unreachable("Unknown nullability kind.");
}
+
+diag::kind
+IdentifierTable::getFutureCompatDiagKind(const IdentifierInfo &II,
+ const LangOptions &LangOpts) {
+ assert(II.isFutureCompatKeyword() && "diagnostic should not be needed");
+
+ unsigned Flags = llvm::StringSwitch<unsigned>(II.getName())
+#define KEYWORD(NAME, FLAGS) .Case(#NAME, FLAGS)
+#include "clang/Basic/TokenKinds.def"
+#undef KEYWORD
+ ;
+
+ if (LangOpts.CPlusPlus) {
+ if ((Flags & KEYCXX11) == KEYCXX11)
+ return diag::warn_cxx11_keyword;
+
+ // char8_t is not modeled as a CXX20_KEYWORD because it's not
+ // unconditionally enabled in C++20 mode. (It can be disabled
+ // by -fno-char8_t.)
+ if (((Flags & KEYCXX20) == KEYCXX20) ||
+ ((Flags & CHAR8SUPPORT) == CHAR8SUPPORT))
+ return diag::warn_cxx20_keyword;
+ } else {
+ if ((Flags & KEYC99) == KEYC99)
+ return diag::warn_c99_keyword;
+ if ((Flags & KEYC2X) == KEYC2X)
+ return diag::warn_c2x_keyword;
+ }
+
+ llvm_unreachable(
+ "Keyword not known to come from a newer Standard or proposed Standard");
+}
diff --git a/clang/lib/Basic/LangStandards.cpp b/clang/lib/Basic/LangStandards.cpp
index a21898dd3c62..4b36f7bf4786 100644
--- a/clang/lib/Basic/LangStandards.cpp
+++ b/clang/lib/Basic/LangStandards.cpp
@@ -58,27 +58,17 @@ LangStandard::Kind clang::getDefaultLanguageStandard(clang::Language Lang,
return LangStandard::lang_cuda;
case Language::Asm:
case Language::C:
- if (CLANG_DEFAULT_STD_C != LangStandard::lang_unspecified)
- return CLANG_DEFAULT_STD_C;
-
// The PS4 uses C99 as the default C standard.
if (T.isPS4())
return LangStandard::lang_gnu99;
return LangStandard::lang_gnu17;
case Language::ObjC:
- if (CLANG_DEFAULT_STD_C != LangStandard::lang_unspecified)
- return CLANG_DEFAULT_STD_C;
-
return LangStandard::lang_gnu11;
case Language::CXX:
case Language::ObjCXX:
- if (CLANG_DEFAULT_STD_CXX != LangStandard::lang_unspecified)
- return CLANG_DEFAULT_STD_CXX;
-
- if (T.isDriverKit())
- return LangStandard::lang_gnucxx17;
- else
+ if (T.isPS())
return LangStandard::lang_gnucxx14;
+ return LangStandard::lang_gnucxx17;
case Language::RenderScript:
return LangStandard::lang_c99;
case Language::HIP:
diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp
index 17b83184abb6..9c4c83486c2d 100644
--- a/clang/lib/Basic/Module.cpp
+++ b/clang/lib/Basic/Module.cpp
@@ -148,6 +148,26 @@ bool Module::isUnimportable(const LangOptions &LangOpts,
llvm_unreachable("could not find a reason why module is unimportable");
}
+// The -fmodule-name option tells the compiler to textually include headers in
+// the specified module, meaning Clang won't build the specified module. This
+// is useful in a number of situations, for instance, when building a library
+// that vends a module map, one might want to avoid hitting intermediate build
+// products containing the module map or avoid finding the system installed
+// modulemap for that library.
+bool Module::isForBuilding(const LangOptions &LangOpts) const {
+ StringRef TopLevelName = getTopLevelModuleName();
+ StringRef CurrentModule = LangOpts.CurrentModule;
+
+ // When building framework Foo, we want to make sure that Foo *and*
+ // Foo_Private are textually included and no modules are built for both.
+ if (getTopLevelModule()->IsFramework &&
+ CurrentModule == LangOpts.ModuleName &&
+ !CurrentModule.endswith("_Private") && TopLevelName.endswith("_Private"))
+ TopLevelName = TopLevelName.drop_back(8);
+
+ return TopLevelName == CurrentModule;
+}
+
bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
Requirement &Req,
UnresolvedHeaderDirective &MissingHeader,
@@ -264,7 +284,7 @@ ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) {
TopHeaderNames.clear();
}
- return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end());
+ return llvm::ArrayRef(TopHeaders.begin(), TopHeaders.end());
}
bool Module::directlyUses(const Module *Requested) {
@@ -633,7 +653,9 @@ LLVM_DUMP_METHOD void Module::dump() const {
void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
VisibleCallback Vis, ConflictCallback Cb) {
- assert(Loc.isValid() && "setVisible expects a valid import location");
+ // We can't import a global module fragment so the location can be invalid.
+ assert((M->isGlobalModule() || Loc.isValid()) &&
+ "setVisible expects a valid import location");
if (isVisible(M))
return;
@@ -653,7 +675,7 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc,
return;
ImportLocs[ID] = Loc;
- Vis(M);
+ Vis(V.M);
// Make any exported modules visible.
SmallVector<Module *, 16> Exports;
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 2f2e6537ebd3..36bce7e44afb 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -104,14 +104,27 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef 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_at:
+ return llvm::StringSwitch<OpenMPAtClauseKind>(Str)
+#define OPENMP_AT_KIND(Name) .Case(#Name, OMPC_AT_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_AT_unknown);
+ case OMPC_severity:
+ return llvm::StringSwitch<OpenMPSeverityClauseKind>(Str)
+#define OPENMP_SEVERITY_KIND(Name) .Case(#Name, OMPC_SEVERITY_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_SEVERITY_unknown);
case OMPC_lastprivate:
return llvm::StringSwitch<OpenMPLastprivateModifier>(Str)
#define OPENMP_LASTPRIVATE_KIND(Name) .Case(#Name, OMPC_LASTPRIVATE_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_LASTPRIVATE_unknown);
case OMPC_order:
- return llvm::StringSwitch<OpenMPOrderClauseKind>(Str)
-#define OPENMP_ORDER_KIND(Name) .Case(#Name, OMPC_ORDER_##Name)
+ return llvm::StringSwitch<unsigned>(Str)
+#define OPENMP_ORDER_KIND(Name) \
+ .Case(#Name, static_cast<unsigned>(OMPC_ORDER_##Name))
+#define OPENMP_ORDER_MODIFIER(Name) \
+ .Case(#Name, static_cast<unsigned>(OMPC_ORDER_MODIFIER_##Name))
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_ORDER_unknown);
case OMPC_update:
@@ -139,6 +152,24 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str,
#define OPENMP_BIND_KIND(Name) .Case(#Name, OMPC_BIND_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_BIND_unknown);
+ case OMPC_grainsize: {
+ unsigned Type = llvm::StringSwitch<unsigned>(Str)
+#define OPENMP_GRAINSIZE_MODIFIER(Name) .Case(#Name, OMPC_GRAINSIZE_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_GRAINSIZE_unknown);
+ if (LangOpts.OpenMP < 51)
+ return OMPC_GRAINSIZE_unknown;
+ return Type;
+ }
+ case OMPC_num_tasks: {
+ unsigned Type = llvm::StringSwitch<unsigned>(Str)
+#define OPENMP_NUMTASKS_MODIFIER(Name) .Case(#Name, OMPC_NUMTASKS_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_NUMTASKS_unknown);
+ if (LangOpts.OpenMP < 51)
+ return OMPC_NUMTASKS_unknown;
+ return Type;
+ }
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -178,9 +209,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str,
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_uniform:
case OMPC_use_device_ptr:
@@ -336,6 +365,26 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'device_type' clause type");
+ case OMPC_at:
+ switch (Type) {
+ case OMPC_AT_unknown:
+ return "unknown";
+#define OPENMP_AT_KIND(Name) \
+ case OMPC_AT_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'at' clause type");
+ case OMPC_severity:
+ switch (Type) {
+ case OMPC_SEVERITY_unknown:
+ return "unknown";
+#define OPENMP_SEVERITY_KIND(Name) \
+ case OMPC_SEVERITY_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'severity' clause type");
case OMPC_lastprivate:
switch (Type) {
case OMPC_LASTPRIVATE_unknown:
@@ -349,10 +398,14 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_order:
switch (Type) {
case OMPC_ORDER_unknown:
+ case OMPC_ORDER_MODIFIER_last:
return "unknown";
#define OPENMP_ORDER_KIND(Name) \
- case OMPC_ORDER_##Name: \
- return #Name;
+ case OMPC_ORDER_##Name: \
+ return #Name;
+#define OPENMP_ORDER_MODIFIER(Name) \
+ case OMPC_ORDER_MODIFIER_##Name: \
+ return #Name;
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'order' clause type");
@@ -406,6 +459,26 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'bind' clause type");
+ case OMPC_grainsize:
+ switch (Type) {
+ case OMPC_GRAINSIZE_unknown:
+ return "unknown";
+#define OPENMP_GRAINSIZE_MODIFIER(Name) \
+ case OMPC_GRAINSIZE_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'grainsize' clause modifier");
+ case OMPC_num_tasks:
+ switch (Type) {
+ case OMPC_NUMTASKS_unknown:
+ return "unknown";
+#define OPENMP_NUMTASKS_MODIFIER(Name) \
+ case OMPC_NUMTASKS_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'num_tasks' clause modifier");
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -445,9 +518,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_uniform:
case OMPC_use_device_ptr:
@@ -650,6 +721,14 @@ bool clang::isOpenMPLoopTransformationDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_tile || DKind == OMPD_unroll;
}
+bool clang::isOpenMPCombinedParallelADirective(OpenMPDirectiveKind DKind) {
+ return DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd ||
+ DKind == OMPD_parallel_master ||
+ DKind == OMPD_parallel_master_taskloop ||
+ DKind == OMPD_parallel_master_taskloop_simd ||
+ DKind == OMPD_parallel_sections;
+}
+
void clang::getOpenMPCaptureRegions(
SmallVectorImpl<OpenMPDirectiveKind> &CaptureRegions,
OpenMPDirectiveKind DKind) {
@@ -763,6 +842,7 @@ void clang::getOpenMPCaptureRegions(
case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
+ case OMPD_error:
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_cancel:
diff --git a/clang/lib/Basic/ProfileList.cpp b/clang/lib/Basic/ProfileList.cpp
index 9c88559d1c33..eea1b1e60ec7 100644
--- a/clang/lib/Basic/ProfileList.cpp
+++ b/clang/lib/Basic/ProfileList.cpp
@@ -17,6 +17,7 @@
#include "llvm/Support/SpecialCaseList.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
@@ -66,8 +67,7 @@ ProfileSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
ProfileList::ProfileList(ArrayRef<std::string> Paths, SourceManager &SM)
: SCL(ProfileSpecialCaseList::createOrDie(
Paths, SM.getFileManager().getVirtualFileSystem())),
- Empty(SCL->isEmpty()),
- Default(SCL->hasPrefix("fun") || SCL->hasPrefix("src")), SM(SM) {}
+ Empty(SCL->isEmpty()), SM(SM) {}
ProfileList::~ProfileList() = default;
@@ -85,30 +85,66 @@ static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) {
llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum");
}
-llvm::Optional<bool>
+ProfileList::ExclusionType
+ProfileList::getDefault(CodeGenOptions::ProfileInstrKind Kind) const {
+ StringRef Section = getSectionName(Kind);
+ // Check for "default:<type>"
+ if (SCL->inSection(Section, "default", "allow"))
+ return Allow;
+ if (SCL->inSection(Section, "default", "skip"))
+ return Skip;
+ if (SCL->inSection(Section, "default", "forbid"))
+ return Forbid;
+ // If any cases use "fun" or "src", set the default to FORBID.
+ if (SCL->hasPrefix("fun") || SCL->hasPrefix("src"))
+ return Forbid;
+ return Allow;
+}
+
+std::optional<ProfileList::ExclusionType>
+ProfileList::inSection(StringRef Section, StringRef Prefix,
+ StringRef Query) const {
+ if (SCL->inSection(Section, Prefix, Query, "allow"))
+ return Allow;
+ if (SCL->inSection(Section, Prefix, Query, "skip"))
+ return Skip;
+ if (SCL->inSection(Section, Prefix, Query, "forbid"))
+ return Forbid;
+ if (SCL->inSection(Section, Prefix, Query))
+ return Allow;
+ return std::nullopt;
+}
+
+std::optional<ProfileList::ExclusionType>
ProfileList::isFunctionExcluded(StringRef FunctionName,
CodeGenOptions::ProfileInstrKind Kind) const {
StringRef Section = getSectionName(Kind);
+ // Check for "function:<regex>=<case>"
+ if (auto V = inSection(Section, "function", FunctionName))
+ return V;
if (SCL->inSection(Section, "!fun", FunctionName))
- return true;
+ return Forbid;
if (SCL->inSection(Section, "fun", FunctionName))
- return false;
- return None;
+ return Allow;
+ return std::nullopt;
}
-llvm::Optional<bool>
+std::optional<ProfileList::ExclusionType>
ProfileList::isLocationExcluded(SourceLocation Loc,
CodeGenOptions::ProfileInstrKind Kind) const {
return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind);
}
-llvm::Optional<bool>
+std::optional<ProfileList::ExclusionType>
ProfileList::isFileExcluded(StringRef FileName,
CodeGenOptions::ProfileInstrKind Kind) const {
StringRef Section = getSectionName(Kind);
+ // Check for "source:<regex>=<case>"
+ if (auto V = inSection(Section, "source", FileName))
+ return V;
if (SCL->inSection(Section, "!src", FileName))
- return true;
+ return Forbid;
if (SCL->inSection(Section, "src", FileName))
- return false;
- return None;
+ return Allow;
+ return std::nullopt;
}
diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp
index 5bf8d39ffd95..2dbf04c6ede9 100644
--- a/clang/lib/Basic/SanitizerSpecialCaseList.cpp
+++ b/clang/lib/Basic/SanitizerSpecialCaseList.cpp
@@ -33,7 +33,7 @@ SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
std::string Error;
if (auto SSCL = create(Paths, VFS, Error))
return SSCL;
- llvm::report_fatal_error(Error);
+ llvm::report_fatal_error(StringRef(Error));
}
void SanitizerSpecialCaseList::createSanitizerSections() {
diff --git a/clang/lib/Basic/Sanitizers.cpp b/clang/lib/Basic/Sanitizers.cpp
index 7d903c8fdf5e..62ccdf8e9bbf 100644
--- a/clang/lib/Basic/Sanitizers.cpp
+++ b/clang/lib/Basic/Sanitizers.cpp
@@ -61,7 +61,7 @@ namespace clang {
unsigned SanitizerMask::countPopulation() const {
unsigned total = 0;
for (const auto &Val : maskLoToHigh)
- total += llvm::countPopulation(Val);
+ total += llvm::popcount(Val);
return total;
}
diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp
index faca9c508c08..c4a1ea40d125 100644
--- a/clang/lib/Basic/Sarif.cpp
+++ b/clang/lib/Basic/Sarif.cpp
@@ -25,6 +25,7 @@
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
+#include <optional>
#include <string>
#include <utility>
@@ -118,8 +119,8 @@ static unsigned int adjustColumnPos(FullSourceLoc Loc,
unsigned int TokenLen = 0) {
assert(!Loc.isInvalid() && "invalid Loc when adjusting column position");
- std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc();
- Optional<MemoryBufferRef> Buf =
+ std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedExpansionLoc();
+ std::optional<MemoryBufferRef> Buf =
Loc.getManager().getBufferOrNone(LocInfo.first);
assert(Buf && "got an invalid buffer for the location's file");
assert(Buf->getBufferSize() >= (LocInfo.second + TokenLen) &&
@@ -149,13 +150,16 @@ json::Object createMessage(StringRef Text) {
/// \pre CharSourceRange must be a token range
static json::Object createTextRegion(const SourceManager &SM,
const CharSourceRange &R) {
- FullSourceLoc FirstTokenLoc{R.getBegin(), SM};
- FullSourceLoc LastTokenLoc{R.getEnd(), SM};
- json::Object Region{{"startLine", FirstTokenLoc.getExpansionLineNumber()},
- {"startColumn", adjustColumnPos(FirstTokenLoc)},
- {"endColumn", adjustColumnPos(LastTokenLoc)}};
- if (FirstTokenLoc != LastTokenLoc) {
- Region["endLine"] = LastTokenLoc.getExpansionLineNumber();
+ FullSourceLoc BeginCharLoc{R.getBegin(), SM};
+ FullSourceLoc EndCharLoc{R.getEnd(), SM};
+ json::Object Region{{"startLine", BeginCharLoc.getExpansionLineNumber()},
+ {"startColumn", adjustColumnPos(BeginCharLoc)}};
+
+ if (BeginCharLoc == EndCharLoc) {
+ Region["endColumn"] = adjustColumnPos(BeginCharLoc);
+ } else {
+ Region["endLine"] = EndCharLoc.getExpansionLineNumber();
+ Region["endColumn"] = adjustColumnPos(EndCharLoc);
}
return Region;
}
@@ -180,6 +184,21 @@ static StringRef importanceToStr(ThreadFlowImportance I) {
llvm_unreachable("Fully covered switch is not so fully covered");
}
+static StringRef resultLevelToStr(SarifResultLevel R) {
+ switch (R) {
+ case SarifResultLevel::None:
+ return "none";
+ case SarifResultLevel::Note:
+ return "note";
+ case SarifResultLevel::Warning:
+ return "warning";
+ case SarifResultLevel::Error:
+ return "error";
+ }
+ llvm_unreachable("Potentially un-handled SarifResultLevel. "
+ "Is the switch not fully covered?");
+}
+
static json::Object
createThreadFlowLocation(json::Object &&Location,
const ThreadFlowImportance &Importance) {
@@ -217,8 +236,10 @@ SarifDocumentWriter::createPhysicalLocation(const CharSourceRange &R) {
}
assert(I != CurrentArtifacts.end() && "Failed to insert new artifact");
const SarifArtifactLocation &Location = I->second.Location;
- uint32_t Idx = Location.Index.value();
- return json::Object{{{"artifactLocation", json::Object{{{"index", Idx}}}},
+ json::Object ArtifactLocationObject{{"uri", Location.URI}};
+ if (Location.Index.has_value())
+ ArtifactLocationObject["index"] = *Location.Index;
+ return json::Object{{{"artifactLocation", std::move(ArtifactLocationObject)},
{"region", createTextRegion(SourceMgr, R)}}};
}
@@ -253,10 +274,15 @@ void SarifDocumentWriter::endRun() {
json::Object &Tool = getCurrentTool();
json::Array Rules;
for (const SarifRule &R : CurrentRules) {
+ json::Object Config{
+ {"enabled", R.DefaultConfiguration.Enabled},
+ {"level", resultLevelToStr(R.DefaultConfiguration.Level)},
+ {"rank", R.DefaultConfiguration.Rank}};
json::Object Rule{
{"name", R.Name},
{"id", R.Id},
- {"fullDescription", json::Object{{"text", R.Description}}}};
+ {"fullDescription", json::Object{{"text", R.Description}}},
+ {"defaultConfiguration", std::move(Config)}};
if (!R.HelpURI.empty())
Rule["helpUri"] = R.HelpURI;
Rules.emplace_back(std::move(Rule));
@@ -271,18 +297,18 @@ void SarifDocumentWriter::endRun() {
const SarifArtifact &A = Pair.getValue();
json::Object Loc{{"uri", A.Location.URI}};
if (A.Location.Index.has_value()) {
- Loc["index"] = static_cast<int64_t>(A.Location.Index.value());
+ Loc["index"] = static_cast<int64_t>(*A.Location.Index);
}
json::Object Artifact;
Artifact["location"] = std::move(Loc);
if (A.Length.has_value())
- Artifact["length"] = static_cast<int64_t>(A.Length.value());
+ Artifact["length"] = static_cast<int64_t>(*A.Length);
if (!A.Roles.empty())
Artifact["roles"] = json::Array(A.Roles);
if (!A.MimeType.empty())
Artifact["mimeType"] = A.MimeType;
if (A.Offset.has_value())
- Artifact["offset"] = A.Offset;
+ Artifact["offset"] = *A.Offset;
Artifacts->push_back(json::Value(std::move(Artifact)));
}
@@ -358,9 +384,12 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
size_t RuleIdx = Result.RuleIdx;
assert(RuleIdx < CurrentRules.size() &&
"Trying to reference a rule that doesn't exist");
+ const SarifRule &Rule = CurrentRules[RuleIdx];
+ assert(Rule.DefaultConfiguration.Enabled &&
+ "Cannot add a result referencing a disabled Rule");
json::Object Ret{{"message", createMessage(Result.DiagnosticMessage)},
{"ruleIndex", static_cast<int64_t>(RuleIdx)},
- {"ruleId", CurrentRules[RuleIdx].Id}};
+ {"ruleId", Rule.Id}};
if (!Result.Locations.empty()) {
json::Array Locs;
for (auto &Range : Result.Locations) {
@@ -370,6 +399,10 @@ void SarifDocumentWriter::appendResult(const SarifResult &Result) {
}
if (!Result.ThreadFlows.empty())
Ret["codeFlows"] = json::Array{createCodeFlow(Result.ThreadFlows)};
+
+ Ret["level"] = resultLevelToStr(
+ Result.LevelOverride.value_or(Rule.DefaultConfiguration.Level));
+
json::Object &Run = getCurrentRun();
json::Array *Results = Run.getArray("results");
Results->emplace_back(std::move(Ret));
diff --git a/clang/lib/Basic/SourceLocation.cpp b/clang/lib/Basic/SourceLocation.cpp
index 6e5e55fb09ce..772f2e612f07 100644
--- a/clang/lib/Basic/SourceLocation.cpp
+++ b/clang/lib/Basic/SourceLocation.cpp
@@ -42,11 +42,11 @@ void PrettyStackTraceLoc::print(raw_ostream &OS) const {
// SourceLocation
//===----------------------------------------------------------------------===//
-static_assert(std::is_trivially_destructible<SourceLocation>::value,
+static_assert(std::is_trivially_destructible_v<SourceLocation>,
"SourceLocation must be trivially destructible because it is "
"used in unions");
-static_assert(std::is_trivially_destructible<SourceRange>::value,
+static_assert(std::is_trivially_destructible_v<SourceRange>,
"SourceRange must be trivially destructible because it is "
"used in unions");
@@ -166,6 +166,10 @@ FullSourceLoc FullSourceLoc::getExpansionLoc() const {
return FullSourceLoc(SrcMgr->getExpansionLoc(*this), *SrcMgr);
}
+std::pair<FileID, unsigned> FullSourceLoc::getDecomposedExpansionLoc() const {
+ return SrcMgr->getDecomposedExpansionLoc(*this);
+}
+
FullSourceLoc FullSourceLoc::getSpellingLoc() const {
assert(isValid());
return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr);
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 98e731eb12e6..3d7a53879584 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -17,8 +17,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -38,6 +37,7 @@
#include <cstddef>
#include <cstdint>
#include <memory>
+#include <optional>
#include <tuple>
#include <utility>
#include <vector>
@@ -98,17 +98,17 @@ const char *ContentCache::getInvalidBOM(StringRef BufStr) {
return InvalidBOM;
}
-llvm::Optional<llvm::MemoryBufferRef>
+std::optional<llvm::MemoryBufferRef>
ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
SourceLocation Loc) const {
// Lazily create the Buffer for ContentCaches that wrap files. If we already
// computed it, just return what we have.
if (IsBufferInvalid)
- return None;
+ return std::nullopt;
if (Buffer)
return Buffer->getMemBufferRef();
if (!ContentsEntry)
- return None;
+ return std::nullopt;
// Start with the assumption that the buffer is invalid to simplify early
// return paths.
@@ -130,7 +130,7 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
Diag.Report(Loc, diag::err_cannot_open_file)
<< ContentsEntry->getName() << BufferOrError.getError().message();
- return None;
+ return std::nullopt;
}
Buffer = std::move(*BufferOrError);
@@ -152,7 +152,7 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
Diag.Report(Loc, diag::err_file_too_large)
<< ContentsEntry->getName();
- return None;
+ return std::nullopt;
}
// Unless this is a named pipe (in which case we can handle a mismatch),
@@ -167,7 +167,7 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
Diag.Report(Loc, diag::err_file_modified)
<< ContentsEntry->getName();
- return None;
+ return std::nullopt;
}
// If the buffer is valid, check to see if it has a UTF Byte Order Mark
@@ -179,7 +179,7 @@ ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
if (InvalidBOM) {
Diag.Report(Loc, diag::err_unsupported_bom)
<< InvalidBOM << ContentsEntry->getName();
- return None;
+ return std::nullopt;
}
// Buffer has been validated.
@@ -399,8 +399,7 @@ ContentCache &SourceManager::getOrCreateContentCache(FileEntryRef FileEnt,
if (OverriddenFilesInfo) {
// If the file contents are overridden with contents from another file,
// pass that file to ContentCache.
- llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
- overI = OverriddenFilesInfo->OverriddenFiles.find(FileEnt);
+ auto overI = OverriddenFilesInfo->OverriddenFiles.find(FileEnt);
if (overI == OverriddenFilesInfo->OverriddenFiles.end())
new (Entry) ContentCache(FileEnt);
else
@@ -455,8 +454,10 @@ SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries,
SourceLocation::UIntTy TotalSize) {
assert(ExternalSLocEntries && "Don't have an external sloc source");
// Make sure we're not about to run out of source locations.
- if (CurrentLoadedOffset - TotalSize < NextLocalOffset)
+ if (CurrentLoadedOffset < TotalSize ||
+ CurrentLoadedOffset - TotalSize < NextLocalOffset) {
return std::make_pair(0, 0);
+ }
LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries);
SLocEntryLoaded.resize(LoadedSLocEntryTable.size());
CurrentLoadedOffset -= TotalSize;
@@ -614,6 +615,7 @@ FileID SourceManager::createFileIDImpl(ContentCache &File, StringRef Filename,
if (!(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset)) {
Diag.Report(IncludePos, diag::err_include_too_large);
+ noteSLocAddressSpaceUsage(Diag);
return FileID();
}
LocalSLocEntryTable.push_back(
@@ -670,6 +672,7 @@ SourceManager::createExpansionLocImpl(const ExpansionInfo &Info,
return SourceLocation::getMacroLoc(LoadedOffset);
}
LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info));
+ // FIXME: Produce a proper diagnostic for this case.
assert(NextLocalOffset + Length + 1 > NextLocalOffset &&
NextLocalOffset + Length + 1 <= CurrentLoadedOffset &&
"Ran out of source locations!");
@@ -678,7 +681,7 @@ SourceManager::createExpansionLocImpl(const ExpansionInfo &Info,
return SourceLocation::getMacroLoc(NextLocalOffset - (Length + 1));
}
-llvm::Optional<llvm::MemoryBufferRef>
+std::optional<llvm::MemoryBufferRef>
SourceManager::getMemoryBufferForFileOrNone(const FileEntry *File) {
SrcMgr::ContentCache &IR = getOrCreateContentCache(File->getLastRef());
return IR.getBufferOrNone(Diag, getFileManager(), SourceLocation());
@@ -695,24 +698,28 @@ void SourceManager::overrideFileContents(
}
void SourceManager::overrideFileContents(const FileEntry *SourceFile,
- const FileEntry *NewFile) {
- assert(SourceFile->getSize() == NewFile->getSize() &&
+ FileEntryRef NewFile) {
+ assert(SourceFile->getSize() == NewFile.getSize() &&
"Different sizes, use the FileManager to create a virtual file with "
"the correct size");
assert(FileInfos.count(SourceFile) == 0 &&
"This function should be called at the initialization stage, before "
"any parsing occurs.");
- getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile;
+ // FileEntryRef is not default-constructible.
+ auto Pair = getOverriddenFilesInfo().OverriddenFiles.insert(
+ std::make_pair(SourceFile, NewFile));
+ if (!Pair.second)
+ Pair.first->second = NewFile;
}
-Optional<FileEntryRef>
+OptionalFileEntryRef
SourceManager::bypassFileContentsOverride(FileEntryRef File) {
assert(isFileOverridden(&File.getFileEntry()));
- llvm::Optional<FileEntryRef> BypassFile = FileMgr.getBypassFile(File);
+ OptionalFileEntryRef BypassFile = FileMgr.getBypassFile(File);
// If the file can't be found in the FS, give up.
if (!BypassFile)
- return None;
+ return std::nullopt;
(void)getOrCreateContentCache(*BypassFile);
return BypassFile;
@@ -722,12 +729,12 @@ void SourceManager::setFileIsTransient(const FileEntry *File) {
getOrCreateContentCache(File->getLastRef()).IsTransient = true;
}
-Optional<StringRef>
+std::optional<StringRef>
SourceManager::getNonBuiltinFilenameForID(FileID FID) const {
if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID))
if (Entry->getFile().getContentCache().OrigEntry)
return Entry->getFile().getName();
- return None;
+ return std::nullopt;
}
StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
@@ -737,19 +744,19 @@ StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
return B ? *B : "<<<<<INVALID SOURCE LOCATION>>>>>";
}
-llvm::Optional<StringRef>
+std::optional<StringRef>
SourceManager::getBufferDataIfLoaded(FileID FID) const {
if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID))
return Entry->getFile().getContentCache().getBufferDataIfLoaded();
- return None;
+ return std::nullopt;
}
-llvm::Optional<StringRef> SourceManager::getBufferDataOrNone(FileID FID) const {
+std::optional<StringRef> SourceManager::getBufferDataOrNone(FileID FID) const {
if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID))
if (auto B = Entry->getFile().getContentCache().getBufferOrNone(
Diag, getFileManager(), SourceLocation()))
return B->getBuffer();
- return None;
+ return std::nullopt;
}
//===----------------------------------------------------------------------===//
@@ -790,24 +797,28 @@ FileID SourceManager::getFileIDLocal(SourceLocation::UIntTy SLocOffset) const {
// See if this is near the file point - worst case we start scanning from the
// most newly created FileID.
- const SrcMgr::SLocEntry *I;
- if (LastFileIDLookup.ID < 0 ||
- LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) {
- // Neither loc prunes our search.
- I = LocalSLocEntryTable.end();
- } else {
- // Perhaps it is near the file point.
- I = LocalSLocEntryTable.begin()+LastFileIDLookup.ID;
+ // LessIndex - This is the lower bound of the range that we're searching.
+ // We know that the offset corresponding to the FileID is less than
+ // SLocOffset.
+ unsigned LessIndex = 0;
+ // upper bound of the search range.
+ unsigned GreaterIndex = LocalSLocEntryTable.size();
+ if (LastFileIDLookup.ID >= 0) {
+ // Use the LastFileIDLookup to prune the search space.
+ if (LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset)
+ LessIndex = LastFileIDLookup.ID;
+ else
+ GreaterIndex = LastFileIDLookup.ID;
}
- // Find the FileID that contains this. "I" is an iterator that points to a
- // FileID whose offset is known to be larger than SLocOffset.
+ // Find the FileID that contains this.
unsigned NumProbes = 0;
while (true) {
- --I;
- if (I->getOffset() <= SLocOffset) {
- FileID Res = FileID::get(int(I - LocalSLocEntryTable.begin()));
+ --GreaterIndex;
+ assert(GreaterIndex < LocalSLocEntryTable.size());
+ if (LocalSLocEntryTable[GreaterIndex].getOffset() <= SLocOffset) {
+ FileID Res = FileID::get(int(GreaterIndex));
// Remember it. We have good locality across FileID lookups.
LastFileIDLookup = Res;
NumLinearScans += NumProbes+1;
@@ -817,13 +828,6 @@ FileID SourceManager::getFileIDLocal(SourceLocation::UIntTy SLocOffset) const {
break;
}
- // Convert "I" back into an index. We know that it is an entry whose index is
- // larger than the offset we are looking for.
- unsigned GreaterIndex = I - LocalSLocEntryTable.begin();
- // LessIndex - This is the lower bound of the range that we're searching.
- // We know that the offset corresponding to the FileID is is less than
- // SLocOffset.
- unsigned LessIndex = 0;
NumProbes = 0;
while (true) {
unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex;
@@ -866,43 +870,46 @@ FileID SourceManager::getFileIDLoaded(SourceLocation::UIntTy SLocOffset) const {
}
// Essentially the same as the local case, but the loaded array is sorted
- // in the other direction.
+ // in the other direction (decreasing order).
+ // GreaterIndex is the one where the offset is greater, which is actually a
+ // lower index!
+ unsigned GreaterIndex = 0;
+ unsigned LessIndex = LoadedSLocEntryTable.size();
+ if (LastFileIDLookup.ID < 0) {
+ // Prune the search space.
+ int LastID = LastFileIDLookup.ID;
+ if (getLoadedSLocEntryByID(LastID).getOffset() > SLocOffset)
+ GreaterIndex =
+ (-LastID - 2) + 1; // Exclude LastID, else we would have hit the cache
+ else
+ LessIndex = -LastID - 2;
+ }
// First do a linear scan from the last lookup position, if possible.
- unsigned I;
- int LastID = LastFileIDLookup.ID;
- if (LastID >= 0 || getLoadedSLocEntryByID(LastID).getOffset() < SLocOffset)
- I = 0;
- else
- I = (-LastID - 2) + 1;
-
unsigned NumProbes;
- for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++I) {
+ bool Invalid = false;
+ for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++GreaterIndex) {
// Make sure the entry is loaded!
- const SrcMgr::SLocEntry &E = getLoadedSLocEntry(I);
+ const SrcMgr::SLocEntry &E = getLoadedSLocEntry(GreaterIndex, &Invalid);
+ if (Invalid)
+ return FileID(); // invalid entry.
if (E.getOffset() <= SLocOffset) {
- FileID Res = FileID::get(-int(I) - 2);
+ FileID Res = FileID::get(-int(GreaterIndex) - 2);
LastFileIDLookup = Res;
NumLinearScans += NumProbes + 1;
return Res;
}
}
- // Linear scan failed. Do the binary search. Note the reverse sorting of the
- // table: GreaterIndex is the one where the offset is greater, which is
- // actually a lower index!
- unsigned GreaterIndex = I;
- unsigned LessIndex = LoadedSLocEntryTable.size();
+ // Linear scan failed. Do the binary search.
NumProbes = 0;
while (true) {
++NumProbes;
unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex;
- const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex);
- if (E.getOffset() == 0)
+ const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex, &Invalid);
+ if (Invalid)
return FileID(); // invalid entry.
- ++NumProbes;
-
if (E.getOffset() > SLocOffset) {
if (GreaterIndex == MiddleIndex) {
assert(0 && "binary search missed the entry");
@@ -1164,7 +1171,7 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
return "<<<<INVALID BUFFER>>>>";
}
- llvm::Optional<llvm::MemoryBufferRef> Buffer =
+ std::optional<llvm::MemoryBufferRef> Buffer =
Entry.getFile().getContentCache().getBufferOrNone(Diag, getFileManager(),
SourceLocation());
if (Invalid)
@@ -1177,7 +1184,7 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
/// this is significantly cheaper to compute than the line number.
unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
bool *Invalid) const {
- llvm::Optional<llvm::MemoryBufferRef> MemBuf = getBufferOrNone(FID);
+ std::optional<llvm::MemoryBufferRef> MemBuf = getBufferOrNone(FID);
if (Invalid)
*Invalid = !MemBuf;
@@ -1273,22 +1280,21 @@ LineOffsetMapping LineOffsetMapping::get(llvm::MemoryBufferRef Buffer,
// Line #1 starts at char 0.
LineOffsets.push_back(0);
- const unsigned char *Buf = (const unsigned char *)Buffer.getBufferStart();
+ const unsigned char *Start = (const unsigned char *)Buffer.getBufferStart();
const unsigned char *End = (const unsigned char *)Buffer.getBufferEnd();
- const std::size_t BufLen = End - Buf;
+ const unsigned char *Buf = Start;
- unsigned I = 0;
uint64_t Word;
// scan sizeof(Word) bytes at a time for new lines.
// This is much faster than scanning each byte independently.
- if (BufLen > sizeof(Word)) {
+ if ((unsigned long)(End - Start) > sizeof(Word)) {
do {
- Word = llvm::support::endian::read64(Buf + I, llvm::support::little);
+ Word = llvm::support::endian::read64(Buf, llvm::support::little);
// no new line => jump over sizeof(Word) bytes.
auto Mask = likelyhasbetween(Word, '\n', '\r');
if (!Mask) {
- I += sizeof(Word);
+ Buf += sizeof(Word);
continue;
}
@@ -1299,30 +1305,33 @@ LineOffsetMapping LineOffsetMapping::get(llvm::MemoryBufferRef Buffer,
unsigned N =
llvm::countTrailingZeros(Mask) - 7; // -7 because 0x80 is the marker
Word >>= N;
- I += N / 8 + 1;
+ Buf += N / 8 + 1;
unsigned char Byte = Word;
- if (Byte == '\n') {
- LineOffsets.push_back(I);
- } else if (Byte == '\r') {
+ switch (Byte) {
+ case '\r':
// If this is \r\n, skip both characters.
- if (Buf[I] == '\n')
- ++I;
- LineOffsets.push_back(I);
- }
- } while (I < BufLen - sizeof(Word) - 1);
+ if (*Buf == '\n') {
+ ++Buf;
+ }
+ LLVM_FALLTHROUGH;
+ case '\n':
+ LineOffsets.push_back(Buf - Start);
+ };
+ } while (Buf < End - sizeof(Word) - 1);
}
// Handle tail using a regular check.
- while (I < BufLen) {
- if (Buf[I] == '\n') {
- LineOffsets.push_back(I + 1);
- } else if (Buf[I] == '\r') {
+ while (Buf < End) {
+ if (*Buf == '\n') {
+ LineOffsets.push_back(Buf - Start + 1);
+ } else if (*Buf == '\r') {
// If this is \r\n, skip both characters.
- if (I + 1 < BufLen && Buf[I + 1] == '\n')
- ++I;
- LineOffsets.push_back(I + 1);
+ if (Buf + 1 < End && Buf[1] == '\n') {
+ ++Buf;
+ }
+ LineOffsets.push_back(Buf - Start + 1);
}
- ++I;
+ ++Buf;
}
return LineOffsetMapping(LineOffsets, Alloc);
@@ -1365,7 +1374,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
if (!Content->SourceLineCache) {
- llvm::Optional<llvm::MemoryBufferRef> Buffer =
+ std::optional<llvm::MemoryBufferRef> Buffer =
Content->getBufferOrNone(Diag, getFileManager(), SourceLocation());
if (Invalid)
*Invalid = !Buffer;
@@ -1715,7 +1724,7 @@ SourceLocation SourceManager::translateLineCol(FileID FID,
// If this is the first use of line information for this buffer, compute the
// SourceLineCache for it on demand.
- llvm::Optional<llvm::MemoryBufferRef> Buffer =
+ std::optional<llvm::MemoryBufferRef> Buffer =
Content->getBufferOrNone(Diag, getFileManager());
if (!Buffer)
return SourceLocation();
@@ -1792,11 +1801,11 @@ void SourceManager::computeMacroArgsCache(MacroArgsMap &MacroArgsCache,
if (Entry.getFile().NumCreatedFIDs)
ID += Entry.getFile().NumCreatedFIDs - 1 /*because of next ++ID*/;
continue;
- } else if (IncludeLoc.isValid()) {
- // If file was included but not from FID, there is no more files/macros
- // that may be "contained" in this file.
- return;
}
+ // If file was included but not from FID, there is no more files/macros
+ // that may be "contained" in this file.
+ if (IncludeLoc.isValid())
+ return;
continue;
}
@@ -1989,6 +1998,7 @@ InBeforeInTUCacheEntry &SourceManager::getInBeforeInTUCache(FileID LFID,
// This is a magic number for limiting the cache size. It was experimentally
// derived from a small Objective-C project (where the cache filled
// out to ~250 items). We can make it larger if necessary.
+ // FIXME: this is almost certainly full these days. Use an LRU cache?
enum { MagicCacheSize = 300 };
IsBeforeInTUCacheKey Key(LFID, RFID);
@@ -1997,7 +2007,7 @@ InBeforeInTUCacheEntry &SourceManager::getInBeforeInTUCache(FileID LFID,
// use. When they update the value, the cache will get automatically
// updated as well.
if (IBTUCache.size() < MagicCacheSize)
- return IBTUCache[Key];
+ return IBTUCache.try_emplace(Key, LFID, RFID).first->second;
// Otherwise, do a lookup that will not construct a new value.
InBeforeInTUCache::iterator I = IBTUCache.find(Key);
@@ -2005,6 +2015,7 @@ InBeforeInTUCacheEntry &SourceManager::getInBeforeInTUCache(FileID LFID,
return I->second;
// Fall back to the overflow value.
+ IBTUCacheOverflow.setQueryFIDs(LFID, RFID);
return IBTUCacheOverflow;
}
@@ -2079,43 +2090,63 @@ std::pair<bool, bool> SourceManager::isInTheSameTranslationUnit(
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
- if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first))
+ if (IsBeforeInTUCache.isCacheValid())
return std::make_pair(
true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
- // Okay, we missed in the cache, start updating the cache for this query.
- IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first,
- /*isLFIDBeforeRFID=*/LOffs.first.ID < ROffs.first.ID);
-
+ // Okay, we missed in the cache, we'll compute the answer and populate it.
// We need to find the common ancestor. The only way of doing this is to
// build the complete include chain for one and then walking up the chain
// of the other looking for a match.
- // We use a map from FileID to Offset to store the chain. Easier than writing
- // a custom set hash info that only depends on the first part of a pair.
- using LocSet = llvm::SmallDenseMap<FileID, unsigned, 16>;
- LocSet LChain;
+
+ // A location within a FileID on the path up from LOffs to the main file.
+ struct Entry {
+ unsigned Offset;
+ FileID ParentFID; // Used for breaking ties.
+ };
+ llvm::SmallDenseMap<FileID, Entry, 16> LChain;
+
+ FileID Parent;
do {
- LChain.insert(LOffs);
+ LChain.try_emplace(LOffs.first, Entry{LOffs.second, Parent});
// We catch the case where LOffs is in a file included by ROffs and
// quit early. The other way round unfortunately remains suboptimal.
- } while (LOffs.first != ROffs.first && !MoveUpIncludeHierarchy(LOffs, *this));
- LocSet::iterator I;
- while((I = LChain.find(ROffs.first)) == LChain.end()) {
- if (MoveUpIncludeHierarchy(ROffs, *this))
- break; // Met at topmost file.
- }
- if (I != LChain.end())
- LOffs = *I;
+ if (LOffs.first == ROffs.first)
+ break;
+ Parent = LOffs.first;
+ } while (!MoveUpIncludeHierarchy(LOffs, *this));
- // If we exited because we found a nearest common ancestor, compare the
- // locations within the common file and cache them.
- if (LOffs.first == ROffs.first) {
- IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second);
- return std::make_pair(
- true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
- }
- // Clear the lookup cache, it depends on a common location.
- IsBeforeInTUCache.clear();
+ Parent = FileID();
+ do {
+ auto I = LChain.find(ROffs.first);
+ if (I != LChain.end()) {
+ // Compare the locations within the common file and cache them.
+ LOffs.first = I->first;
+ LOffs.second = I->second.Offset;
+ // The relative order of LParent and RParent is a tiebreaker when
+ // - locs expand to the same location (occurs in macro arg expansion)
+ // - one loc is a parent of the other (we consider the parent as "first")
+ // For the parent to be first, the invalid file ID must compare smaller.
+ // However loaded FileIDs are <0, so we perform *unsigned* comparison!
+ // This changes the relative order of local vs loaded FileIDs, but it
+ // doesn't matter as these are never mixed in macro expansion.
+ unsigned LParent = I->second.ParentFID.ID;
+ unsigned RParent = Parent.ID;
+ assert(((LOffs.second != ROffs.second) ||
+ (LParent == 0 || RParent == 0) ||
+ isInSameSLocAddrSpace(getComposedLoc(I->second.ParentFID, 0),
+ getComposedLoc(Parent, 0), nullptr)) &&
+ "Mixed local/loaded FileIDs with same include location?");
+ IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second,
+ LParent < RParent);
+ return std::make_pair(
+ true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second));
+ }
+ Parent = ROffs.first;
+ } while (!MoveUpIncludeHierarchy(ROffs, *this));
+
+ // If we found no match, we're not in the same TU.
+ // We don't cache this, but it is rare.
return std::make_pair(false, false);
}
@@ -2151,7 +2182,7 @@ LLVM_DUMP_METHOD void SourceManager::dump() const {
llvm::raw_ostream &out = llvm::errs();
auto DumpSLocEntry = [&](int ID, const SrcMgr::SLocEntry &Entry,
- llvm::Optional<SourceLocation::UIntTy> NextStart) {
+ std::optional<SourceLocation::UIntTy> NextStart) {
out << "SLocEntry <FileID " << ID << "> " << (Entry.isFile() ? "file" : "expansion")
<< " <SourceLocation " << Entry.getOffset() << ":";
if (NextStart)
@@ -2191,15 +2222,103 @@ LLVM_DUMP_METHOD void SourceManager::dump() const {
: LocalSLocEntryTable[ID + 1].getOffset());
}
// Dump loaded SLocEntries.
- llvm::Optional<SourceLocation::UIntTy> NextStart;
+ std::optional<SourceLocation::UIntTy> NextStart;
for (unsigned Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) {
int ID = -(int)Index - 2;
if (SLocEntryLoaded[Index]) {
DumpSLocEntry(ID, LoadedSLocEntryTable[Index], NextStart);
NextStart = LoadedSLocEntryTable[Index].getOffset();
} else {
- NextStart = None;
+ NextStart = std::nullopt;
+ }
+ }
+}
+
+void SourceManager::noteSLocAddressSpaceUsage(
+ DiagnosticsEngine &Diag, std::optional<unsigned> MaxNotes) const {
+ struct Info {
+ // A location where this file was entered.
+ SourceLocation Loc;
+ // Number of times this FileEntry was entered.
+ unsigned Inclusions = 0;
+ // Size usage from the file itself.
+ uint64_t DirectSize = 0;
+ // Total size usage from the file and its macro expansions.
+ uint64_t TotalSize = 0;
+ };
+ using UsageMap = llvm::MapVector<const FileEntry*, Info>;
+
+ UsageMap Usage;
+ uint64_t CountedSize = 0;
+
+ auto AddUsageForFileID = [&](FileID ID) {
+ // The +1 here is because getFileIDSize doesn't include the extra byte for
+ // the one-past-the-end location.
+ unsigned Size = getFileIDSize(ID) + 1;
+
+ // Find the file that used this address space, either directly or by
+ // macro expansion.
+ SourceLocation FileStart = getFileLoc(getComposedLoc(ID, 0));
+ FileID FileLocID = getFileID(FileStart);
+ const FileEntry *Entry = getFileEntryForID(FileLocID);
+
+ Info &EntryInfo = Usage[Entry];
+ if (EntryInfo.Loc.isInvalid())
+ EntryInfo.Loc = FileStart;
+ if (ID == FileLocID) {
+ ++EntryInfo.Inclusions;
+ EntryInfo.DirectSize += Size;
}
+ EntryInfo.TotalSize += Size;
+ CountedSize += Size;
+ };
+
+ // Loaded SLocEntries have indexes counting downwards from -2.
+ for (size_t Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) {
+ AddUsageForFileID(FileID::get(-2 - Index));
+ }
+ // Local SLocEntries have indexes counting upwards from 0.
+ for (size_t Index = 0; Index != LocalSLocEntryTable.size(); ++Index) {
+ AddUsageForFileID(FileID::get(Index));
+ }
+
+ // Sort the usage by size from largest to smallest. Break ties by raw source
+ // location.
+ auto SortedUsage = Usage.takeVector();
+ auto Cmp = [](const UsageMap::value_type &A, const UsageMap::value_type &B) {
+ return A.second.TotalSize > B.second.TotalSize ||
+ (A.second.TotalSize == B.second.TotalSize &&
+ A.second.Loc < B.second.Loc);
+ };
+ auto SortedEnd = SortedUsage.end();
+ if (MaxNotes && SortedUsage.size() > *MaxNotes) {
+ SortedEnd = SortedUsage.begin() + *MaxNotes;
+ std::nth_element(SortedUsage.begin(), SortedEnd, SortedUsage.end(), Cmp);
+ }
+ std::sort(SortedUsage.begin(), SortedEnd, Cmp);
+
+ // Produce note on sloc address space usage total.
+ uint64_t LocalUsage = NextLocalOffset;
+ uint64_t LoadedUsage = MaxLoadedOffset - CurrentLoadedOffset;
+ int UsagePercent = static_cast<int>(100.0 * double(LocalUsage + LoadedUsage) /
+ MaxLoadedOffset);
+ Diag.Report(SourceLocation(), diag::note_total_sloc_usage)
+ << LocalUsage << LoadedUsage << (LocalUsage + LoadedUsage) << UsagePercent;
+
+ // Produce notes on sloc address space usage for each file with a high usage.
+ uint64_t ReportedSize = 0;
+ for (auto &[Entry, FileInfo] :
+ llvm::make_range(SortedUsage.begin(), SortedEnd)) {
+ Diag.Report(FileInfo.Loc, diag::note_file_sloc_usage)
+ << FileInfo.Inclusions << FileInfo.DirectSize
+ << (FileInfo.TotalSize - FileInfo.DirectSize);
+ ReportedSize += FileInfo.TotalSize;
+ }
+
+ // Describe any remaining usage not reported in the per-file usage.
+ if (ReportedSize != CountedSize) {
+ Diag.Report(SourceLocation(), diag::note_file_misc_sloc_usage)
+ << (SortedUsage.end() - SortedEnd) << CountedSize - ReportedSize;
}
}
diff --git a/clang/lib/Basic/Stack.cpp b/clang/lib/Basic/Stack.cpp
index 5e4750931500..aa15d8e66950 100644
--- a/clang/lib/Basic/Stack.cpp
+++ b/clang/lib/Basic/Stack.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Stack.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/CrashRecoveryContext.h"
#ifdef _MSC_VER
diff --git a/clang/lib/Basic/TargetID.cpp b/clang/lib/Basic/TargetID.cpp
index abfbe49e1a91..7cc4d67e3a52 100644
--- a/clang/lib/Basic/TargetID.cpp
+++ b/clang/lib/Basic/TargetID.cpp
@@ -12,6 +12,7 @@
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
+#include <optional>
namespace clang {
@@ -62,7 +63,7 @@ llvm::StringRef getProcessorFromTargetID(const llvm::Triple &T,
// A target ID is a processor name followed by a list of target features
// delimited by colon. Each target feature is a string post-fixed by a plus
// or minus sign, e.g. gfx908:sramecc+:xnack-.
-static llvm::Optional<llvm::StringRef>
+static std::optional<llvm::StringRef>
parseTargetIDWithFormatCheckingOnly(llvm::StringRef TargetID,
llvm::StringMap<bool> *FeatureMap) {
llvm::StringRef Processor;
@@ -73,7 +74,7 @@ parseTargetIDWithFormatCheckingOnly(llvm::StringRef TargetID,
auto Split = TargetID.split(':');
Processor = Split.first;
if (Processor.empty())
- return llvm::None;
+ return std::nullopt;
auto Features = Split.second;
if (Features.empty())
@@ -88,30 +89,30 @@ parseTargetIDWithFormatCheckingOnly(llvm::StringRef TargetID,
auto Sign = Splits.first.back();
auto Feature = Splits.first.drop_back();
if (Sign != '+' && Sign != '-')
- return llvm::None;
+ return std::nullopt;
bool IsOn = Sign == '+';
auto Loc = FeatureMap->find(Feature);
// Each feature can only show up at most once in target ID.
if (Loc != FeatureMap->end())
- return llvm::None;
+ return std::nullopt;
(*FeatureMap)[Feature] = IsOn;
Features = Splits.second;
}
return Processor;
}
-llvm::Optional<llvm::StringRef>
+std::optional<llvm::StringRef>
parseTargetID(const llvm::Triple &T, llvm::StringRef TargetID,
llvm::StringMap<bool> *FeatureMap) {
auto OptionalProcessor =
parseTargetIDWithFormatCheckingOnly(TargetID, FeatureMap);
if (!OptionalProcessor)
- return llvm::None;
+ return std::nullopt;
llvm::StringRef Processor = getCanonicalProcessorName(T, *OptionalProcessor);
if (Processor.empty())
- return llvm::None;
+ return std::nullopt;
llvm::SmallSet<llvm::StringRef, 4> AllFeatures;
for (auto &&F : getAllPossibleTargetIDFeatures(T, Processor))
@@ -119,7 +120,7 @@ parseTargetID(const llvm::Triple &T, llvm::StringRef TargetID,
for (auto &&F : *FeatureMap)
if (!AllFeatures.count(F.first()))
- return llvm::None;
+ return std::nullopt;
return Processor;
}
@@ -140,7 +141,7 @@ std::string getCanonicalTargetID(llvm::StringRef Processor,
// For a specific processor, a feature either shows up in all target IDs, or
// does not show up in any target IDs. Otherwise the target ID combination
// is invalid.
-llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictTargetIDCombination(const std::set<llvm::StringRef> &TargetIDs) {
struct Info {
llvm::StringRef TargetID;
@@ -161,7 +162,28 @@ getConflictTargetIDCombination(const std::set<llvm::StringRef> &TargetIDs) {
return std::make_pair(Loc->second.TargetID, ID);
}
}
- return llvm::None;
+ return std::nullopt;
+}
+
+bool isCompatibleTargetID(llvm::StringRef Provided, llvm::StringRef Requested) {
+ llvm::StringMap<bool> ProvidedFeatures, RequestedFeatures;
+ llvm::StringRef ProvidedProc =
+ *parseTargetIDWithFormatCheckingOnly(Provided, &ProvidedFeatures);
+ llvm::StringRef RequestedProc =
+ *parseTargetIDWithFormatCheckingOnly(Requested, &RequestedFeatures);
+ if (ProvidedProc != RequestedProc)
+ return false;
+ for (const auto &F : ProvidedFeatures) {
+ auto Loc = RequestedFeatures.find(F.first());
+ // The default (unspecified) value of a feature is 'All', which can match
+ // either 'On' or 'Off'.
+ if (Loc == RequestedFeatures.end())
+ return false;
+ // If a feature is specified, it must have exact match.
+ if (Loc->second != F.second)
+ return false;
+ }
+ return true;
}
} // namespace clang
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index 6685145ea6d2..8ee43261fc1d 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -14,6 +14,7 @@
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
@@ -23,6 +24,30 @@
using namespace clang;
static const LangASMap DefaultAddrSpaceMap = {0};
+// The fake address space map must have a distinct entry for each
+// language-specific address space.
+static const LangASMap FakeAddrSpaceMap = {
+ 0, // Default
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // opencl_private
+ 4, // opencl_generic
+ 5, // opencl_global_device
+ 6, // opencl_global_host
+ 7, // cuda_device
+ 8, // cuda_constant
+ 9, // cuda_shared
+ 1, // sycl_global
+ 5, // sycl_global_device
+ 6, // sycl_global_host
+ 3, // sycl_local
+ 0, // sycl_private
+ 10, // ptr32_sptr
+ 11, // ptr32_uptr
+ 12, // ptr64
+ 13, // hlsl_groupshared
+};
// TargetInfo Constructor.
TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
@@ -33,6 +58,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
VLASupported = true;
NoAsmVariants = false;
HasLegalHalfType = false;
+ HalfArgsAndReturns = false;
HasFloat128 = false;
HasIbm128 = false;
HasFloat16 = false;
@@ -45,6 +71,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
LongLongWidth = LongLongAlign = 64;
+ Int128Align = 128;
// Fixed point default bit widths
ShortAccumWidth = ShortAccumAlign = 16;
@@ -152,8 +179,6 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) {
MaxOpenCLWorkGroupSize = 1024;
MaxBitIntWidth.reset();
-
- ProgramAddrSpace = 0;
}
// Out of line virtual dtor for TargetInfo.
@@ -207,11 +232,11 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) const {
case UnsignedChar:
if (getCharWidth() < getIntWidth())
return "";
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case UnsignedShort:
if (getShortWidth() < getIntWidth())
return "";
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case UnsignedInt: return "U";
case UnsignedLong: return "UL";
case UnsignedLongLong: return "ULL";
@@ -485,7 +510,10 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
}
if (Opts.MaxBitIntWidth)
- MaxBitIntWidth = Opts.MaxBitIntWidth;
+ MaxBitIntWidth = static_cast<unsigned>(Opts.MaxBitIntWidth);
+
+ if (Opts.FakeAddressSpaceMap)
+ AddrSpaceMap = &FakeAddrSpaceMap;
}
bool TargetInfo::initFeatureMap(
@@ -493,13 +521,61 @@ bool TargetInfo::initFeatureMap(
const std::vector<std::string> &FeatureVec) const {
for (const auto &F : FeatureVec) {
StringRef Name = F;
+ if (Name.empty())
+ continue;
// Apply the feature via the target.
- bool Enabled = Name[0] == '+';
- setFeatureEnabled(Features, Name.substr(1), Enabled);
+ if (Name[0] != '+' && Name[0] != '-')
+ Diags.Report(diag::warn_fe_backend_invalid_feature_flag) << Name;
+ else
+ setFeatureEnabled(Features, Name.substr(1), Name[0] == '+');
}
return true;
}
+ParsedTargetAttr TargetInfo::parseTargetAttr(StringRef Features) const {
+ ParsedTargetAttr Ret;
+ if (Features == "default")
+ return Ret;
+ SmallVector<StringRef, 1> AttrFeatures;
+ Features.split(AttrFeatures, ",");
+
+ // Grab the various features and prepend a "+" to turn on the feature to
+ // the backend and add them to our existing set of features.
+ for (auto &Feature : AttrFeatures) {
+ // Go ahead and trim whitespace rather than either erroring or
+ // accepting it weirdly.
+ Feature = Feature.trim();
+
+ // TODO: Support the fpmath option. It will require checking
+ // overall feature validity for the function with the rest of the
+ // attributes on the function.
+ if (Feature.startswith("fpmath="))
+ continue;
+
+ if (Feature.startswith("branch-protection=")) {
+ Ret.BranchProtection = Feature.split('=').second.trim();
+ continue;
+ }
+
+ // While we're here iterating check for a different target cpu.
+ if (Feature.startswith("arch=")) {
+ if (!Ret.CPU.empty())
+ Ret.Duplicate = "arch=";
+ else
+ Ret.CPU = Feature.split("=").second.trim();
+ } else if (Feature.startswith("tune=")) {
+ if (!Ret.Tune.empty())
+ Ret.Duplicate = "tune=";
+ else
+ Ret.Tune = Feature.split("=").second.trim();
+ } else if (Feature.startswith("no-"))
+ Ret.Features.push_back("-" + Feature.split("-").second.str());
+ else
+ Ret.Features.push_back("+" + Feature.str());
+ }
+ return Ret;
+}
+
TargetInfo::CallingConvKind
TargetInfo::getCallingConvKind(bool ClangABICompat4) const {
if (getCXXABI() != TargetCXXABI::Microsoft &&
@@ -508,6 +584,10 @@ TargetInfo::getCallingConvKind(bool ClangABICompat4) const {
return CCK_Default;
}
+bool TargetInfo::areDefaultedSMFStillPOD(const LangOptions &LangOpts) const {
+ return LangOpts.getClangABICompat() > LangOptions::ClangABI::Ver15;
+}
+
LangAS TargetInfo::getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const {
switch (TK) {
case OCLTK_Image:
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index 2d6ef998485a..8400774db93d 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -24,6 +24,7 @@
#include "Targets/Hexagon.h"
#include "Targets/Lanai.h"
#include "Targets/Le64.h"
+#include "Targets/LoongArch.h"
#include "Targets/M68k.h"
#include "Targets/MSP430.h"
#include "Targets/Mips.h"
@@ -80,9 +81,10 @@ void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName, bool Tuning) {
void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) {
// Mingw and cygwin define __declspec(a) to __attribute__((a)). Clang
- // supports __declspec natively under -fms-extensions, but we define a no-op
- // __declspec macro anyway for pre-processor compatibility.
- if (Opts.MicrosoftExt)
+ // supports __declspec natively under -fdeclspec (also enabled with
+ // -fms-extensions), but we define a no-op __declspec macro anyway for
+ // pre-processor compatibility.
+ if (Opts.DeclSpecKeyword)
Builder.defineMacro("__declspec", "__declspec");
else
Builder.defineMacro("__declspec(a)", "__attribute__((a))");
@@ -670,6 +672,20 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple,
default:
return new CSKYTargetInfo(Triple, Opts);
}
+ case llvm::Triple::loongarch32:
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<LoongArch32TargetInfo>(Triple, Opts);
+ default:
+ return new LoongArch32TargetInfo(Triple, Opts);
+ }
+ case llvm::Triple::loongarch64:
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<LoongArch64TargetInfo>(Triple, Opts);
+ default:
+ return new LoongArch64TargetInfo(Triple, Opts);
+ }
}
}
} // namespace targets
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 60ef52ac3f0d..dfed95f0513f 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -18,46 +18,106 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/AArch64TargetParser.h"
+#include "llvm/Support/ARMTargetParserCommon.h"
+#include <optional>
using namespace clang;
using namespace clang::targets;
-const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsNEON.def"
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsSVE.def"
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \
- {#ID, TYPE, ATTRS, nullptr, LANG, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANG},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
- {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS},
#include "clang/Basic/BuiltinsAArch64.def"
};
-static StringRef getArchVersionString(llvm::AArch64::ArchKind Kind) {
- switch (Kind) {
- case llvm::AArch64::ArchKind::ARMV9A:
- case llvm::AArch64::ArchKind::ARMV9_1A:
- case llvm::AArch64::ArchKind::ARMV9_2A:
- case llvm::AArch64::ArchKind::ARMV9_3A:
- return "9";
- default:
- return "8";
- }
-}
-
-StringRef AArch64TargetInfo::getArchProfile() const {
- switch (ArchKind) {
- case llvm::AArch64::ArchKind::ARMV8R:
- return "R";
- default:
- return "A";
+void AArch64TargetInfo::setArchFeatures() {
+ if (*ArchInfo == llvm::AArch64::ARMV8R) {
+ HasDotProd = true;
+ HasDIT = true;
+ HasFlagM = true;
+ HasRCPC = true;
+ FPU |= NeonMode;
+ HasCCPP = true;
+ HasCRC = true;
+ HasLSE = true;
+ HasRDM = true;
+ } else if (ArchInfo->Version.getMajor() == 8) {
+ if (ArchInfo->Version.getMinor() >= 7u) {
+ HasWFxT = true;
+ }
+ if (ArchInfo->Version.getMinor() >= 6u) {
+ HasBFloat16 = true;
+ HasMatMul = true;
+ }
+ if (ArchInfo->Version.getMinor() >= 5u) {
+ HasAlternativeNZCV = true;
+ HasFRInt3264 = true;
+ HasSSBS = true;
+ HasSB = true;
+ HasPredRes = true;
+ HasBTI = true;
+ }
+ if (ArchInfo->Version.getMinor() >= 4u) {
+ HasDotProd = true;
+ HasDIT = true;
+ HasFlagM = true;
+ }
+ if (ArchInfo->Version.getMinor() >= 3u) {
+ HasRCPC = true;
+ FPU |= NeonMode;
+ }
+ if (ArchInfo->Version.getMinor() >= 2u) {
+ HasCCPP = true;
+ }
+ if (ArchInfo->Version.getMinor() >= 1u) {
+ HasCRC = true;
+ HasLSE = true;
+ HasRDM = true;
+ }
+ } else if (ArchInfo->Version.getMajor() == 9) {
+ if (ArchInfo->Version.getMinor() >= 2u) {
+ HasWFxT = true;
+ }
+ if (ArchInfo->Version.getMinor() >= 1u) {
+ HasBFloat16 = true;
+ HasMatMul = true;
+ }
+ FPU |= SveMode;
+ HasSVE2 = true;
+ HasFullFP16 = true;
+ HasAlternativeNZCV = true;
+ HasFRInt3264 = true;
+ HasSSBS = true;
+ HasSB = true;
+ HasPredRes = true;
+ HasBTI = true;
+ HasDotProd = true;
+ HasDIT = true;
+ HasFlagM = true;
+ HasRCPC = true;
+ FPU |= NeonMode;
+ HasCCPP = true;
+ HasCRC = true;
+ HasLSE = true;
+ HasRDM = true;
}
}
@@ -77,7 +137,9 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
// All AArch64 implementations support ARMv8 FP, which makes half a legal type.
HasLegalHalfType = true;
+ HalfArgsAndReturns = true;
HasFloat16 = true;
+ HasStrictFP = true;
if (Triple.isArch64Bit())
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
@@ -162,7 +224,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
bool AArch64TargetInfo::isValidCPUName(StringRef Name) const {
return Name == "generic" ||
- llvm::AArch64::parseCPUArch(Name) != llvm::AArch64::ArchKind::INVALID;
+ llvm::AArch64::parseCpu(Name).Arch != llvm::AArch64::INVALID;
}
bool AArch64TargetInfo::setCPU(const std::string &Name) {
@@ -191,6 +253,7 @@ void AArch64TargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1");
Builder.defineMacro("__ARM_FEATURE_JCVT", "1");
+ Builder.defineMacro("__ARM_FEATURE_PAUTH", "1");
// Also include the Armv8.2 defines
getTargetDefinesARMV82A(Opts, Builder);
}
@@ -204,6 +267,7 @@ void AArch64TargetInfo::getTargetDefinesARMV84A(const LangOptions &Opts,
void AArch64TargetInfo::getTargetDefinesARMV85A(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__ARM_FEATURE_FRINT", "1");
+ Builder.defineMacro("__ARM_FEATURE_BTI", "1");
// Also include the Armv8.4 defines
getTargetDefinesARMV84A(Opts, Builder);
}
@@ -230,6 +294,12 @@ void AArch64TargetInfo::getTargetDefinesARMV88A(const LangOptions &Opts,
getTargetDefinesARMV87A(Opts, Builder);
}
+void AArch64TargetInfo::getTargetDefinesARMV89A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Also include the Armv8.8 defines
+ getTargetDefinesARMV88A(Opts, Builder);
+}
+
void AArch64TargetInfo::getTargetDefinesARMV9A(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Armv9-A maps to Armv8.5-A
@@ -254,6 +324,12 @@ void AArch64TargetInfo::getTargetDefinesARMV93A(const LangOptions &Opts,
getTargetDefinesARMV88A(Opts, Builder);
}
+void AArch64TargetInfo::getTargetDefinesARMV94A(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // Armv9.4-A maps to Armv8.9-A
+ getTargetDefinesARMV89A(Opts, Builder);
+}
+
void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
@@ -278,8 +354,10 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
// ACLE predefines. Many can only have one possible value on v8 AArch64.
Builder.defineMacro("__ARM_ACLE", "200");
- Builder.defineMacro("__ARM_ARCH", getArchVersionString(ArchKind));
- Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + getArchProfile() + "'");
+ Builder.defineMacro("__ARM_ARCH",
+ std::to_string(ArchInfo->Version.getMajor()));
+ Builder.defineMacro("__ARM_ARCH_PROFILE",
+ std::string("'") + (char)ArchInfo->Profile + "'");
Builder.defineMacro("__ARM_64BIT_STATE", "1");
Builder.defineMacro("__ARM_PCS_AAPCS64", "1");
@@ -341,6 +419,12 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasCRC)
Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
+ if (HasRCPC)
+ Builder.defineMacro("__ARM_FEATURE_RCPC", "1");
+
+ if (HasFMV)
+ Builder.defineMacro("__HAVE_FUNCTION_MULTI_VERSIONING", "1");
+
// The __ARM_FEATURE_CRYPTO is deprecated in favor of finer grained feature
// macros for AES, SHA2, SHA3 and SM4
if (HasAES && HasSHA2)
@@ -362,6 +446,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__ARM_FEATURE_SM4", "1");
}
+ if (HasPAuth)
+ Builder.defineMacro("__ARM_FEATURE_PAUTH", "1");
+
if (HasUnaligned)
Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1");
@@ -438,46 +525,37 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasMOPS)
Builder.defineMacro("__ARM_FEATURE_MOPS", "1");
- switch (ArchKind) {
- default:
- break;
- case llvm::AArch64::ArchKind::ARMV8_1A:
+ if (HasD128)
+ Builder.defineMacro("__ARM_FEATURE_SYSREG128", "1");
+
+ if (*ArchInfo == llvm::AArch64::ARMV8_1A)
getTargetDefinesARMV81A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV8_2A:
+ else if (*ArchInfo == llvm::AArch64::ARMV8_2A)
getTargetDefinesARMV82A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV8_3A:
+ else if (*ArchInfo == llvm::AArch64::ARMV8_3A)
getTargetDefinesARMV83A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV8_4A:
+ else if (*ArchInfo == llvm::AArch64::ARMV8_4A)
getTargetDefinesARMV84A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV8_5A:
+ else if (*ArchInfo == llvm::AArch64::ARMV8_5A)
getTargetDefinesARMV85A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV8_6A:
+ else if (*ArchInfo == llvm::AArch64::ARMV8_6A)
getTargetDefinesARMV86A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV8_7A:
+ else if (*ArchInfo == llvm::AArch64::ARMV8_7A)
getTargetDefinesARMV87A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV8_8A:
+ else if (*ArchInfo == llvm::AArch64::ARMV8_8A)
getTargetDefinesARMV88A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV9A:
+ else if (*ArchInfo == llvm::AArch64::ARMV8_9A)
+ getTargetDefinesARMV89A(Opts, Builder);
+ else if (*ArchInfo == llvm::AArch64::ARMV9A)
getTargetDefinesARMV9A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV9_1A:
+ else if (*ArchInfo == llvm::AArch64::ARMV9_1A)
getTargetDefinesARMV91A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV9_2A:
+ else if (*ArchInfo == llvm::AArch64::ARMV9_2A)
getTargetDefinesARMV92A(Opts, Builder);
- break;
- case llvm::AArch64::ArchKind::ARMV9_3A:
+ else if (*ArchInfo == llvm::AArch64::ARMV9_3A)
getTargetDefinesARMV93A(Opts, Builder);
- break;
- }
+ else if (*ArchInfo == llvm::AArch64::ARMV9_4A)
+ getTargetDefinesARMV94A(Opts, Builder);
// All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work.
Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
@@ -489,18 +567,21 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__FP_FAST_FMA", "1");
Builder.defineMacro("__FP_FAST_FMAF", "1");
+ // C/C++ operators work on both VLS and VLA SVE types
+ if (FPU & SveMode)
+ Builder.defineMacro("__ARM_FEATURE_SVE_VECTOR_OPERATORS", "2");
+
if (Opts.VScaleMin && Opts.VScaleMin == Opts.VScaleMax) {
Builder.defineMacro("__ARM_FEATURE_SVE_BITS", Twine(Opts.VScaleMin * 128));
- Builder.defineMacro("__ARM_FEATURE_SVE_VECTOR_OPERATORS");
}
}
ArrayRef<Builtin::Info> AArch64TargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
}
-Optional<std::pair<unsigned, unsigned>>
+std::optional<std::pair<unsigned, unsigned>>
AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
if (LangOpts.VScaleMin || LangOpts.VScaleMax)
return std::pair<unsigned, unsigned>(
@@ -509,140 +590,311 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
if (hasFeature("sve"))
return std::pair<unsigned, unsigned>(1, 16);
- return None;
+ return std::nullopt;
+}
+
+unsigned AArch64TargetInfo::multiVersionSortPriority(StringRef Name) const {
+ if (Name == "default")
+ return 0;
+ for (const auto &E : llvm::AArch64::Extensions)
+ if (Name == E.Name)
+ return E.FmvPriority;
+ return 0;
+}
+
+unsigned AArch64TargetInfo::multiVersionFeatureCost() const {
+ // Take the maximum priority as per feature cost, so more features win.
+ return llvm::AArch64::ExtensionInfo::MaxFMVPriority;
+}
+
+bool AArch64TargetInfo::getFeatureDepOptions(StringRef Name,
+ std::string &FeatureVec) const {
+ FeatureVec = "";
+ for (const auto &E : llvm::AArch64::Extensions) {
+ if (Name == E.Name) {
+ FeatureVec = E.DependentFeatures;
+ break;
+ }
+ }
+ return FeatureVec != "";
+}
+
+bool AArch64TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
+ for (const auto &E : llvm::AArch64::Extensions)
+ if (FeatureStr == E.Name)
+ return true;
+ return false;
}
bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
- .Cases("aarch64", "arm64", "arm", true)
- .Case("neon", FPU & NeonMode)
- .Cases("sve", "sve2", "sve2-bitperm", "sve2-aes", "sve2-sha3", "sve2-sm4", "f64mm", "f32mm", "i8mm", "bf16", FPU & SveMode)
- .Case("ls64", HasLS64)
- .Default(false);
+ .Cases("aarch64", "arm64", "arm", true)
+ .Case("fmv", HasFMV)
+ .Cases("neon", "fp", "simd", FPU & NeonMode)
+ .Case("jscvt", HasJSCVT)
+ .Case("fcma", HasFCMA)
+ .Case("rng", HasRandGen)
+ .Case("flagm", HasFlagM)
+ .Case("flagm2", HasAlternativeNZCV)
+ .Case("fp16fml", HasFP16FML)
+ .Case("dotprod", HasDotProd)
+ .Case("sm4", HasSM4)
+ .Case("rdm", HasRDM)
+ .Case("lse", HasLSE)
+ .Case("crc", HasCRC)
+ .Case("sha2", HasSHA2)
+ .Case("sha3", HasSHA3)
+ .Cases("aes", "pmull", HasAES)
+ .Cases("fp16", "fullfp16", HasFullFP16)
+ .Case("dit", HasDIT)
+ .Case("dpb", HasCCPP)
+ .Case("dpb2", HasCCDP)
+ .Case("rcpc", HasRCPC)
+ .Case("frintts", HasFRInt3264)
+ .Case("i8mm", HasMatMul)
+ .Case("bf16", HasBFloat16)
+ .Case("sve", FPU & SveMode)
+ .Case("sve-bf16", FPU & SveMode && HasBFloat16)
+ .Case("sve-i8mm", FPU & SveMode && HasMatMul)
+ .Case("f32mm", FPU & SveMode && HasMatmulFP32)
+ .Case("f64mm", FPU & SveMode && HasMatmulFP64)
+ .Case("sve2", FPU & SveMode && HasSVE2)
+ .Case("sve2-pmull128", FPU & SveMode && HasSVE2AES)
+ .Case("sve2-bitperm", FPU & SveMode && HasSVE2BitPerm)
+ .Case("sve2-sha3", FPU & SveMode && HasSVE2SHA3)
+ .Case("sve2-sm4", FPU & SveMode && HasSVE2SM4)
+ .Case("sme", HasSME)
+ .Case("sme-f64f64", HasSMEF64)
+ .Case("sme-i16i64", HasSMEI64)
+ .Cases("memtag", "memtag2", HasMTE)
+ .Case("sb", HasSB)
+ .Case("predres", HasPredRes)
+ .Cases("ssbs", "ssbs2", HasSSBS)
+ .Case("bti", HasBTI)
+ .Cases("ls64", "ls64_v", "ls64_accdata", HasLS64)
+ .Case("wfxt", HasWFxT)
+ .Default(false);
+}
+
+void AArch64TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
+ StringRef Name, bool Enabled) const {
+ Features[Name] = Enabled;
+ // If the feature is an architecture feature (like v8.2a), add all previous
+ // architecture versions and any dependant target features.
+ const llvm::AArch64::ArchInfo &ArchInfo =
+ llvm::AArch64::ArchInfo::findBySubArch(Name);
+
+ if (ArchInfo == llvm::AArch64::INVALID)
+ return; // Not an architecure, nothing more to do.
+
+ for (const auto *OtherArch : llvm::AArch64::ArchInfos)
+ if (ArchInfo.implies(*OtherArch))
+ Features[OtherArch->getSubArch()] = Enabled;
+
+ // Set any features implied by the architecture
+ uint64_t Extensions =
+ llvm::AArch64::getDefaultExtensions("generic", ArchInfo);
+ std::vector<StringRef> CPUFeats;
+ if (llvm::AArch64::getExtensionFeatures(Extensions, CPUFeats)) {
+ for (auto F : CPUFeats) {
+ assert(F[0] == '+' && "Expected + in target feature!");
+ Features[F.drop_front(1)] = true;
+ }
+ }
}
bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) {
- FPU = FPUMode;
- HasCRC = false;
- HasAES = false;
- HasSHA2 = false;
- HasSHA3 = false;
- HasSM4 = false;
- HasUnaligned = true;
- HasFullFP16 = false;
- HasDotProd = false;
- HasFP16FML = false;
- HasMTE = false;
- HasTME = false;
- HasLS64 = false;
- HasRandGen = false;
- HasMatMul = false;
- HasBFloat16 = false;
- HasSVE2 = false;
- HasSVE2AES = false;
- HasSVE2SHA3 = false;
- HasSVE2SM4 = false;
- HasSVE2BitPerm = false;
- HasMatmulFP64 = false;
- HasMatmulFP32 = false;
- HasLSE = false;
- HasMOPS = false;
-
- ArchKind = llvm::AArch64::ArchKind::INVALID;
-
for (const auto &Feature : Features) {
- if (Feature == "+neon")
+ if (Feature == "-neon")
+ HasNoNeon = true;
+ if (Feature == "-sve")
+ HasNoSVE = true;
+
+ if (Feature == "+neon" || Feature == "+fp-armv8")
+ FPU |= NeonMode;
+ if (Feature == "+jscvt") {
+ HasJSCVT = true;
+ FPU |= NeonMode;
+ }
+ if (Feature == "+fcma") {
+ HasFCMA = true;
FPU |= NeonMode;
+ }
+
if (Feature == "+sve") {
+ FPU |= NeonMode;
FPU |= SveMode;
HasFullFP16 = true;
}
if (Feature == "+sve2") {
+ FPU |= NeonMode;
FPU |= SveMode;
HasFullFP16 = true;
HasSVE2 = true;
}
if (Feature == "+sve2-aes") {
+ FPU |= NeonMode;
FPU |= SveMode;
HasFullFP16 = true;
HasSVE2 = true;
HasSVE2AES = true;
}
if (Feature == "+sve2-sha3") {
+ FPU |= NeonMode;
FPU |= SveMode;
HasFullFP16 = true;
HasSVE2 = true;
HasSVE2SHA3 = true;
}
if (Feature == "+sve2-sm4") {
+ FPU |= NeonMode;
FPU |= SveMode;
HasFullFP16 = true;
HasSVE2 = true;
HasSVE2SM4 = true;
}
if (Feature == "+sve2-bitperm") {
+ FPU |= NeonMode;
FPU |= SveMode;
HasFullFP16 = true;
HasSVE2 = true;
HasSVE2BitPerm = true;
}
if (Feature == "+f32mm") {
+ FPU |= NeonMode;
FPU |= SveMode;
+ HasFullFP16 = true;
HasMatmulFP32 = true;
}
if (Feature == "+f64mm") {
+ FPU |= NeonMode;
FPU |= SveMode;
+ HasFullFP16 = true;
HasMatmulFP64 = true;
}
+ if (Feature == "+sme") {
+ HasSME = true;
+ HasBFloat16 = true;
+ }
+ if (Feature == "+sme-f64f64") {
+ HasSME = true;
+ HasSMEF64 = true;
+ HasBFloat16 = true;
+ }
+ if (Feature == "+sme-i16i64") {
+ HasSME = true;
+ HasSMEI64 = true;
+ HasBFloat16 = true;
+ }
+ if (Feature == "+sb")
+ HasSB = true;
+ if (Feature == "+predres")
+ HasPredRes = true;
+ if (Feature == "+ssbs")
+ HasSSBS = true;
+ if (Feature == "+bti")
+ HasBTI = true;
+ if (Feature == "+wfxt")
+ HasWFxT = true;
+ if (Feature == "-fmv")
+ HasFMV = false;
if (Feature == "+crc")
HasCRC = true;
- if (Feature == "+aes")
+ if (Feature == "+rcpc")
+ HasRCPC = true;
+ if (Feature == "+aes") {
+ FPU |= NeonMode;
HasAES = true;
- if (Feature == "+sha2")
+ }
+ if (Feature == "+sha2") {
+ FPU |= NeonMode;
HasSHA2 = true;
+ }
if (Feature == "+sha3") {
+ FPU |= NeonMode;
HasSHA2 = true;
HasSHA3 = true;
}
- if (Feature == "+sm4")
+ if (Feature == "+rdm") {
+ FPU |= NeonMode;
+ HasRDM = true;
+ }
+ if (Feature == "+dit")
+ HasDIT = true;
+ if (Feature == "+cccp")
+ HasCCPP = true;
+ if (Feature == "+ccdp") {
+ HasCCPP = true;
+ HasCCDP = true;
+ }
+ if (Feature == "+fptoint")
+ HasFRInt3264 = true;
+ if (Feature == "+sm4") {
+ FPU |= NeonMode;
HasSM4 = true;
+ }
if (Feature == "+strict-align")
HasUnaligned = false;
- if (Feature == "+v8a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8A;
- if (Feature == "+v8.1a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8_1A;
- if (Feature == "+v8.2a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8_2A;
- if (Feature == "+v8.3a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8_3A;
- if (Feature == "+v8.4a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8_4A;
- if (Feature == "+v8.5a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8_5A;
- if (Feature == "+v8.6a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8_6A;
- if (Feature == "+v8.7a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8_7A;
- if (Feature == "+v8.8a")
- ArchKind = llvm::AArch64::ArchKind::ARMV8_8A;
- if (Feature == "+v9a")
- ArchKind = llvm::AArch64::ArchKind::ARMV9A;
- if (Feature == "+v9.1a")
- ArchKind = llvm::AArch64::ArchKind::ARMV9_1A;
- if (Feature == "+v9.2a")
- ArchKind = llvm::AArch64::ArchKind::ARMV9_2A;
- if (Feature == "+v9.3a")
- ArchKind = llvm::AArch64::ArchKind::ARMV9_3A;
+ // All predecessor archs are added but select the latest one for ArchKind.
+ if (Feature == "+v8a" && ArchInfo->Version < llvm::AArch64::ARMV8A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8A;
+ if (Feature == "+v8.1a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_1A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_1A;
+ if (Feature == "+v8.2a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_2A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_2A;
+ if (Feature == "+v8.3a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_3A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_3A;
+ if (Feature == "+v8.4a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_4A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_4A;
+ if (Feature == "+v8.5a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_5A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_5A;
+ if (Feature == "+v8.6a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_6A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_6A;
+ if (Feature == "+v8.7a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_7A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_7A;
+ if (Feature == "+v8.8a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_8A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_8A;
+ if (Feature == "+v8.9a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV8_9A.Version)
+ ArchInfo = &llvm::AArch64::ARMV8_9A;
+ if (Feature == "+v9a" && ArchInfo->Version < llvm::AArch64::ARMV9A.Version)
+ ArchInfo = &llvm::AArch64::ARMV9A;
+ if (Feature == "+v9.1a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV9_1A.Version)
+ ArchInfo = &llvm::AArch64::ARMV9_1A;
+ if (Feature == "+v9.2a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV9_2A.Version)
+ ArchInfo = &llvm::AArch64::ARMV9_2A;
+ if (Feature == "+v9.3a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV9_3A.Version)
+ ArchInfo = &llvm::AArch64::ARMV9_3A;
+ if (Feature == "+v9.4a" &&
+ ArchInfo->Version < llvm::AArch64::ARMV9_4A.Version)
+ ArchInfo = &llvm::AArch64::ARMV9_4A;
if (Feature == "+v8r")
- ArchKind = llvm::AArch64::ArchKind::ARMV8R;
- if (Feature == "+fullfp16")
+ ArchInfo = &llvm::AArch64::ARMV8R;
+ if (Feature == "+fullfp16") {
+ FPU |= NeonMode;
HasFullFP16 = true;
- if (Feature == "+dotprod")
+ }
+ if (Feature == "+dotprod") {
+ FPU |= NeonMode;
HasDotProd = true;
- if (Feature == "+fp16fml")
+ }
+ if (Feature == "+fp16fml") {
+ FPU |= NeonMode;
+ HasFullFP16 = true;
HasFP16FML = true;
+ }
if (Feature == "+mte")
HasMTE = true;
if (Feature == "+tme")
@@ -661,12 +913,175 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasRandGen = true;
if (Feature == "+flagm")
HasFlagM = true;
+ if (Feature == "+altnzcv") {
+ HasFlagM = true;
+ HasAlternativeNZCV = true;
+ }
if (Feature == "+mops")
HasMOPS = true;
+ if (Feature == "+d128")
+ HasD128 = true;
+ }
+
+ // Check features that are manually disabled by command line options.
+ // This needs to be checked after architecture-related features are handled,
+ // making sure they are properly disabled when required.
+ for (const auto &Feature : Features) {
+ if (Feature == "-d128")
+ HasD128 = false;
}
setDataLayout();
+ setArchFeatures();
+
+ if (HasNoNeon) {
+ FPU &= ~NeonMode;
+ FPU &= ~SveMode;
+ }
+ if (HasNoSVE)
+ FPU &= ~SveMode;
+
+ return true;
+}
+
+bool AArch64TargetInfo::initFeatureMap(
+ llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const {
+ std::vector<std::string> UpdatedFeaturesVec;
+ // Parse the CPU and add any implied features.
+ const llvm::AArch64::ArchInfo &Arch = llvm::AArch64::parseCpu(CPU).Arch;
+ if (Arch != llvm::AArch64::INVALID) {
+ uint64_t Exts = llvm::AArch64::getDefaultExtensions(CPU, Arch);
+ std::vector<StringRef> CPUFeats;
+ llvm::AArch64::getExtensionFeatures(Exts, CPUFeats);
+ for (auto F : CPUFeats) {
+ assert((F[0] == '+' || F[0] == '-') && "Expected +/- in target feature!");
+ UpdatedFeaturesVec.push_back(F.str());
+ }
+ }
+
+ // Process target and dependent features. This is done in two loops collecting
+ // them into UpdatedFeaturesVec: first to add dependent '+'features,
+ // second to add target '+/-'features that can later disable some of
+ // features added on the first loop.
+ for (const auto &Feature : FeaturesVec)
+ if ((Feature[0] == '?' || Feature[0] == '+')) {
+ std::string Options;
+ if (AArch64TargetInfo::getFeatureDepOptions(Feature.substr(1), Options)) {
+ SmallVector<StringRef, 1> AttrFeatures;
+ StringRef(Options).split(AttrFeatures, ",");
+ for (auto F : AttrFeatures)
+ UpdatedFeaturesVec.push_back(F.str());
+ }
+ }
+ for (const auto &Feature : FeaturesVec)
+ if (Feature[0] == '+') {
+ std::string F;
+ llvm::AArch64::getFeatureOption(Feature, F);
+ UpdatedFeaturesVec.push_back(F);
+ } else if (Feature[0] != '?')
+ UpdatedFeaturesVec.push_back(Feature);
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec);
+}
+
+// Parse AArch64 Target attributes, which are a comma separated list of:
+// "arch=<arch>" - parsed to features as per -march=..
+// "cpu=<cpu>" - parsed to features as per -mcpu=.., with CPU set to <cpu>
+// "tune=<cpu>" - TuneCPU set to <cpu>
+// "feature", "no-feature" - Add (or remove) feature.
+// "+feature", "+nofeature" - Add (or remove) feature.
+ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
+ ParsedTargetAttr Ret;
+ if (Features == "default")
+ return Ret;
+ SmallVector<StringRef, 1> AttrFeatures;
+ Features.split(AttrFeatures, ",");
+ bool FoundArch = false;
+
+ auto SplitAndAddFeatures = [](StringRef FeatString,
+ std::vector<std::string> &Features) {
+ SmallVector<StringRef, 8> SplitFeatures;
+ FeatString.split(SplitFeatures, StringRef("+"), -1, false);
+ for (StringRef Feature : SplitFeatures) {
+ StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
+ if (!FeatureName.empty())
+ Features.push_back(FeatureName.str());
+ else
+ // Pushing the original feature string to give a sema error later on
+ // when they get checked.
+ if (Feature.startswith("no"))
+ Features.push_back("-" + Feature.drop_front(2).str());
+ else
+ Features.push_back("+" + Feature.str());
+ }
+ };
+
+ for (auto &Feature : AttrFeatures) {
+ Feature = Feature.trim();
+ if (Feature.startswith("fpmath="))
+ continue;
+
+ if (Feature.startswith("branch-protection=")) {
+ Ret.BranchProtection = Feature.split('=').second.trim();
+ continue;
+ }
+
+ if (Feature.startswith("arch=")) {
+ if (FoundArch)
+ Ret.Duplicate = "arch=";
+ FoundArch = true;
+ std::pair<StringRef, StringRef> Split =
+ Feature.split("=").second.trim().split("+");
+ const llvm::AArch64::ArchInfo &AI = llvm::AArch64::parseArch(Split.first);
+
+ // Parse the architecture version, adding the required features to
+ // Ret.Features.
+ if (AI == llvm::AArch64::INVALID)
+ continue;
+ Ret.Features.push_back(AI.ArchFeature.str());
+ // Add any extra features, after the +
+ SplitAndAddFeatures(Split.second, Ret.Features);
+ } else if (Feature.startswith("cpu=")) {
+ if (!Ret.CPU.empty())
+ Ret.Duplicate = "cpu=";
+ else {
+ // Split the cpu string into "cpu=", "cortex-a710" and any remaining
+ // "+feat" features.
+ std::pair<StringRef, StringRef> Split =
+ Feature.split("=").second.trim().split("+");
+ Ret.CPU = Split.first;
+ SplitAndAddFeatures(Split.second, Ret.Features);
+ }
+ } else if (Feature.startswith("tune=")) {
+ if (!Ret.Tune.empty())
+ Ret.Duplicate = "tune=";
+ else
+ Ret.Tune = Feature.split("=").second.trim();
+ } else if (Feature.startswith("+")) {
+ SplitAndAddFeatures(Feature, Ret.Features);
+ } else if (Feature.startswith("no-")) {
+ StringRef FeatureName =
+ llvm::AArch64::getArchExtFeature(Feature.split("-").second);
+ if (!FeatureName.empty())
+ Ret.Features.push_back("-" + FeatureName.drop_front(1).str());
+ else
+ Ret.Features.push_back("-" + Feature.split("-").second.str());
+ } else {
+ // Try parsing the string to the internal target feature name. If it is
+ // invalid, add the original string (which could already be an internal
+ // name). These should be checked later by isValidFeatureName.
+ StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
+ if (!FeatureName.empty())
+ Ret.Features.push_back(FeatureName.str());
+ else
+ Ret.Features.push_back("+" + Feature.str());
+ }
+ }
+ return Ret;
+}
+bool AArch64TargetInfo::hasBFloat16Type() const {
return true;
}
@@ -731,7 +1146,7 @@ const char *const AArch64TargetInfo::GCCRegNames[] = {
};
ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
@@ -774,7 +1189,7 @@ const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
};
ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
bool AArch64TargetInfo::validateAsmConstraint(
diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index bd6812d1257c..34df886377ea 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -16,7 +16,7 @@
#include "OSTargets.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/Support/AArch64TargetParser.h"
-#include "llvm/Support/TargetParser.h"
+#include <optional>
namespace clang {
namespace targets {
@@ -28,39 +28,58 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
enum FPUModeEnum { FPUMode, NeonMode = (1 << 0), SveMode = (1 << 1) };
- unsigned FPU;
- bool HasCRC;
- bool HasAES;
- bool HasSHA2;
- bool HasSHA3;
- bool HasSM4;
- bool HasUnaligned;
- bool HasFullFP16;
- bool HasDotProd;
- bool HasFP16FML;
- bool HasMTE;
- bool HasTME;
- bool HasPAuth;
- bool HasLS64;
- bool HasRandGen;
- bool HasMatMul;
- bool HasSVE2;
- bool HasSVE2AES;
- bool HasSVE2SHA3;
- bool HasSVE2SM4;
- bool HasSVE2BitPerm;
- bool HasMatmulFP64;
- bool HasMatmulFP32;
- bool HasLSE;
- bool HasFlagM;
- bool HasMOPS;
-
- llvm::AArch64::ArchKind ArchKind;
-
- static const Builtin::Info BuiltinInfo[];
+ unsigned FPU = FPUMode;
+ bool HasCRC = false;
+ bool HasAES = false;
+ bool HasSHA2 = false;
+ bool HasSHA3 = false;
+ bool HasSM4 = false;
+ bool HasUnaligned = true;
+ bool HasFullFP16 = false;
+ bool HasDotProd = false;
+ bool HasFP16FML = false;
+ bool HasMTE = false;
+ bool HasTME = false;
+ bool HasPAuth = false;
+ bool HasLS64 = false;
+ bool HasRandGen = false;
+ bool HasMatMul = false;
+ bool HasBFloat16 = false;
+ bool HasSVE2 = false;
+ bool HasSVE2AES = false;
+ bool HasSVE2SHA3 = false;
+ bool HasSVE2SM4 = false;
+ bool HasSVE2BitPerm = false;
+ bool HasMatmulFP64 = false;
+ bool HasMatmulFP32 = false;
+ bool HasLSE = false;
+ bool HasFlagM = false;
+ bool HasAlternativeNZCV = false;
+ bool HasMOPS = false;
+ bool HasD128 = false;
+ bool HasRCPC = false;
+ bool HasRDM = false;
+ bool HasDIT = false;
+ bool HasCCPP = false;
+ bool HasCCDP = false;
+ bool HasFRInt3264 = false;
+ bool HasSME = false;
+ bool HasSMEF64 = false;
+ bool HasSMEI64 = false;
+ bool HasSB = false;
+ bool HasPredRes = false;
+ bool HasSSBS = false;
+ bool HasBTI = false;
+ bool HasWFxT = false;
+ bool HasJSCVT = false;
+ bool HasFCMA = false;
+ bool HasNoNeon = false;
+ bool HasNoSVE = false;
+ bool HasFMV = true;
+
+ const llvm::AArch64::ArchInfo *ArchInfo = &llvm::AArch64::ARMV8A;
std::string ABI;
- StringRef getArchProfile() const;
public:
AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts);
@@ -76,10 +95,19 @@ public:
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool setCPU(const std::string &Name) override;
+ unsigned multiVersionSortPriority(StringRef Name) const override;
+ unsigned multiVersionFeatureCost() const override;
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override;
bool useFP16ConversionIntrinsics() const override {
return false;
}
+ void setArchFeatures();
+
void getTargetDefinesARMV81A(const LangOptions &Opts,
MacroBuilder &Builder) const;
void getTargetDefinesARMV82A(const LangOptions &Opts,
@@ -96,6 +124,8 @@ public:
MacroBuilder &Builder) const;
void getTargetDefinesARMV88A(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ void getTargetDefinesARMV89A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
void getTargetDefinesARMV9A(const LangOptions &Opts,
MacroBuilder &Builder) const;
void getTargetDefinesARMV91A(const LangOptions &Opts,
@@ -104,17 +134,28 @@ public:
MacroBuilder &Builder) const;
void getTargetDefinesARMV93A(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ void getTargetDefinesARMV94A(const LangOptions &Opts,
+ MacroBuilder &Builder) const;
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
ArrayRef<Builtin::Info> getTargetBuiltins() const override;
- Optional<std::pair<unsigned, unsigned>>
+ std::optional<std::pair<unsigned, unsigned>>
getVScaleRange(const LangOptions &LangOpts) const override;
+ bool getFeatureDepOptions(StringRef Feature,
+ std::string &Options) const override;
+ bool validateCpuSupports(StringRef FeatureStr) const override;
bool hasFeature(StringRef Feature) const override;
+ void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name,
+ bool Enabled) const override;
bool handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) override;
+ ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
+ bool supportsTargetAttributeTune() const override { return true; }
+
+ bool hasBFloat16Type() const override;
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override;
diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp
index 80f2601b0a24..fe50fbcf3b88 100644
--- a/clang/lib/Basic/Targets/AMDGPU.cpp
+++ b/clang/lib/Basic/Targets/AMDGPU.cpp
@@ -13,10 +13,10 @@
#include "AMDGPU.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CodeGenOptions.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetBuiltins.h"
-#include "llvm/ADT/StringSwitch.h"
using namespace clang;
using namespace clang::targets;
@@ -56,7 +56,8 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = {
Private, // sycl_private
Generic, // ptr32_sptr
Generic, // ptr32_uptr
- Generic // ptr64
+ Generic, // ptr64
+ Generic, // hlsl_groupshared
};
const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
@@ -72,24 +73,25 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = {
Constant, // cuda_constant
Local, // cuda_shared
// SYCL address space values for this map are dummy
- Generic, // sycl_global
- Generic, // sycl_global_device
- Generic, // sycl_global_host
- Generic, // sycl_local
- Generic, // sycl_private
- Generic, // ptr32_sptr
- Generic, // ptr32_uptr
- Generic // ptr64
+ Generic, // sycl_global
+ Generic, // sycl_global_device
+ Generic, // sycl_global_host
+ Generic, // sycl_local
+ Generic, // sycl_private
+ Generic, // ptr32_sptr
+ Generic, // ptr32_uptr
+ Generic, // ptr64
+ Generic, // hlsl_groupshared
};
} // namespace targets
} // namespace clang
-const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsAMDGPU.def"
};
@@ -171,12 +173,14 @@ const char *const AMDGPUTargetInfo::GCCRegNames[] = {
};
ArrayRef<const char *> AMDGPUTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
bool AMDGPUTargetInfo::initFeatureMap(
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
const std::vector<std::string> &FeatureVec) const {
+ const bool IsNullCPU = CPU.empty();
+ bool IsWave32Capable = false;
using namespace llvm::AMDGPU;
@@ -187,14 +191,13 @@ bool AMDGPUTargetInfo::initFeatureMap(
case GK_GFX1102:
case GK_GFX1101:
case GK_GFX1100:
+ IsWave32Capable = true;
Features["ci-insts"] = true;
- Features["dot1-insts"] = true;
Features["dot5-insts"] = true;
- Features["dot6-insts"] = true;
Features["dot7-insts"] = true;
Features["dot8-insts"] = true;
+ Features["dot9-insts"] = true;
Features["dl-insts"] = true;
- Features["flat-address-space"] = true;
Features["16-bit-insts"] = true;
Features["dpp"] = true;
Features["gfx8-insts"] = true;
@@ -210,6 +213,7 @@ bool AMDGPUTargetInfo::initFeatureMap(
case GK_GFX1032:
case GK_GFX1031:
case GK_GFX1030:
+ IsWave32Capable = true;
Features["ci-insts"] = true;
Features["dot1-insts"] = true;
Features["dot2-insts"] = true;
@@ -217,7 +221,6 @@ bool AMDGPUTargetInfo::initFeatureMap(
Features["dot6-insts"] = true;
Features["dot7-insts"] = true;
Features["dl-insts"] = true;
- Features["flat-address-space"] = true;
Features["16-bit-insts"] = true;
Features["dpp"] = true;
Features["gfx8-insts"] = true;
@@ -234,12 +237,12 @@ bool AMDGPUTargetInfo::initFeatureMap(
Features["dot5-insts"] = true;
Features["dot6-insts"] = true;
Features["dot7-insts"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GK_GFX1013:
case GK_GFX1010:
+ IsWave32Capable = true;
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;
@@ -251,30 +254,30 @@ bool AMDGPUTargetInfo::initFeatureMap(
case GK_GFX940:
Features["gfx940-insts"] = true;
Features["fp8-insts"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GK_GFX90A:
Features["gfx90a-insts"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GK_GFX908:
Features["dot3-insts"] = true;
Features["dot4-insts"] = true;
Features["dot5-insts"] = true;
Features["dot6-insts"] = true;
Features["mai-insts"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GK_GFX906:
Features["dl-insts"] = true;
Features["dot1-insts"] = true;
Features["dot2-insts"] = true;
Features["dot7-insts"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GK_GFX90C:
case GK_GFX909:
case GK_GFX904:
case GK_GFX902:
case GK_GFX900:
Features["gfx9-insts"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GK_GFX810:
case GK_GFX805:
case GK_GFX803:
@@ -284,7 +287,7 @@ bool AMDGPUTargetInfo::initFeatureMap(
Features["16-bit-insts"] = true;
Features["dpp"] = true;
Features["s-memrealtime"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GK_GFX705:
case GK_GFX704:
case GK_GFX703:
@@ -292,8 +295,7 @@ bool AMDGPUTargetInfo::initFeatureMap(
case GK_GFX701:
case GK_GFX700:
Features["ci-insts"] = true;
- Features["flat-address-space"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GK_GFX602:
case GK_GFX601:
case GK_GFX600:
@@ -333,7 +335,32 @@ bool AMDGPUTargetInfo::initFeatureMap(
}
}
- return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec);
+ if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec))
+ return false;
+
+ // FIXME: Not diagnosing wavefrontsize32 on wave64 only targets.
+ const bool HaveWave32 =
+ (IsWave32Capable || IsNullCPU) && Features.count("wavefrontsize32");
+ const bool HaveWave64 = Features.count("wavefrontsize64");
+
+ // TODO: Should move this logic into TargetParser
+ if (HaveWave32 && HaveWave64) {
+ Diags.Report(diag::err_invalid_feature_combination)
+ << "'wavefrontsize32' and 'wavefrontsize64' are mutually exclusive";
+ return false;
+ }
+
+ // Don't assume any wavesize with an unknown subtarget.
+ if (!IsNullCPU) {
+ // Default to wave32 if available, or wave64 if not
+ if (!HaveWave32 && !HaveWave64) {
+ StringRef DefaultWaveSizeFeature =
+ IsWave32Capable ? "wavefrontsize32" : "wavefrontsize64";
+ Features.insert(std::make_pair(DefaultWaveSizeFeature, true));
+ }
+ }
+
+ return true;
}
void AMDGPUTargetInfo::fillValidCPUList(
@@ -364,13 +391,19 @@ AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple,
!isAMDGCN(Triple));
UseAddrSpaceMapMangling = true;
+ if (isAMDGCN(Triple)) {
+ // __bf16 is always available as a load/store only type on AMDGCN.
+ BFloat16Width = BFloat16Align = 16;
+ BFloat16Format = &llvm::APFloat::BFloat();
+ }
+
HasLegalHalfType = true;
HasFloat16 = true;
WavefrontSize = GPUFeatures & llvm::AMDGPU::FEATURE_WAVE32 ? 32 : 64;
AllowAMDGPUUnsafeFPAtomics = Opts.AllowAMDGPUUnsafeFPAtomics;
- // Set pointer width and alignment for target address space 0.
- PointerWidth = PointerAlign = getPointerWidthV(Generic);
+ // Set pointer width and alignment for the generic address space.
+ PointerWidth = PointerAlign = getPointerWidthV(LangAS::Default);
if (getMaxPointerWidth() == 64) {
LongWidth = LongAlign = 64;
SizeType = UnsignedLong;
@@ -391,8 +424,8 @@ void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
}
ArrayRef<Builtin::Info> AMDGPUTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::AMDGPU::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h
index 5e73a3cb8019..576bcf9d5401 100644
--- a/clang/lib/Basic/Targets/AMDGPU.h
+++ b/clang/lib/Basic/Targets/AMDGPU.h
@@ -20,13 +20,13 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/TargetParser.h"
+#include <optional>
namespace clang {
namespace targets {
class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
static const char *const GCCRegNames[];
enum AddrSpace {
@@ -95,17 +95,18 @@ public:
void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override;
- uint64_t getPointerWidthV(unsigned AddrSpace) const override {
+ uint64_t getPointerWidthV(LangAS AS) const override {
if (isR600(getTriple()))
return 32;
+ unsigned TargetAS = getTargetAddressSpace(AS);
- if (AddrSpace == Private || AddrSpace == Local)
+ if (TargetAS == Private || TargetAS == Local)
return 32;
return 64;
}
- uint64_t getPointerAlignV(unsigned AddrSpace) const override {
+ uint64_t getPointerAlignV(LangAS AddrSpace) const override {
return getPointerWidthV(AddrSpace);
}
@@ -113,12 +114,15 @@ public:
return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32;
}
+ bool hasBFloat16Type() const override { return isAMDGCN(getTriple()); }
+ const char *getBFloat16Mangling() const override { return "u6__bf16"; };
+
const char *getClobbers() const override { return ""; }
ArrayRef<const char *> getGCCRegNames() const override;
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
/// Accepted register names: (n, m is unsigned integer, n < m)
@@ -366,7 +370,7 @@ public:
}
}
- llvm::Optional<LangAS> getConstantAddressSpace() const override {
+ std::optional<LangAS> getConstantAddressSpace() const override {
return getLangASFromTargetAS(Constant);
}
@@ -390,9 +394,9 @@ public:
/// space \p AddressSpace to be converted in order to be used, then return the
/// corresponding target specific DWARF address space.
///
- /// \returns Otherwise return None and no conversion will be emitted in the
- /// DWARF.
- Optional<unsigned>
+ /// \returns Otherwise return std::nullopt and no conversion will be emitted
+ /// in the DWARF.
+ std::optional<unsigned>
getDWARFAddressSpace(unsigned AddressSpace) const override {
const unsigned DWARF_Private = 1;
const unsigned DWARF_Local = 2;
@@ -401,7 +405,7 @@ public:
} else if (AddressSpace == Local) {
return DWARF_Local;
} else {
- return None;
+ return std::nullopt;
}
}
@@ -449,9 +453,9 @@ public:
return true;
}
- Optional<std::string> getTargetID() const override {
+ std::optional<std::string> getTargetID() const override {
if (!isAMDGCN(getTriple()))
- return llvm::None;
+ return std::nullopt;
// When -target-cpu is not set, we assume generic code that it is valid
// for all GPU and use an empty string as target ID to represent that.
if (GPUKind == llvm::AMDGPU::GK_NONE)
diff --git a/clang/lib/Basic/Targets/ARC.h b/clang/lib/Basic/Targets/ARC.h
index 5411cd2cd869..3cb338a821e1 100644
--- a/clang/lib/Basic/Targets/ARC.h
+++ b/clang/lib/Basic/Targets/ARC.h
@@ -40,7 +40,9 @@ public:
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ return std::nullopt;
+ }
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
@@ -54,11 +56,11 @@ public:
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
"r24", "r25", "gp", "sp", "fp", "ilink1", "r30", "blink"};
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
bool validateAsmConstraint(const char *&Name,
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp
index b2f61cff81c9..f11751a76073 100644
--- a/clang/lib/Basic/Targets/ARM.cpp
+++ b/clang/lib/Basic/Targets/ARM.cpp
@@ -214,6 +214,8 @@ StringRef ARMTargetInfo::getCPUAttr() const {
return "8_7A";
case llvm::ARM::ArchKind::ARMV8_8A:
return "8_8A";
+ case llvm::ARM::ArchKind::ARMV8_9A:
+ return "8_9A";
case llvm::ARM::ArchKind::ARMV9A:
return "9A";
case llvm::ARM::ArchKind::ARMV9_1A:
@@ -222,6 +224,8 @@ StringRef ARMTargetInfo::getCPUAttr() const {
return "9_2A";
case llvm::ARM::ArchKind::ARMV9_3A:
return "9_3A";
+ case llvm::ARM::ArchKind::ARMV9_4A:
+ return "9_4A";
case llvm::ARM::ArchKind::ARMV8MBaseline:
return "8M_BASE";
case llvm::ARM::ArchKind::ARMV8MMainline:
@@ -431,6 +435,19 @@ bool ARMTargetInfo::initFeatureMap(
if (CPUArch != llvm::ARM::ArchKind::INVALID) {
ArchFeature = ("+" + llvm::ARM::getArchName(CPUArch)).str();
TargetFeatures.push_back(ArchFeature);
+
+ // These features are added to allow arm_neon.h target(..) attributes to
+ // match with both arm and aarch64. We need to add all previous architecture
+ // versions, so that "8.6" also allows "8.1" functions. In case of v9.x the
+ // v8.x counterparts are added too. We only need these for anything > 8.0-A.
+ for (llvm::ARM::ArchKind I = llvm::ARM::convertV9toV8(CPUArch);
+ I != llvm::ARM::ArchKind::INVALID; --I)
+ Features[llvm::ARM::getSubArch(I)] = true;
+ if (CPUArch > llvm::ARM::ArchKind::ARMV8A &&
+ CPUArch <= llvm::ARM::ArchKind::ARMV9_3A)
+ for (llvm::ARM::ArchKind I = CPUArch; I != llvm::ARM::ArchKind::INVALID;
+ --I)
+ Features[llvm::ARM::getSubArch(I)] = true;
}
// get default FPU features
@@ -580,6 +597,8 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
}
}
+ HalfArgsAndReturns = true;
+
switch (ArchVersion) {
case 6:
if (ArchProfile == llvm::ARM::ProfileKind::M)
@@ -628,7 +647,8 @@ bool ARMTargetInfo::hasFeature(StringRef Feature) const {
}
bool ARMTargetInfo::hasBFloat16Type() const {
- return HasBFloat16 && !SoftFloat;
+ // The __bf16 type is generally available so long as we have any fp registers.
+ return HasBFloat16 || (FPU && !SoftFloat);
}
bool ARMTargetInfo::isValidCPUName(StringRef Name) const {
@@ -689,8 +709,11 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
// For bare-metal none-eabi.
if (getTriple().getOS() == llvm::Triple::UnknownOS &&
(getTriple().getEnvironment() == llvm::Triple::EABI ||
- getTriple().getEnvironment() == llvm::Triple::EABIHF))
+ getTriple().getEnvironment() == llvm::Triple::EABIHF)) {
Builder.defineMacro("__ELF__");
+ if (Opts.CPlusPlus)
+ Builder.defineMacro("_GNU_SOURCE");
+ }
// Target properties.
Builder.defineMacro("__REGISTER_PREFIX__", "");
@@ -798,7 +821,7 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp" || ABI == "aapcs16")
Builder.defineMacro("__ARM_PCS_VFP", "1");
- if (SoftFloat)
+ if (SoftFloat || (SoftFloatABI && !FPU))
Builder.defineMacro("__SOFTFP__");
// ACLE position independent code macros.
@@ -957,36 +980,42 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts,
case llvm::ARM::ArchKind::ARMV8_6A:
case llvm::ARM::ArchKind::ARMV8_7A:
case llvm::ARM::ArchKind::ARMV8_8A:
+ case llvm::ARM::ArchKind::ARMV8_9A:
case llvm::ARM::ArchKind::ARMV9A:
case llvm::ARM::ArchKind::ARMV9_1A:
case llvm::ARM::ArchKind::ARMV9_2A:
case llvm::ARM::ArchKind::ARMV9_3A:
+ case llvm::ARM::ArchKind::ARMV9_4A:
getTargetDefinesARMV83A(Opts, Builder);
break;
}
}
-const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsNEON.def"
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \
- {#ID, TYPE, ATTRS, nullptr, LANG, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, LANG},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
- {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS},
#include "clang/Basic/BuiltinsARM.def"
};
ArrayRef<Builtin::Info> ARMTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::ARM::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::ARM::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
bool ARMTargetInfo::isCLZForZeroUndef() const { return false; }
@@ -1017,7 +1046,7 @@ const char *const ARMTargetInfo::GCCRegNames[] = {
"q12", "q13", "q14", "q15"};
ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = {
@@ -1030,7 +1059,7 @@ const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = {
};
ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
bool ARMTargetInfo::validateAsmConstraint(
diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h
index e85336b6e32f..e662a609017b 100644
--- a/clang/lib/Basic/Targets/ARM.h
+++ b/clang/lib/Basic/Targets/ARM.h
@@ -17,9 +17,9 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/ARMTargetParser.h"
-#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/ARMTargetParserCommon.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
namespace targets {
@@ -100,8 +100,6 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo {
};
uint32_t HW_FP;
- static const Builtin::Info BuiltinInfo[];
-
void setABIAAPCS();
void setABIAPCS(bool IsAAPCS16);
diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp
index 67e27ebd58de..3d662cc3ba74 100644
--- a/clang/lib/Basic/Targets/AVR.cpp
+++ b/clang/lib/Basic/Targets/AVR.cpp
@@ -24,348 +24,403 @@ namespace targets {
struct LLVM_LIBRARY_VISIBILITY MCUInfo {
const char *Name;
const char *DefineName;
+ StringRef Arch; // The __AVR_ARCH__ value.
const int NumFlashBanks; // Set to 0 for the devices do not support LPM/ELPM.
- bool IsTiny; // Set to true for the devices belong to the avrtiny family.
};
// NOTE: This list has been synchronized with gcc-avr 5.4.0 and avr-libc 2.0.0.
static MCUInfo AVRMcus[] = {
- {"at90s1200", "__AVR_AT90S1200__", 0, false},
- {"attiny11", "__AVR_ATtiny11__", 0, false},
- {"attiny12", "__AVR_ATtiny12__", 0, false},
- {"attiny15", "__AVR_ATtiny15__", 0, false},
- {"attiny28", "__AVR_ATtiny28__", 0, false},
- {"at90s2313", "__AVR_AT90S2313__", 1, false},
- {"at90s2323", "__AVR_AT90S2323__", 1, false},
- {"at90s2333", "__AVR_AT90S2333__", 1, false},
- {"at90s2343", "__AVR_AT90S2343__", 1, false},
- {"attiny22", "__AVR_ATtiny22__", 1, false},
- {"attiny26", "__AVR_ATtiny26__", 1, false},
- {"at86rf401", "__AVR_AT86RF401__", 1, false},
- {"at90s4414", "__AVR_AT90S4414__", 1, false},
- {"at90s4433", "__AVR_AT90S4433__", 1, false},
- {"at90s4434", "__AVR_AT90S4434__", 1, false},
- {"at90s8515", "__AVR_AT90S8515__", 1, false},
- {"at90c8534", "__AVR_AT90c8534__", 1, false},
- {"at90s8535", "__AVR_AT90S8535__", 1, false},
- {"ata5272", "__AVR_ATA5272__", 1, false},
- {"ata6616c", "__AVR_ATA6616c__", 1, false},
- {"attiny13", "__AVR_ATtiny13__", 1, false},
- {"attiny13a", "__AVR_ATtiny13A__", 1, false},
- {"attiny2313", "__AVR_ATtiny2313__", 1, false},
- {"attiny2313a", "__AVR_ATtiny2313A__", 1, false},
- {"attiny24", "__AVR_ATtiny24__", 1, false},
- {"attiny24a", "__AVR_ATtiny24A__", 1, false},
- {"attiny4313", "__AVR_ATtiny4313__", 1, false},
- {"attiny44", "__AVR_ATtiny44__", 1, false},
- {"attiny44a", "__AVR_ATtiny44A__", 1, false},
- {"attiny84", "__AVR_ATtiny84__", 1, false},
- {"attiny84a", "__AVR_ATtiny84A__", 1, false},
- {"attiny25", "__AVR_ATtiny25__", 1, false},
- {"attiny45", "__AVR_ATtiny45__", 1, false},
- {"attiny85", "__AVR_ATtiny85__", 1, false},
- {"attiny261", "__AVR_ATtiny261__", 1, false},
- {"attiny261a", "__AVR_ATtiny261A__", 1, false},
- {"attiny441", "__AVR_ATtiny441__", 1, false},
- {"attiny461", "__AVR_ATtiny461__", 1, false},
- {"attiny461a", "__AVR_ATtiny461A__", 1, false},
- {"attiny841", "__AVR_ATtiny841__", 1, false},
- {"attiny861", "__AVR_ATtiny861__", 1, false},
- {"attiny861a", "__AVR_ATtiny861A__", 1, false},
- {"attiny87", "__AVR_ATtiny87__", 1, false},
- {"attiny43u", "__AVR_ATtiny43U__", 1, false},
- {"attiny48", "__AVR_ATtiny48__", 1, false},
- {"attiny88", "__AVR_ATtiny88__", 1, false},
- {"attiny828", "__AVR_ATtiny828__", 1, false},
- {"at43usb355", "__AVR_AT43USB355__", 1, false},
- {"at76c711", "__AVR_AT76C711__", 1, false},
- {"atmega103", "__AVR_ATmega103__", 1, false},
- {"at43usb320", "__AVR_AT43USB320__", 1, false},
- {"attiny167", "__AVR_ATtiny167__", 1, false},
- {"at90usb82", "__AVR_AT90USB82__", 1, false},
- {"at90usb162", "__AVR_AT90USB162__", 1, false},
- {"ata5505", "__AVR_ATA5505__", 1, false},
- {"ata6617c", "__AVR_ATA6617C__", 1, false},
- {"ata664251", "__AVR_ATA664251__", 1, false},
- {"atmega8u2", "__AVR_ATmega8U2__", 1, false},
- {"atmega16u2", "__AVR_ATmega16U2__", 1, false},
- {"atmega32u2", "__AVR_ATmega32U2__", 1, false},
- {"attiny1634", "__AVR_ATtiny1634__", 1, false},
- {"atmega8", "__AVR_ATmega8__", 1, false},
- {"ata6289", "__AVR_ATA6289__", 1, false},
- {"atmega8a", "__AVR_ATmega8A__", 1, false},
- {"ata6285", "__AVR_ATA6285__", 1, false},
- {"ata6286", "__AVR_ATA6286__", 1, false},
- {"ata6612c", "__AVR_ATA6612C__", 1, false},
- {"atmega48", "__AVR_ATmega48__", 1, false},
- {"atmega48a", "__AVR_ATmega48A__", 1, false},
- {"atmega48pa", "__AVR_ATmega48PA__", 1, false},
- {"atmega48pb", "__AVR_ATmega48PB__", 1, false},
- {"atmega48p", "__AVR_ATmega48P__", 1, false},
- {"atmega88", "__AVR_ATmega88__", 1, false},
- {"atmega88a", "__AVR_ATmega88A__", 1, false},
- {"atmega88p", "__AVR_ATmega88P__", 1, false},
- {"atmega88pa", "__AVR_ATmega88PA__", 1, false},
- {"atmega88pb", "__AVR_ATmega88PB__", 1, false},
- {"atmega8515", "__AVR_ATmega8515__", 1, false},
- {"atmega8535", "__AVR_ATmega8535__", 1, false},
- {"atmega8hva", "__AVR_ATmega8HVA__", 1, false},
- {"at90pwm1", "__AVR_AT90PWM1__", 1, false},
- {"at90pwm2", "__AVR_AT90PWM2__", 1, false},
- {"at90pwm2b", "__AVR_AT90PWM2B__", 1, false},
- {"at90pwm3", "__AVR_AT90PWM3__", 1, false},
- {"at90pwm3b", "__AVR_AT90PWM3B__", 1, false},
- {"at90pwm81", "__AVR_AT90PWM81__", 1, false},
- {"ata5702m322", "__AVR_ATA5702M322__", 1, false},
- {"ata5782", "__AVR_ATA5782__", 1, false},
- {"ata5790", "__AVR_ATA5790__", 1, false},
- {"ata5790n", "__AVR_ATA5790N__", 1, false},
- {"ata5791", "__AVR_ATA5791__", 1, false},
- {"ata5795", "__AVR_ATA5795__", 1, false},
- {"ata5831", "__AVR_ATA5831__", 1, false},
- {"ata6613c", "__AVR_ATA6613C__", 1, false},
- {"ata6614q", "__AVR_ATA6614Q__", 1, false},
- {"ata8210", "__AVR_ATA8210__", 1, false},
- {"ata8510", "__AVR_ATA8510__", 1, false},
- {"atmega16", "__AVR_ATmega16__", 1, false},
- {"atmega16a", "__AVR_ATmega16A__", 1, false},
- {"atmega161", "__AVR_ATmega161__", 1, false},
- {"atmega162", "__AVR_ATmega162__", 1, false},
- {"atmega163", "__AVR_ATmega163__", 1, false},
- {"atmega164a", "__AVR_ATmega164A__", 1, false},
- {"atmega164p", "__AVR_ATmega164P__", 1, false},
- {"atmega164pa", "__AVR_ATmega164PA__", 1, false},
- {"atmega165", "__AVR_ATmega165__", 1, false},
- {"atmega165a", "__AVR_ATmega165A__", 1, false},
- {"atmega165p", "__AVR_ATmega165P__", 1, false},
- {"atmega165pa", "__AVR_ATmega165PA__", 1, false},
- {"atmega168", "__AVR_ATmega168__", 1, false},
- {"atmega168a", "__AVR_ATmega168A__", 1, false},
- {"atmega168p", "__AVR_ATmega168P__", 1, false},
- {"atmega168pa", "__AVR_ATmega168PA__", 1, false},
- {"atmega168pb", "__AVR_ATmega168PB__", 1, false},
- {"atmega169", "__AVR_ATmega169__", 1, false},
- {"atmega169a", "__AVR_ATmega169A__", 1, false},
- {"atmega169p", "__AVR_ATmega169P__", 1, false},
- {"atmega169pa", "__AVR_ATmega169PA__", 1, false},
- {"atmega32", "__AVR_ATmega32__", 1, false},
- {"atmega32a", "__AVR_ATmega32A__", 1, false},
- {"atmega323", "__AVR_ATmega323__", 1, false},
- {"atmega324a", "__AVR_ATmega324A__", 1, false},
- {"atmega324p", "__AVR_ATmega324P__", 1, false},
- {"atmega324pa", "__AVR_ATmega324PA__", 1, false},
- {"atmega324pb", "__AVR_ATmega324PB__", 1, false},
- {"atmega325", "__AVR_ATmega325__", 1, false},
- {"atmega325a", "__AVR_ATmega325A__", 1, false},
- {"atmega325p", "__AVR_ATmega325P__", 1, false},
- {"atmega325pa", "__AVR_ATmega325PA__", 1, false},
- {"atmega3250", "__AVR_ATmega3250__", 1, false},
- {"atmega3250a", "__AVR_ATmega3250A__", 1, false},
- {"atmega3250p", "__AVR_ATmega3250P__", 1, false},
- {"atmega3250pa", "__AVR_ATmega3250PA__", 1, false},
- {"atmega328", "__AVR_ATmega328__", 1, false},
- {"atmega328p", "__AVR_ATmega328P__", 1, false},
- {"atmega328pb", "__AVR_ATmega328PB__", 1, false},
- {"atmega329", "__AVR_ATmega329__", 1, false},
- {"atmega329a", "__AVR_ATmega329A__", 1, false},
- {"atmega329p", "__AVR_ATmega329P__", 1, false},
- {"atmega329pa", "__AVR_ATmega329PA__", 1, false},
- {"atmega3290", "__AVR_ATmega3290__", 1, false},
- {"atmega3290a", "__AVR_ATmega3290A__", 1, false},
- {"atmega3290p", "__AVR_ATmega3290P__", 1, false},
- {"atmega3290pa", "__AVR_ATmega3290PA__", 1, false},
- {"atmega406", "__AVR_ATmega406__", 1, false},
- {"atmega64", "__AVR_ATmega64__", 1, false},
- {"atmega64a", "__AVR_ATmega64A__", 1, false},
- {"atmega640", "__AVR_ATmega640__", 1, false},
- {"atmega644", "__AVR_ATmega644__", 1, false},
- {"atmega644a", "__AVR_ATmega644A__", 1, false},
- {"atmega644p", "__AVR_ATmega644P__", 1, false},
- {"atmega644pa", "__AVR_ATmega644PA__", 1, false},
- {"atmega645", "__AVR_ATmega645__", 1, false},
- {"atmega645a", "__AVR_ATmega645A__", 1, false},
- {"atmega645p", "__AVR_ATmega645P__", 1, false},
- {"atmega649", "__AVR_ATmega649__", 1, false},
- {"atmega649a", "__AVR_ATmega649A__", 1, false},
- {"atmega649p", "__AVR_ATmega649P__", 1, false},
- {"atmega6450", "__AVR_ATmega6450__", 1, false},
- {"atmega6450a", "__AVR_ATmega6450A__", 1, false},
- {"atmega6450p", "__AVR_ATmega6450P__", 1, false},
- {"atmega6490", "__AVR_ATmega6490__", 1, false},
- {"atmega6490a", "__AVR_ATmega6490A__", 1, false},
- {"atmega6490p", "__AVR_ATmega6490P__", 1, false},
- {"atmega64rfr2", "__AVR_ATmega64RFR2__", 1, false},
- {"atmega644rfr2", "__AVR_ATmega644RFR2__", 1, false},
- {"atmega16hva", "__AVR_ATmega16HVA__", 1, false},
- {"atmega16hva2", "__AVR_ATmega16HVA2__", 1, false},
- {"atmega16hvb", "__AVR_ATmega16HVB__", 1, false},
- {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__", 1, false},
- {"atmega32hvb", "__AVR_ATmega32HVB__", 1, false},
- {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__", 1, false},
- {"atmega64hve", "__AVR_ATmega64HVE__", 1, false},
- {"atmega64hve2", "__AVR_ATmega64HVE2__", 1, false},
- {"at90can32", "__AVR_AT90CAN32__", 1, false},
- {"at90can64", "__AVR_AT90CAN64__", 1, false},
- {"at90pwm161", "__AVR_AT90PWM161__", 1, false},
- {"at90pwm216", "__AVR_AT90PWM216__", 1, false},
- {"at90pwm316", "__AVR_AT90PWM316__", 1, false},
- {"atmega32c1", "__AVR_ATmega32C1__", 1, false},
- {"atmega64c1", "__AVR_ATmega64C1__", 1, false},
- {"atmega16m1", "__AVR_ATmega16M1__", 1, false},
- {"atmega32m1", "__AVR_ATmega32M1__", 1, false},
- {"atmega64m1", "__AVR_ATmega64M1__", 1, false},
- {"atmega16u4", "__AVR_ATmega16U4__", 1, false},
- {"atmega32u4", "__AVR_ATmega32U4__", 1, false},
- {"atmega32u6", "__AVR_ATmega32U6__", 1, false},
- {"at90usb646", "__AVR_AT90USB646__", 1, false},
- {"at90usb647", "__AVR_AT90USB647__", 1, false},
- {"at90scr100", "__AVR_AT90SCR100__", 1, false},
- {"at94k", "__AVR_AT94K__", 1, false},
- {"m3000", "__AVR_AT000__", 1, false},
- {"atmega128", "__AVR_ATmega128__", 2, false},
- {"atmega128a", "__AVR_ATmega128A__", 2, false},
- {"atmega1280", "__AVR_ATmega1280__", 2, false},
- {"atmega1281", "__AVR_ATmega1281__", 2, false},
- {"atmega1284", "__AVR_ATmega1284__", 2, false},
- {"atmega1284p", "__AVR_ATmega1284P__", 2, false},
- {"atmega128rfa1", "__AVR_ATmega128RFA1__", 2, false},
- {"atmega128rfr2", "__AVR_ATmega128RFR2__", 2, false},
- {"atmega1284rfr2", "__AVR_ATmega1284RFR2__", 2, false},
- {"at90can128", "__AVR_AT90CAN128__", 2, false},
- {"at90usb1286", "__AVR_AT90USB1286__", 2, false},
- {"at90usb1287", "__AVR_AT90USB1287__", 2, false},
- {"atmega2560", "__AVR_ATmega2560__", 4, false},
- {"atmega2561", "__AVR_ATmega2561__", 4, false},
- {"atmega256rfr2", "__AVR_ATmega256RFR2__", 4, false},
- {"atmega2564rfr2", "__AVR_ATmega2564RFR2__", 4, false},
- {"atxmega16a4", "__AVR_ATxmega16A4__", 1, false},
- {"atxmega16a4u", "__AVR_ATxmega16A4U__", 1, false},
- {"atxmega16c4", "__AVR_ATxmega16C4__", 1, false},
- {"atxmega16d4", "__AVR_ATxmega16D4__", 1, false},
- {"atxmega32a4", "__AVR_ATxmega32A4__", 1, false},
- {"atxmega32a4u", "__AVR_ATxmega32A4U__", 1, false},
- {"atxmega32c3", "__AVR_ATxmega32C3__", 1, false},
- {"atxmega32c4", "__AVR_ATxmega32C4__", 1, false},
- {"atxmega32d3", "__AVR_ATxmega32D3__", 1, false},
- {"atxmega32d4", "__AVR_ATxmega32D4__", 1, false},
- {"atxmega32e5", "__AVR_ATxmega32E5__", 1, false},
- {"atxmega16e5", "__AVR_ATxmega16E5__", 1, false},
- {"atxmega8e5", "__AVR_ATxmega8E5__", 1, false},
- {"atxmega64a3", "__AVR_ATxmega64A3__", 1, false},
- {"atxmega64a3u", "__AVR_ATxmega64A3U__", 1, false},
- {"atxmega64a4u", "__AVR_ATxmega64A4U__", 1, false},
- {"atxmega64b1", "__AVR_ATxmega64B1__", 1, false},
- {"atxmega64b3", "__AVR_ATxmega64B3__", 1, false},
- {"atxmega64c3", "__AVR_ATxmega64C3__", 1, false},
- {"atxmega64d3", "__AVR_ATxmega64D3__", 1, false},
- {"atxmega64d4", "__AVR_ATxmega64D4__", 1, false},
- {"atxmega64a1", "__AVR_ATxmega64A1__", 1, false},
- {"atxmega64a1u", "__AVR_ATxmega64A1U__", 1, false},
- {"atxmega128a3", "__AVR_ATxmega128A3__", 2, false},
- {"atxmega128a3u", "__AVR_ATxmega128A3U__", 2, false},
- {"atxmega128b1", "__AVR_ATxmega128B1__", 2, false},
- {"atxmega128b3", "__AVR_ATxmega128B3__", 2, false},
- {"atxmega128c3", "__AVR_ATxmega128C3__", 2, false},
- {"atxmega128d3", "__AVR_ATxmega128D3__", 2, false},
- {"atxmega128d4", "__AVR_ATxmega128D4__", 2, false},
- {"atxmega192a3", "__AVR_ATxmega192A3__", 3, false},
- {"atxmega192a3u", "__AVR_ATxmega192A3U__", 3, false},
- {"atxmega192c3", "__AVR_ATxmega192C3__", 3, false},
- {"atxmega192d3", "__AVR_ATxmega192D3__", 3, false},
- {"atxmega256a3", "__AVR_ATxmega256A3__", 4, false},
- {"atxmega256a3u", "__AVR_ATxmega256A3U__", 4, false},
- {"atxmega256a3b", "__AVR_ATxmega256A3B__", 4, false},
- {"atxmega256a3bu", "__AVR_ATxmega256A3BU__", 4, false},
- {"atxmega256c3", "__AVR_ATxmega256C3__", 4, false},
- {"atxmega256d3", "__AVR_ATxmega256D3__", 4, false},
- {"atxmega384c3", "__AVR_ATxmega384C3__", 6, false},
- {"atxmega384d3", "__AVR_ATxmega384D3__", 6, false},
- {"atxmega128a1", "__AVR_ATxmega128A1__", 2, false},
- {"atxmega128a1u", "__AVR_ATxmega128A1U__", 2, false},
- {"atxmega128a4u", "__AVR_ATxmega128A4U__", 2, false},
- {"attiny4", "__AVR_ATtiny4__", 0, true},
- {"attiny5", "__AVR_ATtiny5__", 0, true},
- {"attiny9", "__AVR_ATtiny9__", 0, true},
- {"attiny10", "__AVR_ATtiny10__", 0, true},
- {"attiny20", "__AVR_ATtiny20__", 0, true},
- {"attiny40", "__AVR_ATtiny40__", 0, true},
- {"attiny102", "__AVR_ATtiny102__", 0, true},
- {"attiny104", "__AVR_ATtiny104__", 0, true},
- {"attiny202", "__AVR_ATtiny202__", 1, false},
- {"attiny402", "__AVR_ATtiny402__", 1, false},
- {"attiny204", "__AVR_ATtiny204__", 1, false},
- {"attiny404", "__AVR_ATtiny404__", 1, false},
- {"attiny804", "__AVR_ATtiny804__", 1, false},
- {"attiny1604", "__AVR_ATtiny1604__", 1, false},
- {"attiny406", "__AVR_ATtiny406__", 1, false},
- {"attiny806", "__AVR_ATtiny806__", 1, false},
- {"attiny1606", "__AVR_ATtiny1606__", 1, false},
- {"attiny807", "__AVR_ATtiny807__", 1, false},
- {"attiny1607", "__AVR_ATtiny1607__", 1, false},
- {"attiny212", "__AVR_ATtiny212__", 1, false},
- {"attiny412", "__AVR_ATtiny412__", 1, false},
- {"attiny214", "__AVR_ATtiny214__", 1, false},
- {"attiny414", "__AVR_ATtiny414__", 1, false},
- {"attiny814", "__AVR_ATtiny814__", 1, false},
- {"attiny1614", "__AVR_ATtiny1614__", 1, false},
- {"attiny416", "__AVR_ATtiny416__", 1, false},
- {"attiny816", "__AVR_ATtiny816__", 1, false},
- {"attiny1616", "__AVR_ATtiny1616__", 1, false},
- {"attiny3216", "__AVR_ATtiny3216__", 1, false},
- {"attiny417", "__AVR_ATtiny417__", 1, false},
- {"attiny817", "__AVR_ATtiny817__", 1, false},
- {"attiny1617", "__AVR_ATtiny1617__", 1, false},
- {"attiny3217", "__AVR_ATtiny3217__", 1, false},
- {"attiny1624", "__AVR_ATtiny1624__", 1, false},
- {"attiny1626", "__AVR_ATtiny1626__", 1, false},
- {"attiny1627", "__AVR_ATtiny1627__", 1, false},
- {"atmega808", "__AVR_ATmega808__", 1, false},
- {"atmega809", "__AVR_ATmega809__", 1, false},
- {"atmega1608", "__AVR_ATmega1608__", 1, false},
- {"atmega1609", "__AVR_ATmega1609__", 1, false},
- {"atmega3208", "__AVR_ATmega3208__", 1, false},
- {"atmega3209", "__AVR_ATmega3209__", 1, false},
- {"atmega4808", "__AVR_ATmega4808__", 1, false},
- {"atmega4809", "__AVR_ATmega4809__", 1, false},
+ {"avr1", NULL, "1", 0},
+ {"at90s1200", "__AVR_AT90S1200__", "1", 0},
+ {"attiny11", "__AVR_ATtiny11__", "1", 0},
+ {"attiny12", "__AVR_ATtiny12__", "1", 0},
+ {"attiny15", "__AVR_ATtiny15__", "1", 0},
+ {"attiny28", "__AVR_ATtiny28__", "1", 0},
+ {"avr2", NULL, "2", 1},
+ {"at90s2313", "__AVR_AT90S2313__", "2", 1},
+ {"at90s2323", "__AVR_AT90S2323__", "2", 1},
+ {"at90s2333", "__AVR_AT90S2333__", "2", 1},
+ {"at90s2343", "__AVR_AT90S2343__", "2", 1},
+ {"attiny22", "__AVR_ATtiny22__", "2", 1},
+ {"attiny26", "__AVR_ATtiny26__", "2", 1},
+ {"at86rf401", "__AVR_AT86RF401__", "25", 1},
+ {"at90s4414", "__AVR_AT90S4414__", "2", 1},
+ {"at90s4433", "__AVR_AT90S4433__", "2", 1},
+ {"at90s4434", "__AVR_AT90S4434__", "2", 1},
+ {"at90s8515", "__AVR_AT90S8515__", "2", 1},
+ {"at90c8534", "__AVR_AT90c8534__", "2", 1},
+ {"at90s8535", "__AVR_AT90S8535__", "2", 1},
+ {"avr25", NULL, "25", 1},
+ {"ata5272", "__AVR_ATA5272__", "25", 1},
+ {"ata6616c", "__AVR_ATA6616c__", "25", 1},
+ {"attiny13", "__AVR_ATtiny13__", "25", 1},
+ {"attiny13a", "__AVR_ATtiny13A__", "25", 1},
+ {"attiny2313", "__AVR_ATtiny2313__", "25", 1},
+ {"attiny2313a", "__AVR_ATtiny2313A__", "25", 1},
+ {"attiny24", "__AVR_ATtiny24__", "25", 1},
+ {"attiny24a", "__AVR_ATtiny24A__", "25", 1},
+ {"attiny4313", "__AVR_ATtiny4313__", "25", 1},
+ {"attiny44", "__AVR_ATtiny44__", "25", 1},
+ {"attiny44a", "__AVR_ATtiny44A__", "25", 1},
+ {"attiny84", "__AVR_ATtiny84__", "25", 1},
+ {"attiny84a", "__AVR_ATtiny84A__", "25", 1},
+ {"attiny25", "__AVR_ATtiny25__", "25", 1},
+ {"attiny45", "__AVR_ATtiny45__", "25", 1},
+ {"attiny85", "__AVR_ATtiny85__", "25", 1},
+ {"attiny261", "__AVR_ATtiny261__", "25", 1},
+ {"attiny261a", "__AVR_ATtiny261A__", "25", 1},
+ {"attiny441", "__AVR_ATtiny441__", "25", 1},
+ {"attiny461", "__AVR_ATtiny461__", "25", 1},
+ {"attiny461a", "__AVR_ATtiny461A__", "25", 1},
+ {"attiny841", "__AVR_ATtiny841__", "25", 1},
+ {"attiny861", "__AVR_ATtiny861__", "25", 1},
+ {"attiny861a", "__AVR_ATtiny861A__", "25", 1},
+ {"attiny87", "__AVR_ATtiny87__", "25", 1},
+ {"attiny43u", "__AVR_ATtiny43U__", "25", 1},
+ {"attiny48", "__AVR_ATtiny48__", "25", 1},
+ {"attiny88", "__AVR_ATtiny88__", "25", 1},
+ {"attiny828", "__AVR_ATtiny828__", "25", 1},
+ {"avr3", NULL, "3", 1},
+ {"at43usb355", "__AVR_AT43USB355__", "3", 1},
+ {"at76c711", "__AVR_AT76C711__", "3", 1},
+ {"avr31", NULL, "31", 1},
+ {"atmega103", "__AVR_ATmega103__", "31", 1},
+ {"at43usb320", "__AVR_AT43USB320__", "31", 1},
+ {"avr35", NULL, "35", 1},
+ {"attiny167", "__AVR_ATtiny167__", "35", 1},
+ {"at90usb82", "__AVR_AT90USB82__", "35", 1},
+ {"at90usb162", "__AVR_AT90USB162__", "35", 1},
+ {"ata5505", "__AVR_ATA5505__", "35", 1},
+ {"ata6617c", "__AVR_ATA6617C__", "35", 1},
+ {"ata664251", "__AVR_ATA664251__", "35", 1},
+ {"atmega8u2", "__AVR_ATmega8U2__", "35", 1},
+ {"atmega16u2", "__AVR_ATmega16U2__", "35", 1},
+ {"atmega32u2", "__AVR_ATmega32U2__", "35", 1},
+ {"attiny1634", "__AVR_ATtiny1634__", "35", 1},
+ {"avr4", NULL, "4", 1},
+ {"atmega8", "__AVR_ATmega8__", "4", 1},
+ {"ata6289", "__AVR_ATA6289__", "4", 1},
+ {"atmega8a", "__AVR_ATmega8A__", "4", 1},
+ {"ata6285", "__AVR_ATA6285__", "4", 1},
+ {"ata6286", "__AVR_ATA6286__", "4", 1},
+ {"ata6612c", "__AVR_ATA6612C__", "4", 1},
+ {"atmega48", "__AVR_ATmega48__", "4", 1},
+ {"atmega48a", "__AVR_ATmega48A__", "4", 1},
+ {"atmega48pa", "__AVR_ATmega48PA__", "4", 1},
+ {"atmega48pb", "__AVR_ATmega48PB__", "4", 1},
+ {"atmega48p", "__AVR_ATmega48P__", "4", 1},
+ {"atmega88", "__AVR_ATmega88__", "4", 1},
+ {"atmega88a", "__AVR_ATmega88A__", "4", 1},
+ {"atmega88p", "__AVR_ATmega88P__", "4", 1},
+ {"atmega88pa", "__AVR_ATmega88PA__", "4", 1},
+ {"atmega88pb", "__AVR_ATmega88PB__", "4", 1},
+ {"atmega8515", "__AVR_ATmega8515__", "4", 1},
+ {"atmega8535", "__AVR_ATmega8535__", "4", 1},
+ {"atmega8hva", "__AVR_ATmega8HVA__", "4", 1},
+ {"at90pwm1", "__AVR_AT90PWM1__", "4", 1},
+ {"at90pwm2", "__AVR_AT90PWM2__", "4", 1},
+ {"at90pwm2b", "__AVR_AT90PWM2B__", "4", 1},
+ {"at90pwm3", "__AVR_AT90PWM3__", "4", 1},
+ {"at90pwm3b", "__AVR_AT90PWM3B__", "4", 1},
+ {"at90pwm81", "__AVR_AT90PWM81__", "4", 1},
+ {"avr5", NULL, "5", 1},
+ {"ata5702m322", "__AVR_ATA5702M322__", "5", 1},
+ {"ata5782", "__AVR_ATA5782__", "5", 1},
+ {"ata5790", "__AVR_ATA5790__", "5", 1},
+ {"ata5790n", "__AVR_ATA5790N__", "5", 1},
+ {"ata5791", "__AVR_ATA5791__", "5", 1},
+ {"ata5795", "__AVR_ATA5795__", "5", 1},
+ {"ata5831", "__AVR_ATA5831__", "5", 1},
+ {"ata6613c", "__AVR_ATA6613C__", "5", 1},
+ {"ata6614q", "__AVR_ATA6614Q__", "5", 1},
+ {"ata8210", "__AVR_ATA8210__", "5", 1},
+ {"ata8510", "__AVR_ATA8510__", "5", 1},
+ {"atmega16", "__AVR_ATmega16__", "5", 1},
+ {"atmega16a", "__AVR_ATmega16A__", "5", 1},
+ {"atmega161", "__AVR_ATmega161__", "5", 1},
+ {"atmega162", "__AVR_ATmega162__", "5", 1},
+ {"atmega163", "__AVR_ATmega163__", "5", 1},
+ {"atmega164a", "__AVR_ATmega164A__", "5", 1},
+ {"atmega164p", "__AVR_ATmega164P__", "5", 1},
+ {"atmega164pa", "__AVR_ATmega164PA__", "5", 1},
+ {"atmega165", "__AVR_ATmega165__", "5", 1},
+ {"atmega165a", "__AVR_ATmega165A__", "5", 1},
+ {"atmega165p", "__AVR_ATmega165P__", "5", 1},
+ {"atmega165pa", "__AVR_ATmega165PA__", "5", 1},
+ {"atmega168", "__AVR_ATmega168__", "5", 1},
+ {"atmega168a", "__AVR_ATmega168A__", "5", 1},
+ {"atmega168p", "__AVR_ATmega168P__", "5", 1},
+ {"atmega168pa", "__AVR_ATmega168PA__", "5", 1},
+ {"atmega168pb", "__AVR_ATmega168PB__", "5", 1},
+ {"atmega169", "__AVR_ATmega169__", "5", 1},
+ {"atmega169a", "__AVR_ATmega169A__", "5", 1},
+ {"atmega169p", "__AVR_ATmega169P__", "5", 1},
+ {"atmega169pa", "__AVR_ATmega169PA__", "5", 1},
+ {"atmega32", "__AVR_ATmega32__", "5", 1},
+ {"atmega32a", "__AVR_ATmega32A__", "5", 1},
+ {"atmega323", "__AVR_ATmega323__", "5", 1},
+ {"atmega324a", "__AVR_ATmega324A__", "5", 1},
+ {"atmega324p", "__AVR_ATmega324P__", "5", 1},
+ {"atmega324pa", "__AVR_ATmega324PA__", "5", 1},
+ {"atmega324pb", "__AVR_ATmega324PB__", "5", 1},
+ {"atmega325", "__AVR_ATmega325__", "5", 1},
+ {"atmega325a", "__AVR_ATmega325A__", "5", 1},
+ {"atmega325p", "__AVR_ATmega325P__", "5", 1},
+ {"atmega325pa", "__AVR_ATmega325PA__", "5", 1},
+ {"atmega3250", "__AVR_ATmega3250__", "5", 1},
+ {"atmega3250a", "__AVR_ATmega3250A__", "5", 1},
+ {"atmega3250p", "__AVR_ATmega3250P__", "5", 1},
+ {"atmega3250pa", "__AVR_ATmega3250PA__", "5", 1},
+ {"atmega328", "__AVR_ATmega328__", "5", 1},
+ {"atmega328p", "__AVR_ATmega328P__", "5", 1},
+ {"atmega328pb", "__AVR_ATmega328PB__", "5", 1},
+ {"atmega329", "__AVR_ATmega329__", "5", 1},
+ {"atmega329a", "__AVR_ATmega329A__", "5", 1},
+ {"atmega329p", "__AVR_ATmega329P__", "5", 1},
+ {"atmega329pa", "__AVR_ATmega329PA__", "5", 1},
+ {"atmega3290", "__AVR_ATmega3290__", "5", 1},
+ {"atmega3290a", "__AVR_ATmega3290A__", "5", 1},
+ {"atmega3290p", "__AVR_ATmega3290P__", "5", 1},
+ {"atmega3290pa", "__AVR_ATmega3290PA__", "5", 1},
+ {"atmega406", "__AVR_ATmega406__", "5", 1},
+ {"atmega64", "__AVR_ATmega64__", "5", 1},
+ {"atmega64a", "__AVR_ATmega64A__", "5", 1},
+ {"atmega640", "__AVR_ATmega640__", "5", 1},
+ {"atmega644", "__AVR_ATmega644__", "5", 1},
+ {"atmega644a", "__AVR_ATmega644A__", "5", 1},
+ {"atmega644p", "__AVR_ATmega644P__", "5", 1},
+ {"atmega644pa", "__AVR_ATmega644PA__", "5", 1},
+ {"atmega645", "__AVR_ATmega645__", "5", 1},
+ {"atmega645a", "__AVR_ATmega645A__", "5", 1},
+ {"atmega645p", "__AVR_ATmega645P__", "5", 1},
+ {"atmega649", "__AVR_ATmega649__", "5", 1},
+ {"atmega649a", "__AVR_ATmega649A__", "5", 1},
+ {"atmega649p", "__AVR_ATmega649P__", "5", 1},
+ {"atmega6450", "__AVR_ATmega6450__", "5", 1},
+ {"atmega6450a", "__AVR_ATmega6450A__", "5", 1},
+ {"atmega6450p", "__AVR_ATmega6450P__", "5", 1},
+ {"atmega6490", "__AVR_ATmega6490__", "5", 1},
+ {"atmega6490a", "__AVR_ATmega6490A__", "5", 1},
+ {"atmega6490p", "__AVR_ATmega6490P__", "5", 1},
+ {"atmega64rfr2", "__AVR_ATmega64RFR2__", "5", 1},
+ {"atmega644rfr2", "__AVR_ATmega644RFR2__", "5", 1},
+ {"atmega16hva", "__AVR_ATmega16HVA__", "5", 1},
+ {"atmega16hva2", "__AVR_ATmega16HVA2__", "5", 1},
+ {"atmega16hvb", "__AVR_ATmega16HVB__", "5", 1},
+ {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__", "5", 1},
+ {"atmega32hvb", "__AVR_ATmega32HVB__", "5", 1},
+ {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__", "5", 1},
+ {"atmega64hve", "__AVR_ATmega64HVE__", "5", 1},
+ {"atmega64hve2", "__AVR_ATmega64HVE2__", "5", 1},
+ {"at90can32", "__AVR_AT90CAN32__", "5", 1},
+ {"at90can64", "__AVR_AT90CAN64__", "5", 1},
+ {"at90pwm161", "__AVR_AT90PWM161__", "5", 1},
+ {"at90pwm216", "__AVR_AT90PWM216__", "5", 1},
+ {"at90pwm316", "__AVR_AT90PWM316__", "5", 1},
+ {"atmega32c1", "__AVR_ATmega32C1__", "5", 1},
+ {"atmega64c1", "__AVR_ATmega64C1__", "5", 1},
+ {"atmega16m1", "__AVR_ATmega16M1__", "5", 1},
+ {"atmega32m1", "__AVR_ATmega32M1__", "5", 1},
+ {"atmega64m1", "__AVR_ATmega64M1__", "5", 1},
+ {"atmega16u4", "__AVR_ATmega16U4__", "5", 1},
+ {"atmega32u4", "__AVR_ATmega32U4__", "5", 1},
+ {"atmega32u6", "__AVR_ATmega32U6__", "5", 1},
+ {"at90usb646", "__AVR_AT90USB646__", "5", 1},
+ {"at90usb647", "__AVR_AT90USB647__", "5", 1},
+ {"at90scr100", "__AVR_AT90SCR100__", "5", 1},
+ {"at94k", "__AVR_AT94K__", "5", 1},
+ {"m3000", "__AVR_AT000__", "5", 1},
+ {"avr51", NULL, "51", 2},
+ {"atmega128", "__AVR_ATmega128__", "51", 2},
+ {"atmega128a", "__AVR_ATmega128A__", "51", 2},
+ {"atmega1280", "__AVR_ATmega1280__", "51", 2},
+ {"atmega1281", "__AVR_ATmega1281__", "51", 2},
+ {"atmega1284", "__AVR_ATmega1284__", "51", 2},
+ {"atmega1284p", "__AVR_ATmega1284P__", "51", 2},
+ {"atmega128rfa1", "__AVR_ATmega128RFA1__", "51", 2},
+ {"atmega128rfr2", "__AVR_ATmega128RFR2__", "51", 2},
+ {"atmega1284rfr2", "__AVR_ATmega1284RFR2__", "51", 2},
+ {"at90can128", "__AVR_AT90CAN128__", "51", 2},
+ {"at90usb1286", "__AVR_AT90USB1286__", "51", 2},
+ {"at90usb1287", "__AVR_AT90USB1287__", "51", 2},
+ {"avr6", NULL, "6", 4},
+ {"atmega2560", "__AVR_ATmega2560__", "6", 4},
+ {"atmega2561", "__AVR_ATmega2561__", "6", 4},
+ {"atmega256rfr2", "__AVR_ATmega256RFR2__", "6", 4},
+ {"atmega2564rfr2", "__AVR_ATmega2564RFR2__", "6", 4},
+ {"avrxmega2", NULL, "102", 1},
+ {"atxmega16a4", "__AVR_ATxmega16A4__", "102", 1},
+ {"atxmega16a4u", "__AVR_ATxmega16A4U__", "102", 1},
+ {"atxmega16c4", "__AVR_ATxmega16C4__", "102", 1},
+ {"atxmega16d4", "__AVR_ATxmega16D4__", "102", 1},
+ {"atxmega32a4", "__AVR_ATxmega32A4__", "102", 1},
+ {"atxmega32a4u", "__AVR_ATxmega32A4U__", "102", 1},
+ {"atxmega32c3", "__AVR_ATxmega32C3__", "102", 1},
+ {"atxmega32c4", "__AVR_ATxmega32C4__", "102", 1},
+ {"atxmega32d3", "__AVR_ATxmega32D3__", "102", 1},
+ {"atxmega32d4", "__AVR_ATxmega32D4__", "102", 1},
+ {"atxmega32e5", "__AVR_ATxmega32E5__", "102", 1},
+ {"atxmega16e5", "__AVR_ATxmega16E5__", "102", 1},
+ {"atxmega8e5", "__AVR_ATxmega8E5__", "102", 1},
+ {"avrxmega4", NULL, "104", 1},
+ {"atxmega64a3", "__AVR_ATxmega64A3__", "104", 1},
+ {"atxmega64a3u", "__AVR_ATxmega64A3U__", "104", 1},
+ {"atxmega64a4u", "__AVR_ATxmega64A4U__", "104", 1},
+ {"atxmega64b1", "__AVR_ATxmega64B1__", "104", 1},
+ {"atxmega64b3", "__AVR_ATxmega64B3__", "104", 1},
+ {"atxmega64c3", "__AVR_ATxmega64C3__", "104", 1},
+ {"atxmega64d3", "__AVR_ATxmega64D3__", "104", 1},
+ {"atxmega64d4", "__AVR_ATxmega64D4__", "104", 1},
+ {"avrxmega5", NULL, "105", 1},
+ {"atxmega64a1", "__AVR_ATxmega64A1__", "105", 1},
+ {"atxmega64a1u", "__AVR_ATxmega64A1U__", "105", 1},
+ {"avrxmega6", NULL, "106", 6},
+ {"atxmega128a3", "__AVR_ATxmega128A3__", "106", 2},
+ {"atxmega128a3u", "__AVR_ATxmega128A3U__", "106", 2},
+ {"atxmega128b1", "__AVR_ATxmega128B1__", "106", 2},
+ {"atxmega128b3", "__AVR_ATxmega128B3__", "106", 2},
+ {"atxmega128c3", "__AVR_ATxmega128C3__", "106", 2},
+ {"atxmega128d3", "__AVR_ATxmega128D3__", "106", 2},
+ {"atxmega128d4", "__AVR_ATxmega128D4__", "106", 2},
+ {"atxmega192a3", "__AVR_ATxmega192A3__", "106", 3},
+ {"atxmega192a3u", "__AVR_ATxmega192A3U__", "106", 3},
+ {"atxmega192c3", "__AVR_ATxmega192C3__", "106", 3},
+ {"atxmega192d3", "__AVR_ATxmega192D3__", "106", 3},
+ {"atxmega256a3", "__AVR_ATxmega256A3__", "106", 4},
+ {"atxmega256a3u", "__AVR_ATxmega256A3U__", "106", 4},
+ {"atxmega256a3b", "__AVR_ATxmega256A3B__", "106", 4},
+ {"atxmega256a3bu", "__AVR_ATxmega256A3BU__", "106", 4},
+ {"atxmega256c3", "__AVR_ATxmega256C3__", "106", 4},
+ {"atxmega256d3", "__AVR_ATxmega256D3__", "106", 4},
+ {"atxmega384c3", "__AVR_ATxmega384C3__", "106", 6},
+ {"atxmega384d3", "__AVR_ATxmega384D3__", "106", 6},
+ {"avrxmega7", NULL, "107", 2},
+ {"atxmega128a1", "__AVR_ATxmega128A1__", "107", 2},
+ {"atxmega128a1u", "__AVR_ATxmega128A1U__", "107", 2},
+ {"atxmega128a4u", "__AVR_ATxmega128A4U__", "107", 2},
+ {"avrtiny", NULL, "100", 0},
+ {"attiny4", "__AVR_ATtiny4__", "100", 0},
+ {"attiny5", "__AVR_ATtiny5__", "100", 0},
+ {"attiny9", "__AVR_ATtiny9__", "100", 0},
+ {"attiny10", "__AVR_ATtiny10__", "100", 0},
+ {"attiny20", "__AVR_ATtiny20__", "100", 0},
+ {"attiny40", "__AVR_ATtiny40__", "100", 0},
+ {"attiny102", "__AVR_ATtiny102__", "100", 0},
+ {"attiny104", "__AVR_ATtiny104__", "100", 0},
+ {"avrxmega3", NULL, "103", 1},
+ {"attiny202", "__AVR_ATtiny202__", "103", 1},
+ {"attiny402", "__AVR_ATtiny402__", "103", 1},
+ {"attiny204", "__AVR_ATtiny204__", "103", 1},
+ {"attiny404", "__AVR_ATtiny404__", "103", 1},
+ {"attiny804", "__AVR_ATtiny804__", "103", 1},
+ {"attiny1604", "__AVR_ATtiny1604__", "103", 1},
+ {"attiny406", "__AVR_ATtiny406__", "103", 1},
+ {"attiny806", "__AVR_ATtiny806__", "103", 1},
+ {"attiny1606", "__AVR_ATtiny1606__", "103", 1},
+ {"attiny807", "__AVR_ATtiny807__", "103", 1},
+ {"attiny1607", "__AVR_ATtiny1607__", "103", 1},
+ {"attiny212", "__AVR_ATtiny212__", "103", 1},
+ {"attiny412", "__AVR_ATtiny412__", "103", 1},
+ {"attiny214", "__AVR_ATtiny214__", "103", 1},
+ {"attiny414", "__AVR_ATtiny414__", "103", 1},
+ {"attiny814", "__AVR_ATtiny814__", "103", 1},
+ {"attiny1614", "__AVR_ATtiny1614__", "103", 1},
+ {"attiny416", "__AVR_ATtiny416__", "103", 1},
+ {"attiny816", "__AVR_ATtiny816__", "103", 1},
+ {"attiny1616", "__AVR_ATtiny1616__", "103", 1},
+ {"attiny3216", "__AVR_ATtiny3216__", "103", 1},
+ {"attiny417", "__AVR_ATtiny417__", "103", 1},
+ {"attiny817", "__AVR_ATtiny817__", "103", 1},
+ {"attiny1617", "__AVR_ATtiny1617__", "103", 1},
+ {"attiny3217", "__AVR_ATtiny3217__", "103", 1},
+ {"attiny1624", "__AVR_ATtiny1624__", "103", 1},
+ {"attiny1626", "__AVR_ATtiny1626__", "103", 1},
+ {"attiny1627", "__AVR_ATtiny1627__", "103", 1},
+ {"atmega808", "__AVR_ATmega808__", "103", 1},
+ {"atmega809", "__AVR_ATmega809__", "103", 1},
+ {"atmega1608", "__AVR_ATmega1608__", "103", 1},
+ {"atmega1609", "__AVR_ATmega1609__", "103", 1},
+ {"atmega3208", "__AVR_ATmega3208__", "103", 1},
+ {"atmega3209", "__AVR_ATmega3209__", "103", 1},
+ {"atmega4808", "__AVR_ATmega4808__", "103", 1},
+ {"atmega4809", "__AVR_ATmega4809__", "103", 1},
};
} // namespace targets
} // namespace clang
-static constexpr llvm::StringLiteral ValidFamilyNames[] = {
- "avr1", "avr2", "avr25", "avr3", "avr31",
- "avr35", "avr4", "avr5", "avr51", "avr6",
- "avrxmega1", "avrxmega2", "avrxmega3", "avrxmega4", "avrxmega5",
- "avrxmega6", "avrxmega7", "avrtiny"};
+static bool ArchHasELPM(StringRef Arch) {
+ return llvm::StringSwitch<bool>(Arch)
+ .Cases("31", "51", "6", true)
+ .Cases("102", "104", "105", "106", "107", true)
+ .Default(false);
+}
-bool AVRTargetInfo::isValidCPUName(StringRef Name) const {
- bool IsFamily = llvm::is_contained(ValidFamilyNames, Name);
+static bool ArchHasELPMX(StringRef Arch) {
+ return llvm::StringSwitch<bool>(Arch)
+ .Cases("51", "6", true)
+ .Cases("102", "104", "105", "106", "107", true)
+ .Default(false);
+}
+
+static bool ArchHasMOVW(StringRef Arch) {
+ return llvm::StringSwitch<bool>(Arch)
+ .Cases("25", "35", "4", "5", "51", "6", true)
+ .Cases("102", "103", "104", "105", "106", "107", true)
+ .Default(false);
+}
+
+static bool ArchHasLPMX(StringRef Arch) {
+ return ArchHasMOVW(Arch); // same architectures
+}
+
+static bool ArchHasMUL(StringRef Arch) {
+ return llvm::StringSwitch<bool>(Arch)
+ .Cases("4", "5", "51", "6", true)
+ .Cases("102", "103", "104", "105", "106", "107", true)
+ .Default(false);
+}
+
+static bool ArchHasJMPCALL(StringRef Arch) {
+ return llvm::StringSwitch<bool>(Arch)
+ .Cases("3", "31", "35", "5", "51", "6", true)
+ .Cases("102", "103", "104", "105", "106", "107", true)
+ .Default(false);
+}
+
+static bool ArchHas3BytePC(StringRef Arch) {
+ // These devices have more than 128kB of program memory.
+ // Note:
+ // - Not fully correct for arch 106: only about half the chips have more
+ // than 128kB program memory and therefore a 3 byte PC.
+ // - Doesn't match GCC entirely: avr-gcc thinks arch 107 goes beyond 128kB
+ // but in fact it doesn't.
+ return llvm::StringSwitch<bool>(Arch)
+ .Case("6", true)
+ .Case("106", true)
+ .Default(false);
+}
- bool IsMCU = llvm::any_of(
+bool AVRTargetInfo::isValidCPUName(StringRef Name) const {
+ return llvm::any_of(
AVRMcus, [&](const MCUInfo &Info) { return Info.Name == Name; });
- return IsFamily || IsMCU;
}
void AVRTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const {
- Values.append(std::begin(ValidFamilyNames), std::end(ValidFamilyNames));
for (const MCUInfo &Info : AVRMcus)
Values.push_back(Info.Name);
}
bool AVRTargetInfo::setCPU(const std::string &Name) {
- // Set the ABI and CPU fields if parameter Name is a family name.
- if (llvm::is_contained(ValidFamilyNames, Name)) {
- CPU = Name;
- ABI = Name == "avrtiny" ? "avrtiny" : "avr";
- return true;
- }
-
- // Set the ABI field if parameter Name is a device name.
+ // Set the ABI field based on the device or family name.
auto It = llvm::find_if(
AVRMcus, [&](const MCUInfo &Info) { return Info.Name == Name; });
if (It != std::end(AVRMcus)) {
CPU = Name;
- ABI = It->IsTiny ? "avrtiny" : "avr";
+ ABI = (It->Arch == "100") ? "avrtiny" : "avr";
+ DefineName = It->DefineName;
+ Arch = It->Arch;
+ NumFlashBanks = It->NumFlashBanks;
return true;
}
@@ -383,24 +438,45 @@ void AVRTargetInfo::getTargetDefines(const LangOptions &Opts,
if (ABI == "avrtiny")
Builder.defineMacro("__AVR_TINY__", "1");
- if (!this->CPU.empty()) {
- auto It = llvm::find_if(
- AVRMcus, [&](const MCUInfo &Info) { return Info.Name == this->CPU; });
+ if (DefineName.size() != 0)
+ Builder.defineMacro(DefineName);
- if (It != std::end(AVRMcus)) {
- Builder.defineMacro(It->DefineName);
- if (It->NumFlashBanks >= 1)
- Builder.defineMacro("__flash", "__attribute__((address_space(1)))");
- if (It->NumFlashBanks >= 2)
- Builder.defineMacro("__flash1", "__attribute__((address_space(2)))");
- if (It->NumFlashBanks >= 3)
- Builder.defineMacro("__flash2", "__attribute__((address_space(3)))");
- if (It->NumFlashBanks >= 4)
- Builder.defineMacro("__flash3", "__attribute__((address_space(4)))");
- if (It->NumFlashBanks >= 5)
- Builder.defineMacro("__flash4", "__attribute__((address_space(5)))");
- if (It->NumFlashBanks >= 6)
- Builder.defineMacro("__flash5", "__attribute__((address_space(6)))");
- }
+ Builder.defineMacro("__AVR_ARCH__", Arch);
+
+ // TODO: perhaps we should use the information from AVRDevices.td instead?
+ if (ArchHasELPM(Arch))
+ Builder.defineMacro("__AVR_HAVE_ELPM__");
+ if (ArchHasELPMX(Arch))
+ Builder.defineMacro("__AVR_HAVE_ELPMX__");
+ if (ArchHasMOVW(Arch))
+ Builder.defineMacro("__AVR_HAVE_MOVW__");
+ if (ArchHasLPMX(Arch))
+ Builder.defineMacro("__AVR_HAVE_LPMX__");
+ if (ArchHasMUL(Arch))
+ Builder.defineMacro("__AVR_HAVE_MUL__");
+ if (ArchHasJMPCALL(Arch))
+ Builder.defineMacro("__AVR_HAVE_JMP_CALL__");
+ if (ArchHas3BytePC(Arch)) {
+ // Note: some devices do support eijmp/eicall even though this macro isn't
+ // set. This is the case if they have less than 128kB flash and so
+ // eijmp/eicall isn't very useful anyway. (This matches gcc, although it's
+ // debatable whether we should be bug-compatible in this case).
+ Builder.defineMacro("__AVR_HAVE_EIJMP_EICALL__");
+ Builder.defineMacro("__AVR_3_BYTE_PC__");
+ } else {
+ Builder.defineMacro("__AVR_2_BYTE_PC__");
}
+
+ if (NumFlashBanks >= 1)
+ Builder.defineMacro("__flash", "__attribute__((__address_space__(1)))");
+ if (NumFlashBanks >= 2)
+ Builder.defineMacro("__flash1", "__attribute__((__address_space__(2)))");
+ if (NumFlashBanks >= 3)
+ Builder.defineMacro("__flash2", "__attribute__((__address_space__(3)))");
+ if (NumFlashBanks >= 4)
+ Builder.defineMacro("__flash3", "__attribute__((__address_space__(4)))");
+ if (NumFlashBanks >= 5)
+ Builder.defineMacro("__flash4", "__attribute__((__address_space__(5)))");
+ if (NumFlashBanks >= 6)
+ Builder.defineMacro("__flash5", "__attribute__((__address_space__(6)))");
}
diff --git a/clang/lib/Basic/Targets/AVR.h b/clang/lib/Basic/Targets/AVR.h
index 74b012a0923b..7730bb8e5132 100644
--- a/clang/lib/Basic/Targets/AVR.h
+++ b/clang/lib/Basic/Targets/AVR.h
@@ -55,14 +55,15 @@ public:
Int16Type = SignedInt;
Char32Type = UnsignedLong;
SigAtomicType = SignedChar;
- ProgramAddrSpace = 1;
resetDataLayout("e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8");
}
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override;
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ return std::nullopt;
+ }
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
@@ -75,11 +76,11 @@ public:
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
"r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
"r20", "r21", "r22", "r23", "r24", "r25", "X", "Y", "Z", "SP"};
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override {
@@ -89,7 +90,7 @@ public:
{{"r30", "r31"}, 28},
{{"SPL", "SPH"}, 29},
};
- return llvm::makeArrayRef(AddlRegNames);
+ return llvm::ArrayRef(AddlRegNames);
}
bool validateAsmConstraint(const char *&Name,
@@ -174,6 +175,9 @@ public:
protected:
std::string CPU;
StringRef ABI;
+ StringRef DefineName;
+ StringRef Arch;
+ int NumFlashBanks = 0;
};
} // namespace targets
diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp
index 2dfe21564cc1..c9095c28aec2 100644
--- a/clang/lib/Basic/Targets/BPF.cpp
+++ b/clang/lib/Basic/Targets/BPF.cpp
@@ -19,9 +19,9 @@
using namespace clang;
using namespace clang::targets;
-const Builtin::Info BPFTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsBPF.def"
};
@@ -43,8 +43,8 @@ void BPFTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const {
}
ArrayRef<Builtin::Info> BPFTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::BPF::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::BPF::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
bool BPFTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h
index 393a91ff53a5..4750e3e9bf9b 100644
--- a/clang/lib/Basic/Targets/BPF.h
+++ b/clang/lib/Basic/Targets/BPF.h
@@ -22,7 +22,6 @@ namespace clang {
namespace targets {
class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
bool HasAlu32 = false;
public:
@@ -68,7 +67,9 @@ public:
}
bool isValidGCCRegisterName(StringRef Name) const override { return true; }
- ArrayRef<const char *> getGCCRegNames() const override { return None; }
+ ArrayRef<const char *> getGCCRegNames() const override {
+ return std::nullopt;
+ }
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const override {
@@ -85,7 +86,7 @@ public:
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
bool allowDebugInfoForExternalRef() const override { return true; }
diff --git a/clang/lib/Basic/Targets/CSKY.cpp b/clang/lib/Basic/Targets/CSKY.cpp
index adcffd90ae78..f272bedc170b 100644
--- a/clang/lib/Basic/Targets/CSKY.cpp
+++ b/clang/lib/Basic/Targets/CSKY.cpp
@@ -213,7 +213,7 @@ ArrayRef<const char *> CSKYTargetInfo::getGCCRegNames() const {
"fr31",
};
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::GCCRegAlias> CSKYTargetInfo::getGCCRegAliases() const {
@@ -285,7 +285,7 @@ ArrayRef<TargetInfo::GCCRegAlias> CSKYTargetInfo::getGCCRegAliases() const {
{{"vr31"}, "fr31"},
};
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
bool CSKYTargetInfo::validateAsmConstraint(
diff --git a/clang/lib/Basic/Targets/DirectX.h b/clang/lib/Basic/Targets/DirectX.h
index a773090b413f..06cfa79756f9 100644
--- a/clang/lib/Basic/Targets/DirectX.h
+++ b/clang/lib/Basic/Targets/DirectX.h
@@ -40,7 +40,8 @@ static const unsigned DirectXAddrSpaceMap[] = {
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
- 0 // ptr64
+ 0, // ptr64
+ 3, // hlsl_groupshared
};
class LLVM_LIBRARY_VISIBILITY DirectXTargetInfo : public TargetInfo {
@@ -55,6 +56,8 @@ public:
HasLegalHalfType = true;
HasFloat16 = true;
NoAsmVariants = true;
+ PlatformMinVersion = Triple.getOSVersion();
+ PlatformName = llvm::Triple::getOSTypeName(Triple.getOS());
resetDataLayout("e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:"
"32-f64:64-n8:16:32:64");
TheCXXABI.set(TargetCXXABI::Microsoft);
@@ -67,11 +70,15 @@ public:
return Feature == "directx";
}
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ return std::nullopt;
+ }
const char *getClobbers() const override { return ""; }
- ArrayRef<const char *> getGCCRegNames() const override { return None; }
+ ArrayRef<const char *> getGCCRegNames() const override {
+ return std::nullopt;
+ }
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override {
@@ -79,7 +86,7 @@ public:
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
BuiltinVaListKind getBuiltinVaListKind() const override {
diff --git a/clang/lib/Basic/Targets/Hexagon.cpp b/clang/lib/Basic/Targets/Hexagon.cpp
index 161369242926..0b98c48fea55 100644
--- a/clang/lib/Basic/Targets/Hexagon.cpp
+++ b/clang/lib/Basic/Targets/Hexagon.cpp
@@ -71,6 +71,15 @@ void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
} else if (CPU == "hexagonv69") {
Builder.defineMacro("__HEXAGON_V69__");
Builder.defineMacro("__HEXAGON_ARCH__", "69");
+ } else if (CPU == "hexagonv71") {
+ Builder.defineMacro("__HEXAGON_V71__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "71");
+ } else if (CPU == "hexagonv71t") {
+ Builder.defineMacro("__HEXAGON_V71T__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "71");
+ } else if (CPU == "hexagonv73") {
+ Builder.defineMacro("__HEXAGON_V73__");
+ Builder.defineMacro("__HEXAGON_ARCH__", "73");
}
if (hasFeature("hvx-length64b")) {
@@ -93,6 +102,11 @@ void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts,
std::string NumPhySlots = isTinyCore() ? "3" : "4";
Builder.defineMacro("__HEXAGON_PHYSICAL_SLOTS__", NumPhySlots);
+
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
}
bool HexagonTargetInfo::initFeatureMap(
@@ -173,7 +187,7 @@ const char *const HexagonTargetInfo::GCCRegNames[] = {
};
ArrayRef<const char *> HexagonTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = {
@@ -183,16 +197,16 @@ const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = {
};
ArrayRef<TargetInfo::GCCRegAlias> HexagonTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
-const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsHexagon.def"
};
@@ -222,6 +236,8 @@ static constexpr CPUSuffix Suffixes[] = {
{{"hexagonv65"}, {"65"}}, {{"hexagonv66"}, {"66"}},
{{"hexagonv67"}, {"67"}}, {{"hexagonv67t"}, {"67t"}},
{{"hexagonv68"}, {"68"}}, {{"hexagonv69"}, {"69"}},
+ {{"hexagonv71"}, {"71"}}, {{"hexagonv71t"}, {"71t"}},
+ {{"hexagonv73"}, {"73"}},
};
const char *HexagonTargetInfo::getHexagonCPUSuffix(StringRef Name) {
@@ -239,6 +255,6 @@ void HexagonTargetInfo::fillValidCPUList(
}
ArrayRef<Builtin::Info> HexagonTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
}
diff --git a/clang/lib/Basic/Targets/Hexagon.h b/clang/lib/Basic/Targets/Hexagon.h
index 94441998f355..191d99b11d53 100644
--- a/clang/lib/Basic/Targets/Hexagon.h
+++ b/clang/lib/Basic/Targets/Hexagon.h
@@ -24,7 +24,6 @@ namespace targets {
// Hexagon abstract base class
class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
static const char *const GCCRegNames[];
static const TargetInfo::GCCRegAlias GCCRegAliases[];
std::string CPU;
diff --git a/clang/lib/Basic/Targets/Lanai.cpp b/clang/lib/Basic/Targets/Lanai.cpp
index bb1872083c09..8722a369ed87 100644
--- a/clang/lib/Basic/Targets/Lanai.cpp
+++ b/clang/lib/Basic/Targets/Lanai.cpp
@@ -24,7 +24,7 @@ const char *const LanaiTargetInfo::GCCRegNames[] = {
};
ArrayRef<const char *> LanaiTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = {
@@ -33,7 +33,7 @@ const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = {
};
ArrayRef<TargetInfo::GCCRegAlias> LanaiTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
bool LanaiTargetInfo::isValidCPUName(StringRef Name) const {
diff --git a/clang/lib/Basic/Targets/Lanai.h b/clang/lib/Basic/Targets/Lanai.h
index 56c6cced938a..6ab4aea6ac4a 100644
--- a/clang/lib/Basic/Targets/Lanai.h
+++ b/clang/lib/Basic/Targets/Lanai.h
@@ -78,7 +78,9 @@ public:
return TargetInfo::VoidPtrBuiltinVaList;
}
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ return std::nullopt;
+ }
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override {
diff --git a/clang/lib/Basic/Targets/Le64.h b/clang/lib/Basic/Targets/Le64.h
index 13a0b04d9f09..6652bcea78df 100644
--- a/clang/lib/Basic/Targets/Le64.h
+++ b/clang/lib/Basic/Targets/Le64.h
@@ -43,10 +43,12 @@ public:
const char *getClobbers() const override { return ""; }
- ArrayRef<const char *> getGCCRegNames() const override { return None; }
+ ArrayRef<const char *> getGCCRegNames() const override {
+ return std::nullopt;
+ }
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
bool validateAsmConstraint(const char *&Name,
diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp
new file mode 100644
index 000000000000..2079c89e3e15
--- /dev/null
+++ b/clang/lib/Basic/Targets/LoongArch.cpp
@@ -0,0 +1,217 @@
+//===--- LoongArch.cpp - Implement LoongArch target feature support -------===//
+//
+// 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 implements LoongArch TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LoongArch.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::targets;
+
+ArrayRef<const char *> LoongArchTargetInfo::getGCCRegNames() const {
+ static const char *const GCCRegNames[] = {
+ // General purpose registers.
+ "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9",
+ "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", "$r17", "$r18",
+ "$r19", "$r20", "$r21", "$r22", "$r23", "$r24", "$r25", "$r26", "$r27",
+ "$r28", "$r29", "$r30", "$r31",
+ // 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::ArrayRef(GCCRegNames);
+}
+
+ArrayRef<TargetInfo::GCCRegAlias>
+LoongArchTargetInfo::getGCCRegAliases() const {
+ static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
+ {{"$zero"}, "$r0"}, {{"$ra"}, "$r1"}, {{"$tp"}, "$r2"},
+ {{"$sp"}, "$r3"}, {{"$a0"}, "$r4"}, {{"$a1"}, "$r5"},
+ {{"$a2"}, "$r6"}, {{"$a3"}, "$r7"}, {{"$a4"}, "$r8"},
+ {{"$a5"}, "$r9"}, {{"$a6"}, "$r10"}, {{"$a7"}, "$r11"},
+ {{"$t0"}, "$r12"}, {{"$t1"}, "$r13"}, {{"$t2"}, "$r14"},
+ {{"$t3"}, "$r15"}, {{"$t4"}, "$r16"}, {{"$t5"}, "$r17"},
+ {{"$t6"}, "$r18"}, {{"$t7"}, "$r19"}, {{"$t8"}, "$r20"},
+ {{"$fp", "$s9"}, "$r22"}, {{"$s0"}, "$r23"}, {{"$s1"}, "$r24"},
+ {{"$s2"}, "$r25"}, {{"$s3"}, "$r26"}, {{"$s4"}, "$r27"},
+ {{"$s5"}, "$r28"}, {{"$s6"}, "$r29"}, {{"$s7"}, "$r30"},
+ {{"$s8"}, "$r31"}, {{"$fa0"}, "$f0"}, {{"$fa1"}, "$f1"},
+ {{"$fa2"}, "$f2"}, {{"$fa3"}, "$f3"}, {{"$fa4"}, "$f4"},
+ {{"$fa5"}, "$f5"}, {{"$fa6"}, "$f6"}, {{"$fa7"}, "$f7"},
+ {{"$ft0"}, "$f8"}, {{"$ft1"}, "$f9"}, {{"$ft2"}, "$f10"},
+ {{"$ft3"}, "$f11"}, {{"$ft4"}, "$f12"}, {{"$ft5"}, "$f13"},
+ {{"$ft6"}, "$f14"}, {{"$ft7"}, "$f15"}, {{"$ft8"}, "$f16"},
+ {{"$ft9"}, "$f17"}, {{"$ft10"}, "$f18"}, {{"$ft11"}, "$f19"},
+ {{"$ft12"}, "$f20"}, {{"$ft13"}, "$f21"}, {{"$ft14"}, "$f22"},
+ {{"$ft15"}, "$f23"}, {{"$fs0"}, "$f24"}, {{"$fs1"}, "$f25"},
+ {{"$fs2"}, "$f26"}, {{"$fs3"}, "$f27"}, {{"$fs4"}, "$f28"},
+ {{"$fs5"}, "$f29"}, {{"$fs6"}, "$f30"}, {{"$fs7"}, "$f31"},
+ };
+ return llvm::ArrayRef(GCCRegAliases);
+}
+
+bool LoongArchTargetInfo::validateAsmConstraint(
+ const char *&Name, TargetInfo::ConstraintInfo &Info) const {
+ // See the GCC definitions here:
+ // https://gcc.gnu.org/onlinedocs/gccint/Machine-Constraints.html
+ // Note that the 'm' constraint is handled in TargetInfo.
+ switch (*Name) {
+ default:
+ return false;
+ case 'f':
+ // A floating-point register (if available).
+ Info.setAllowsRegister();
+ return true;
+ case 'k':
+ // A memory operand whose address is formed by a base register and
+ // (optionally scaled) index register.
+ Info.setAllowsMemory();
+ return true;
+ case 'l':
+ // A signed 16-bit constant.
+ Info.setRequiresImmediate(-32768, 32767);
+ return true;
+ case 'I':
+ // A signed 12-bit constant (for arithmetic instructions).
+ Info.setRequiresImmediate(-2048, 2047);
+ return true;
+ case 'J':
+ // Integer zero.
+ Info.setRequiresImmediate(0);
+ return true;
+ case 'K':
+ // An unsigned 12-bit constant (for logic instructions).
+ Info.setRequiresImmediate(0, 4095);
+ return true;
+ case 'Z':
+ // ZB: An address that is held in a general-purpose register. The offset is
+ // zero.
+ // ZC: A memory operand whose address is formed by a base register
+ // and offset that is suitable for use in instructions with the same
+ // addressing mode as ll.w and sc.w.
+ if (Name[1] == 'C' || Name[1] == 'B') {
+ Info.setAllowsMemory();
+ ++Name; // Skip over 'Z'.
+ return true;
+ }
+ return false;
+ }
+}
+
+std::string
+LoongArchTargetInfo::convertConstraint(const char *&Constraint) const {
+ std::string R;
+ switch (*Constraint) {
+ case 'Z':
+ // "ZC"/"ZB" are two-character constraints; add "^" hint for later
+ // parsing.
+ R = "^" + std::string(Constraint, 2);
+ ++Constraint;
+ break;
+ default:
+ R = TargetInfo::convertConstraint(Constraint);
+ break;
+ }
+ return R;
+}
+
+void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ Builder.defineMacro("__loongarch__");
+ unsigned GRLen = getRegisterWidth();
+ Builder.defineMacro("__loongarch_grlen", Twine(GRLen));
+ if (GRLen == 64)
+ Builder.defineMacro("__loongarch64");
+
+ if (HasFeatureD)
+ Builder.defineMacro("__loongarch_frlen", "64");
+ else if (HasFeatureF)
+ Builder.defineMacro("__loongarch_frlen", "32");
+ else
+ Builder.defineMacro("__loongarch_frlen", "0");
+
+ // TODO: define __loongarch_arch and __loongarch_tune.
+
+ StringRef ABI = getABI();
+ if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")
+ Builder.defineMacro("__loongarch_lp64");
+
+ if (ABI == "lp64d" || ABI == "ilp32d") {
+ Builder.defineMacro("__loongarch_hard_float");
+ Builder.defineMacro("__loongarch_double_float");
+ } else if (ABI == "lp64f" || ABI == "ilp32f") {
+ Builder.defineMacro("__loongarch_hard_float");
+ Builder.defineMacro("__loongarch_single_float");
+ } else if (ABI == "lp64s" || ABI == "ilp32s") {
+ Builder.defineMacro("__loongarch_soft_float");
+ }
+
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ if (GRLen == 64)
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+}
+
+static constexpr Builtin::Info BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
+#include "clang/Basic/BuiltinsLoongArch.def"
+};
+
+bool LoongArchTargetInfo::initFeatureMap(
+ llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const {
+ if (getTriple().getArch() == llvm::Triple::loongarch64)
+ Features["64bit"] = true;
+ if (getTriple().getArch() == llvm::Triple::loongarch32)
+ Features["32bit"] = true;
+
+ return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
+}
+
+/// Return true if has this feature.
+bool LoongArchTargetInfo::hasFeature(StringRef Feature) const {
+ bool Is64Bit = getTriple().getArch() == llvm::Triple::loongarch64;
+ // TODO: Handle more features.
+ return llvm::StringSwitch<bool>(Feature)
+ .Case("loongarch32", !Is64Bit)
+ .Case("loongarch64", Is64Bit)
+ .Case("32bit", !Is64Bit)
+ .Case("64bit", Is64Bit)
+ .Default(false);
+}
+
+ArrayRef<Builtin::Info> LoongArchTargetInfo::getTargetBuiltins() const {
+ return llvm::ArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
+
+bool LoongArchTargetInfo::handleTargetFeatures(
+ std::vector<std::string> &Features, DiagnosticsEngine &Diags) {
+ for (const auto &Feature : Features) {
+ if (Feature == "+d" || Feature == "+f") {
+ // "d" implies "f".
+ HasFeatureF = true;
+ if (Feature == "+d") {
+ HasFeatureD = true;
+ }
+ }
+ }
+ return true;
+}
diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h
new file mode 100644
index 000000000000..646c8d071f1d
--- /dev/null
+++ b/clang/lib/Basic/Targets/LoongArch.h
@@ -0,0 +1,136 @@
+//===-- LoongArch.h - Declare LoongArch target feature support --*- 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 declares LoongArch TargetInfo objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_LOONGARCH_H
+#define LLVM_CLANG_LIB_BASIC_TARGETS_LOONGARCH_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+namespace targets {
+
+class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
+protected:
+ std::string ABI;
+ bool HasFeatureD;
+ bool HasFeatureF;
+
+public:
+ LoongArchTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+ : TargetInfo(Triple) {
+ HasFeatureD = false;
+ HasFeatureF = false;
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 128;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad();
+ SuitableAlign = 128;
+ WCharType = SignedInt;
+ WIntType = UnsignedInt;
+ }
+
+ StringRef getABI() const override { return ABI; }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override;
+
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
+
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+
+ const char *getClobbers() const override { return ""; }
+
+ ArrayRef<const char *> getGCCRegNames() const override;
+
+ int getEHDataRegisterNumber(unsigned RegNo) const override {
+ if (RegNo == 0)
+ return 4;
+ if (RegNo == 1)
+ return 5;
+ return -1;
+ }
+
+ ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
+
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const override;
+ std::string convertConstraint(const char *&Constraint) const override;
+
+ bool hasBitIntType() const override { return true; }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override;
+
+ bool
+ initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
+ StringRef CPU,
+ const std::vector<std::string> &FeaturesVec) const override;
+
+ bool hasFeature(StringRef Feature) const override;
+};
+
+class LLVM_LIBRARY_VISIBILITY LoongArch32TargetInfo
+ : public LoongArchTargetInfo {
+public:
+ LoongArch32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : LoongArchTargetInfo(Triple, Opts) {
+ IntPtrType = SignedInt;
+ PtrDiffType = SignedInt;
+ SizeType = UnsignedInt;
+ resetDataLayout("e-m:e-p:32:32-i64:64-n32-S128");
+ // TODO: select appropriate ABI.
+ setABI("ilp32d");
+ }
+
+ bool setABI(const std::string &Name) override {
+ if (Name == "ilp32d" || Name == "ilp32f" || Name == "ilp32s") {
+ ABI = Name;
+ return true;
+ }
+ return false;
+ }
+ void setMaxAtomicWidth() override {
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY LoongArch64TargetInfo
+ : public LoongArchTargetInfo {
+public:
+ LoongArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
+ : LoongArchTargetInfo(Triple, Opts) {
+ LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+ IntMaxType = Int64Type = SignedLong;
+ resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n64-S128");
+ // TODO: select appropriate ABI.
+ setABI("lp64d");
+ }
+
+ bool setABI(const std::string &Name) override {
+ if (Name == "lp64d" || Name == "lp64f" || Name == "lp64s") {
+ ABI = Name;
+ return true;
+ }
+ return false;
+ }
+ void setMaxAtomicWidth() override {
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ }
+};
+} // end namespace targets
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_BASIC_TARGETS_LOONGARCH_H
diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp
index ada5b97ed66d..6c2d77444f13 100644
--- a/clang/lib/Basic/Targets/M68k.cpp
+++ b/clang/lib/Basic/Targets/M68k.cpp
@@ -21,6 +21,7 @@
#include <cstdint>
#include <cstring>
#include <limits>
+#include <optional>
namespace clang {
namespace targets {
@@ -113,11 +114,17 @@ void M68kTargetInfo::getTargetDefines(const LangOptions &Opts,
default:
break;
}
+
+ if (CPU >= CK_68020) {
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ }
}
ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const {
// FIXME: Implement.
- return None;
+ return std::nullopt;
}
bool M68kTargetInfo::hasFeature(StringRef Feature) const {
@@ -131,12 +138,12 @@ const char *const M68kTargetInfo::GCCRegNames[] = {
"pc"};
ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const {
// No aliases.
- return None;
+ return std::nullopt;
}
bool M68kTargetInfo::validateAsmConstraint(
@@ -191,7 +198,7 @@ bool M68kTargetInfo::validateAsmConstraint(
return false;
}
-llvm::Optional<std::string>
+std::optional<std::string>
M68kTargetInfo::handleAsmEscapedChar(char EscChar) const {
char C;
switch (EscChar) {
@@ -209,7 +216,7 @@ M68kTargetInfo::handleAsmEscapedChar(char EscChar) const {
C = 'd';
break;
default:
- return llvm::None;
+ return std::nullopt;
}
return std::string(1, C);
diff --git a/clang/lib/Basic/Targets/M68k.h b/clang/lib/Basic/Targets/M68k.h
index a42ca674ef9c..16b32248418c 100644
--- a/clang/lib/Basic/Targets/M68k.h
+++ b/clang/lib/Basic/Targets/M68k.h
@@ -18,6 +18,7 @@
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
+#include <optional>
namespace clang {
namespace targets {
@@ -47,7 +48,7 @@ public:
std::string convertConstraint(const char *&Constraint) const override;
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override;
- llvm::Optional<std::string> handleAsmEscapedChar(char EscChar) const override;
+ std::optional<std::string> handleAsmEscapedChar(char EscChar) const override;
const char *getClobbers() const override;
BuiltinVaListKind getBuiltinVaListKind() const override;
bool setCPU(const std::string &Name) override;
diff --git a/clang/lib/Basic/Targets/MSP430.cpp b/clang/lib/Basic/Targets/MSP430.cpp
index 90890500ae27..de8704fe97e7 100644
--- a/clang/lib/Basic/Targets/MSP430.cpp
+++ b/clang/lib/Basic/Targets/MSP430.cpp
@@ -22,7 +22,7 @@ const char *const MSP430TargetInfo::GCCRegNames[] = {
};
ArrayRef<const char *> MSP430TargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
void MSP430TargetInfo::getTargetDefines(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/MSP430.h b/clang/lib/Basic/Targets/MSP430.h
index 9d42e4d4bb18..3761fc7667b8 100644
--- a/clang/lib/Basic/Targets/MSP430.h
+++ b/clang/lib/Basic/Targets/MSP430.h
@@ -52,7 +52,7 @@ public:
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
// FIXME: Implement.
- return None;
+ return std::nullopt;
}
bool allowsLargerPreferedTypeAlignment() const override { return false; }
@@ -71,7 +71,7 @@ public:
{{"r2"}, "sr"},
{{"r3"}, "cg"},
};
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
bool validateAsmConstraint(const char *&Name,
diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp
index 39246f650cce..078a8fe62ac2 100644
--- a/clang/lib/Basic/Targets/Mips.cpp
+++ b/clang/lib/Basic/Targets/Mips.cpp
@@ -20,11 +20,11 @@
using namespace clang;
using namespace clang::targets;
-const Builtin::Info MipsTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsMips.def"
};
@@ -182,7 +182,7 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts,
if (DisableMadd4)
Builder.defineMacro("__mips_no_madd4", Twine(1));
- Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0)));
+ Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(LangAS::Default)));
Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth()));
Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth()));
@@ -195,11 +195,11 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts,
if (StringRef(CPU).startswith("octeon"))
Builder.defineMacro("__OCTEON__");
- // These shouldn't be defined for MIPS-I but there's no need to check
- // for that since MIPS-I isn't supported.
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
- Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ if (CPU != "mips1") {
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ }
// 32-bit MIPS processors don't have the necessary lld/scd instructions
// found in 64-bit processors. In the case of O32 on a 64-bit processor,
@@ -220,8 +220,8 @@ bool MipsTargetInfo::hasFeature(StringRef Feature) const {
}
ArrayRef<Builtin::Info> MipsTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::Mips::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
unsigned MipsTargetInfo::getUnwindWordWidth() const {
@@ -229,7 +229,7 @@ unsigned MipsTargetInfo::getUnwindWordWidth() const {
.Case("o32", 32)
.Case("n32", 64)
.Case("n64", 64)
- .Default(getPointerWidth(0));
+ .Default(getPointerWidth(LangAS::Default));
}
bool MipsTargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h
index b54d36e1c95f..9e84dbc386ed 100644
--- a/clang/lib/Basic/Targets/Mips.h
+++ b/clang/lib/Basic/Targets/Mips.h
@@ -40,7 +40,6 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo {
resetDataLayout(("e-" + Layout).str());
}
- static const Builtin::Info BuiltinInfo[];
std::string CPU;
bool IsMips16;
bool IsMicromips;
@@ -226,7 +225,7 @@ public:
"$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify",
"$msarequest", "$msamap", "$msaunmap"
};
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
bool validateAsmConstraint(const char *&Name,
@@ -395,8 +394,8 @@ public:
{{"ra"}, "$31"}
};
if (ABI == "o32")
- return llvm::makeArrayRef(O32RegAliases);
- return llvm::makeArrayRef(NewABIRegAliases);
+ return llvm::ArrayRef(O32RegAliases);
+ return llvm::ArrayRef(NewABIRegAliases);
}
bool hasInt128Type() const override {
diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp
index 9dd60adb00fb..bacd93ee1c37 100644
--- a/clang/lib/Basic/Targets/NVPTX.cpp
+++ b/clang/lib/Basic/Targets/NVPTX.cpp
@@ -20,13 +20,13 @@
using namespace clang;
using namespace clang::targets;
-const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsNVPTX.def"
};
@@ -41,33 +41,20 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
PTXVersion = 32;
for (const StringRef Feature : Opts.FeaturesAsWritten) {
- if (!Feature.startswith("+ptx"))
+ int PTXV;
+ if (!Feature.startswith("+ptx") ||
+ Feature.drop_front(4).getAsInteger(10, PTXV))
continue;
- PTXVersion = llvm::StringSwitch<unsigned>(Feature)
- .Case("+ptx75", 75)
- .Case("+ptx74", 74)
- .Case("+ptx73", 73)
- .Case("+ptx72", 72)
- .Case("+ptx71", 71)
- .Case("+ptx70", 70)
- .Case("+ptx65", 65)
- .Case("+ptx64", 64)
- .Case("+ptx63", 63)
- .Case("+ptx61", 61)
- .Case("+ptx60", 60)
- .Case("+ptx50", 50)
- .Case("+ptx43", 43)
- .Case("+ptx42", 42)
- .Case("+ptx41", 41)
- .Case("+ptx40", 40)
- .Case("+ptx32", 32)
- .Default(32);
+ PTXVersion = PTXV; // TODO: should it be max(PTXVersion, PTXV)?
}
TLSSupported = false;
VLASupported = false;
AddrSpaceMap = &NVPTXAddrSpaceMap;
UseAddrSpaceMapMangling = true;
+ // __bf16 is always available as a load/store only type.
+ BFloat16Width = BFloat16Align = 16;
+ BFloat16Format = &llvm::APFloat::BFloat();
// Define available target features
// These must be defined in sorted order!
@@ -110,8 +97,8 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
}
// Copy properties from host target.
- PointerWidth = HostTarget->getPointerWidth(/* AddrSpace = */ 0);
- PointerAlign = HostTarget->getPointerAlign(/* AddrSpace = */ 0);
+ PointerWidth = HostTarget->getPointerWidth(LangAS::Default);
+ PointerAlign = HostTarget->getPointerAlign(LangAS::Default);
BoolWidth = HostTarget->getBoolWidth();
BoolAlign = HostTarget->getBoolAlign();
IntWidth = HostTarget->getIntWidth();
@@ -132,7 +119,7 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
HostTarget->getDefaultAlignForAttributeAligned();
SizeType = HostTarget->getSizeType();
IntMaxType = HostTarget->getIntMaxType();
- PtrDiffType = HostTarget->getPtrDiffType(/* AddrSpace = */ 0);
+ PtrDiffType = HostTarget->getPtrDiffType(LangAS::Default);
IntPtrType = HostTarget->getIntPtrType();
WCharType = HostTarget->getWCharType();
WIntType = HostTarget->getWIntType();
@@ -166,7 +153,7 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple,
}
ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
bool NVPTXTargetInfo::hasFeature(StringRef Feature) const {
@@ -262,6 +249,12 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts,
return "800";
case CudaArch::SM_86:
return "860";
+ case CudaArch::SM_87:
+ return "870";
+ case CudaArch::SM_89:
+ return "890";
+ case CudaArch::SM_90:
+ return "900";
}
llvm_unreachable("unhandled CudaArch");
}();
@@ -270,6 +263,6 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts,
}
ArrayRef<Builtin::Info> NVPTXTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::NVPTX::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h
index 589f24f4bb03..aab3abfa6294 100644
--- a/clang/lib/Basic/Targets/NVPTX.h
+++ b/clang/lib/Basic/Targets/NVPTX.h
@@ -18,6 +18,7 @@
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
+#include <optional>
namespace clang {
namespace targets {
@@ -42,7 +43,8 @@ static const unsigned NVPTXAddrSpaceMap[] = {
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
- 0 // ptr64
+ 0, // ptr64
+ 0, // hlsl_groupshared
};
/// The DWARF address class. Taken from
@@ -57,7 +59,6 @@ static const int NVPTXDWARFAddrSpaceMap[] = {
class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
static const char *const GCCRegNames[];
- static const Builtin::Info BuiltinInfo[];
CudaArch GPU;
uint32_t PTXVersion;
std::unique_ptr<TargetInfo> HostTarget;
@@ -86,7 +87,7 @@ public:
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
// No aliases.
- return None;
+ return std::nullopt;
}
bool validateAsmConstraint(const char *&Name,
@@ -155,13 +156,13 @@ public:
/// space \p AddressSpace to be converted in order to be used, then return the
/// corresponding target specific DWARF address space.
///
- /// \returns Otherwise return None and no conversion will be emitted in the
- /// DWARF.
- Optional<unsigned>
+ /// \returns Otherwise return std::nullopt and no conversion will be emitted
+ /// in the DWARF.
+ std::optional<unsigned>
getDWARFAddressSpace(unsigned AddressSpace) const override {
- if (AddressSpace >= llvm::array_lengthof(NVPTXDWARFAddrSpaceMap) ||
+ if (AddressSpace >= std::size(NVPTXDWARFAddrSpaceMap) ||
NVPTXDWARFAddrSpaceMap[AddressSpace] < 0)
- return llvm::None;
+ return std::nullopt;
return NVPTXDWARFAddrSpaceMap[AddressSpace];
}
@@ -176,6 +177,8 @@ public:
}
bool hasBitIntType() const override { return true; }
+ bool hasBFloat16Type() const override { return true; }
+ const char *getBFloat16Mangling() const override { return "u6__bf16"; };
};
} // namespace targets
} // namespace clang
diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp
index f2ed076039a0..33a5b500e2d1 100644
--- a/clang/lib/Basic/Targets/OSTargets.cpp
+++ b/clang/lib/Basic/Targets/OSTargets.cpp
@@ -67,48 +67,23 @@ void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
return;
}
- // Set the appropriate OS version define.
- if (Triple.isiOS()) {
- assert(OsVersion < VersionTuple(100) && "Invalid version!");
- char Str[7];
- if (OsVersion.getMajor() < 10) {
- Str[0] = '0' + OsVersion.getMajor();
- Str[1] = '0' + (OsVersion.getMinor().value_or(0) / 10);
- Str[2] = '0' + (OsVersion.getMinor().value_or(0) % 10);
- Str[3] = '0' + (OsVersion.getSubminor().value_or(0) / 10);
- Str[4] = '0' + (OsVersion.getSubminor().value_or(0) % 10);
- Str[5] = '\0';
- } else {
- // Handle versions >= 10.
- Str[0] = '0' + (OsVersion.getMajor() / 10);
- Str[1] = '0' + (OsVersion.getMajor() % 10);
- Str[2] = '0' + (OsVersion.getMinor().value_or(0) / 10);
- Str[3] = '0' + (OsVersion.getMinor().value_or(0) % 10);
- Str[4] = '0' + (OsVersion.getSubminor().value_or(0) / 10);
- Str[5] = '0' + (OsVersion.getSubminor().value_or(0) % 10);
- Str[6] = '\0';
- }
- if (Triple.isTvOS())
- Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str);
- else
- Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
- Str);
-
- } else if (Triple.isWatchOS()) {
- assert(OsVersion < VersionTuple(10) && "Invalid version!");
- char Str[6];
+ assert(OsVersion < VersionTuple(100) && "Invalid version!");
+ char Str[7];
+ if (Triple.isMacOSX() && OsVersion < VersionTuple(10, 10)) {
+ Str[0] = '0' + (OsVersion.getMajor() / 10);
+ Str[1] = '0' + (OsVersion.getMajor() % 10);
+ Str[2] = '0' + std::min(OsVersion.getMinor().value_or(0), 9U);
+ Str[3] = '0' + std::min(OsVersion.getSubminor().value_or(0), 9U);
+ Str[4] = '\0';
+ } else if (!Triple.isMacOSX() && OsVersion.getMajor() < 10) {
Str[0] = '0' + OsVersion.getMajor();
Str[1] = '0' + (OsVersion.getMinor().value_or(0) / 10);
Str[2] = '0' + (OsVersion.getMinor().value_or(0) % 10);
Str[3] = '0' + (OsVersion.getSubminor().value_or(0) / 10);
Str[4] = '0' + (OsVersion.getSubminor().value_or(0) % 10);
Str[5] = '\0';
- Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str);
- } else if (Triple.isDriverKit()) {
- assert(OsVersion.getMajor() < 100 &&
- OsVersion.getMinor().value_or(0) < 100 &&
- OsVersion.getSubminor().value_or(0) < 100 && "Invalid version!");
- char Str[7];
+ } else {
+ // Handle versions >= 10.
Str[0] = '0' + (OsVersion.getMajor() / 10);
Str[1] = '0' + (OsVersion.getMajor() % 10);
Str[2] = '0' + (OsVersion.getMinor().value_or(0) / 10);
@@ -116,30 +91,20 @@ void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Str[4] = '0' + (OsVersion.getSubminor().value_or(0) / 10);
Str[5] = '0' + (OsVersion.getSubminor().value_or(0) % 10);
Str[6] = '\0';
+ }
+
+ // Set the appropriate OS version define.
+ if (Triple.isTvOS()) {
+ Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str);
+ } else if (Triple.isiOS()) {
+ Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str);
+ } else if (Triple.isWatchOS()) {
+ Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str);
+ } else if (Triple.isDriverKit()) {
+ assert(OsVersion.getMinor().value_or(0) < 100 &&
+ OsVersion.getSubminor().value_or(0) < 100 && "Invalid version!");
Builder.defineMacro("__ENVIRONMENT_DRIVERKIT_VERSION_MIN_REQUIRED__", Str);
} else if (Triple.isMacOSX()) {
- // Note that the Driver allows versions which aren't representable in the
- // define (because we only get a single digit for the minor and micro
- // revision numbers). So, we limit them to the maximum representable
- // version.
- assert(OsVersion < VersionTuple(100) && "Invalid version!");
- char Str[7];
- if (OsVersion < VersionTuple(10, 10)) {
- Str[0] = '0' + (OsVersion.getMajor() / 10);
- Str[1] = '0' + (OsVersion.getMajor() % 10);
- Str[2] = '0' + std::min(OsVersion.getMinor().value_or(0), 9U);
- Str[3] = '0' + std::min(OsVersion.getSubminor().value_or(0), 9U);
- Str[4] = '\0';
- } else {
- // Handle versions > 10.9.
- Str[0] = '0' + (OsVersion.getMajor() / 10);
- Str[1] = '0' + (OsVersion.getMajor() % 10);
- Str[2] = '0' + (OsVersion.getMinor().value_or(0) / 10);
- Str[3] = '0' + (OsVersion.getMinor().value_or(0) % 10);
- Str[4] = '0' + (OsVersion.getSubminor().value_or(0) / 10);
- Str[5] = '0' + (OsVersion.getSubminor().value_or(0) % 10);
- Str[6] = '\0';
- }
Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str);
}
@@ -178,6 +143,54 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) {
if (!Opts.CharIsSigned)
Builder.defineMacro("_CHAR_UNSIGNED");
+ // "The /fp:contract option allows the compiler to generate floating-point
+ // contractions [...]"
+ if (Opts.getDefaultFPContractMode() != LangOptions::FPModeKind::FPM_Off)
+ Builder.defineMacro("_M_FP_CONTRACT");
+
+ // "The /fp:except option generates code to ensures that any unmasked
+ // floating-point exceptions are raised at the exact point at which they
+ // occur, and that no other floating-point exceptions are raised."
+ if (Opts.getDefaultExceptionMode() ==
+ LangOptions::FPExceptionModeKind::FPE_Strict)
+ Builder.defineMacro("_M_FP_EXCEPT");
+
+ // "The /fp:fast option allows the compiler to reorder, combine, or simplify
+ // floating-point operations to optimize floating-point code for speed and
+ // space. The compiler may omit rounding at assignment statements,
+ // typecasts, or function calls. It may reorder operations or make algebraic
+ // transforms, for example, by use of associative and distributive laws. It
+ // may reorder code even if such transformations result in observably
+ // different rounding behavior."
+ //
+ // "Under /fp:precise and /fp:strict, the compiler doesn't do any mathematical
+ // transformation unless the transformation is guaranteed to produce a bitwise
+ // identical result."
+ const bool any_imprecise_flags =
+ Opts.FastMath || Opts.FiniteMathOnly || Opts.UnsafeFPMath ||
+ Opts.AllowFPReassoc || Opts.NoHonorNaNs || Opts.NoHonorInfs ||
+ Opts.NoSignedZero || Opts.AllowRecip || Opts.ApproxFunc;
+
+ // "Under both /fp:precise and /fp:fast, the compiler generates code intended
+ // to run in the default floating-point environment."
+ //
+ // "[The] default floating point environment [...] sets the rounding mode
+ // to round to nearest."
+ if (Opts.getDefaultRoundingMode() ==
+ LangOptions::RoundingMode::NearestTiesToEven) {
+ if (any_imprecise_flags) {
+ Builder.defineMacro("_M_FP_FAST");
+ } else {
+ Builder.defineMacro("_M_FP_PRECISE");
+ }
+ } else if (!any_imprecise_flags && Opts.getDefaultRoundingMode() ==
+ LangOptions::RoundingMode::Dynamic) {
+ // "Under /fp:strict, the compiler generates code that allows the
+ // program to safely unmask floating-point exceptions, read or write
+ // floating-point status registers, or change rounding modes."
+ Builder.defineMacro("_M_FP_STRICT");
+ }
+
// FIXME: POSIXThreads isn't exactly the option this should be defined for,
// but it works for now.
if (Opts.POSIXThreads)
@@ -215,6 +228,9 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) {
}
}
+ if (!Opts.MSVolatile)
+ Builder.defineMacro("_ISO_VOLATILE");
+
if (Opts.Kernel)
Builder.defineMacro("_KERNEL_MODE");
diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h
index a814f681b146..fd372cb12df2 100644
--- a/clang/lib/Basic/Targets/OSTargets.h
+++ b/clang/lib/Basic/Targets/OSTargets.h
@@ -50,8 +50,7 @@ protected:
}
public:
- CloudABITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
+ using OSTargetInfo<Target>::OSTargetInfo;
};
// Ananas target
@@ -66,8 +65,7 @@ protected:
}
public:
- AnanasTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
+ using OSTargetInfo<Target>::OSTargetInfo;
};
void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
@@ -163,6 +161,10 @@ public:
: TargetInfo::UnsignedLongLong)
: TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned);
}
+
+ bool areDefaultedSMFStillPOD(const LangOptions &) const override {
+ return false;
+ }
};
// DragonFlyBSD Target
@@ -280,8 +282,7 @@ protected:
}
public:
- KFreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
+ using OSTargetInfo<Target>::OSTargetInfo;
};
// Haiku Target
@@ -336,8 +337,7 @@ protected:
Builder.defineMacro("_GNU_SOURCE");
}
public:
- HurdTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
+ using OSTargetInfo<Target>::OSTargetInfo;
};
// Minix Target
@@ -360,8 +360,7 @@ protected:
}
public:
- MinixTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : OSTargetInfo<Target>(Triple, Opts) {}
+ using OSTargetInfo<Target>::OSTargetInfo;
};
// Linux target
@@ -477,7 +476,7 @@ public:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
this->HasFloat128 = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
this->MCountName = "__mcount";
break;
@@ -496,23 +495,6 @@ public:
}
};
-// PSP Target
-template <typename Target>
-class LLVM_LIBRARY_VISIBILITY PSPTargetInfo : public OSTargetInfo<Target> {
-protected:
- void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
- MacroBuilder &Builder) const override {
- // PSP defines; list based on the output of the pspdev gcc toolchain.
- Builder.defineMacro("PSP");
- Builder.defineMacro("_PSP");
- Builder.defineMacro("__psp__");
- Builder.defineMacro("__ELF__");
- }
-
-public:
- PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {}
-};
-
// PS3 PPU Target
template <typename Target>
class LLVM_LIBRARY_VISIBILITY PS3PPUTargetInfo : public OSTargetInfo<Target> {
@@ -577,6 +559,10 @@ public:
checkCallingConvention(CallingConv CC) const override {
return (CC == CC_C) ? TargetInfo::CCCR_OK : TargetInfo::CCCR_Error;
}
+
+ bool areDefaultedSMFStillPOD(const LangOptions &) const override {
+ return false;
+ }
};
// PS4 Target
@@ -592,8 +578,7 @@ protected:
}
public:
- PS4OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : PSOSTargetInfo<Target>(Triple, Opts) {}
+ using PSOSTargetInfo<Target>::PSOSTargetInfo;
};
// PS5 Target
@@ -609,8 +594,7 @@ protected:
}
public:
- PS5OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : PSOSTargetInfo<Target>(Triple, Opts) {}
+ using PSOSTargetInfo<Target>::PSOSTargetInfo;
};
// RTEMS Target
@@ -772,6 +756,7 @@ protected:
public:
AIXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: OSTargetInfo<Target>(Triple, Opts) {
+ this->MCountName = "__mcount";
this->TheCXXABI.set(TargetCXXABI::XL);
if (this->PointerWidth == 64) {
@@ -788,6 +773,10 @@ public:
}
bool defaultsToAIXPowerAlignment() const override { return true; }
+
+ bool areDefaultedSMFStillPOD(const LangOptions &) const override {
+ return false;
+ }
};
// z/OS target
@@ -846,6 +835,10 @@ public:
this->UseLeadingZeroLengthBitfield = false;
this->ZeroLengthBitfieldBoundary = 32;
}
+
+ bool areDefaultedSMFStillPOD(const LangOptions &) const override {
+ return false;
+ }
};
void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts,
@@ -983,8 +976,7 @@ class LLVM_LIBRARY_VISIBILITY WASITargetInfo
}
public:
- explicit WASITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
- : WebAssemblyOSTargetInfo<Target>(Triple, Opts) {}
+ using WebAssemblyOSTargetInfo<Target>::WebAssemblyOSTargetInfo;
};
// Emscripten target
diff --git a/clang/lib/Basic/Targets/PNaCl.cpp b/clang/lib/Basic/Targets/PNaCl.cpp
index 60e9467193a8..51b6452b0c20 100644
--- a/clang/lib/Basic/Targets/PNaCl.cpp
+++ b/clang/lib/Basic/Targets/PNaCl.cpp
@@ -16,10 +16,12 @@
using namespace clang;
using namespace clang::targets;
-ArrayRef<const char *> PNaClTargetInfo::getGCCRegNames() const { return None; }
+ArrayRef<const char *> PNaClTargetInfo::getGCCRegNames() const {
+ return std::nullopt;
+}
ArrayRef<TargetInfo::GCCRegAlias> PNaClTargetInfo::getGCCRegAliases() const {
- return None;
+ return std::nullopt;
}
void PNaClTargetInfo::getArchDefines(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/PNaCl.h b/clang/lib/Basic/Targets/PNaCl.h
index b5cf73d73e95..72c586359cea 100644
--- a/clang/lib/Basic/Targets/PNaCl.h
+++ b/clang/lib/Basic/Targets/PNaCl.h
@@ -52,7 +52,9 @@ public:
return Feature == "pnacl";
}
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ return std::nullopt;
+ }
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::PNaClABIBuiltinVaList;
diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp
index ca01b44ae3a5..d46b1c55cf81 100644
--- a/clang/lib/Basic/Targets/PPC.cpp
+++ b/clang/lib/Basic/Targets/PPC.cpp
@@ -18,11 +18,11 @@
using namespace clang;
using namespace clang::targets;
-const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsPPC.def"
};
@@ -281,7 +281,6 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
if (PointerWidth == 64) {
Builder.defineMacro("_ARCH_PPC64");
Builder.defineMacro("__powerpc64__");
- Builder.defineMacro("__ppc64__");
Builder.defineMacro("__PPC64__");
} else if (getTriple().isOSAIX()) {
// The XL compilers on AIX define _ARCH_PPC64 for both 32 and 64-bit modes.
@@ -755,7 +754,7 @@ const char *const PPCTargetInfo::GCCRegNames[] = {
};
ArrayRef<const char *> PPCTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = {
@@ -786,7 +785,7 @@ const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = {
};
ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
// PPC ELFABIv2 DWARF Definitoin "Table 2.26. Mappings of Common Registers".
@@ -814,7 +813,7 @@ const TargetInfo::AddlRegName GCCAddlRegNames[] = {
ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const {
if (ABI == "elfv2")
- return llvm::makeArrayRef(GCCAddlRegNames);
+ return llvm::ArrayRef(GCCAddlRegNames);
else
return TargetInfo::getGCCAddlRegNames();
}
@@ -855,6 +854,6 @@ void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
}
ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::PPC::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::PPC::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 8148762f446b..cc185fdadfcb 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -50,7 +50,6 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
} ArchDefineTypes;
ArchDefineTypes ArchDefs = ArchDefineNone;
- static const Builtin::Info BuiltinInfo[];
static const char *const GCCRegNames[];
static const TargetInfo::GCCRegAlias GCCRegAliases[];
std::string CPU;
@@ -216,7 +215,7 @@ public:
// Don't use floating point registers on soft float ABI.
if (FloatABI == SoftFloat)
return false;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 'b': // Base register
Info.setAllowsRegister();
break;
@@ -295,7 +294,7 @@ public:
case 'Q': // Memory operand that is an offset from a register (it is
// usually better to use `m' or `es' in asm statements)
Info.setAllowsRegister();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 'Z': // Memory operand that is an indexed or indirect from a
// register (it is usually better to use `m' or `es' in
// asm statements)
diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp
index 7e6c0620385a..25fda05da033 100644
--- a/clang/lib/Basic/Targets/RISCV.cpp
+++ b/clang/lib/Basic/Targets/RISCV.cpp
@@ -15,8 +15,9 @@
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
+#include <optional>
using namespace clang;
using namespace clang::targets;
@@ -40,7 +41,7 @@ ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"};
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
@@ -61,7 +62,7 @@ ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
{{"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);
+ return llvm::ArrayRef(GCCRegAliases);
}
bool RISCVTargetInfo::validateAsmConstraint(
@@ -117,6 +118,10 @@ std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
return R;
}
+static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
+ return MajorVersion * 1000000 + MinorVersion * 1000;
+}
+
void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__ELF__");
@@ -152,10 +157,10 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
for (auto &Extension : ISAInfo->getExtensions()) {
auto ExtName = Extension.first;
auto ExtInfo = Extension.second;
- unsigned Version =
- (ExtInfo.MajorVersion * 1000000) + (ExtInfo.MinorVersion * 1000);
- Builder.defineMacro(Twine("__riscv_", ExtName), Twine(Version));
+ Builder.defineMacro(
+ Twine("__riscv_", ExtName),
+ Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion)));
}
if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul"))
@@ -190,26 +195,29 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
if (ISAInfo->hasExtension("c"))
Builder.defineMacro("__riscv_compressed");
- if (ISAInfo->hasExtension("zve32x"))
+ if (ISAInfo->hasExtension("zve32x")) {
Builder.defineMacro("__riscv_vector");
+ // Currently we support the v0.10 RISC-V V intrinsics.
+ Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 10)));
+ }
}
-const Builtin::Info RISCVTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsRISCVVector.def"
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsRISCV.def"
};
ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::RISCV::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
bool RISCVTargetInfo::initFeatureMap(
@@ -221,6 +229,8 @@ bool RISCVTargetInfo::initFeatureMap(
if (getTriple().getArch() == llvm::Triple::riscv64) {
Features["64bit"] = true;
XLen = 64;
+ } else {
+ Features["32bit"] = true;
}
auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
@@ -244,17 +254,40 @@ bool RISCVTargetInfo::initFeatureMap(
return TargetInfo::initFeatureMap(Features, Diags, CPU, ImpliedFeatures);
}
+std::optional<std::pair<unsigned, unsigned>>
+RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
+ // RISCV::RVVBitsPerBlock is 64.
+ unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
+
+ if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
+ // Treat Zvl*b as a lower bound on vscale.
+ VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
+ unsigned VScaleMax = LangOpts.VScaleMax;
+ if (VScaleMax != 0 && VScaleMax < VScaleMin)
+ VScaleMax = VScaleMin;
+ return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
+ }
+
+ if (VScaleMin > 0) {
+ unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
+ return std::make_pair(VScaleMin, VScaleMax);
+ }
+
+ return std::nullopt;
+}
+
/// Return true if has this feature, need to sync with handleTargetFeatures.
bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
- auto Result = llvm::StringSwitch<Optional<bool>>(Feature)
+ auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
.Case("riscv", true)
.Case("riscv32", !Is64Bit)
.Case("riscv64", Is64Bit)
+ .Case("32bit", !Is64Bit)
.Case("64bit", Is64Bit)
- .Default(None);
+ .Default(std::nullopt);
if (Result)
- return Result.value();
+ return *Result;
if (ISAInfo->isSupportedExtensionFeature(Feature))
return ISAInfo->hasExtension(Feature);
@@ -285,44 +318,25 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
return true;
}
-bool RISCV32TargetInfo::isValidCPUName(StringRef Name) const {
- return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
- /*Is64Bit=*/false);
-}
-
-void RISCV32TargetInfo::fillValidCPUList(
- SmallVectorImpl<StringRef> &Values) const {
- llvm::RISCV::fillValidCPUArchList(Values, false);
-}
-
-bool RISCV32TargetInfo::isValidTuneCPUName(StringRef Name) const {
- return llvm::RISCV::checkTuneCPUKind(
- llvm::RISCV::parseTuneCPUKind(Name, false),
- /*Is64Bit=*/false);
-}
-
-void RISCV32TargetInfo::fillValidTuneCPUList(
- SmallVectorImpl<StringRef> &Values) const {
- llvm::RISCV::fillValidTuneCPUArchList(Values, false);
-}
-
-bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const {
- return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name),
- /*Is64Bit=*/true);
+bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
+ bool Is64Bit = getTriple().isArch64Bit();
+ return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name), Is64Bit);
}
-void RISCV64TargetInfo::fillValidCPUList(
+void RISCVTargetInfo::fillValidCPUList(
SmallVectorImpl<StringRef> &Values) const {
- llvm::RISCV::fillValidCPUArchList(Values, true);
+ bool Is64Bit = getTriple().isArch64Bit();
+ llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
}
-bool RISCV64TargetInfo::isValidTuneCPUName(StringRef Name) const {
+bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
+ bool Is64Bit = getTriple().isArch64Bit();
return llvm::RISCV::checkTuneCPUKind(
- llvm::RISCV::parseTuneCPUKind(Name, true),
- /*Is64Bit=*/true);
+ llvm::RISCV::parseTuneCPUKind(Name, Is64Bit), Is64Bit);
}
-void RISCV64TargetInfo::fillValidTuneCPUList(
+void RISCVTargetInfo::fillValidTuneCPUList(
SmallVectorImpl<StringRef> &Values) const {
- llvm::RISCV::fillValidTuneCPUArchList(Values, true);
+ bool Is64Bit = getTriple().isArch64Bit();
+ llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
}
diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h
index 7817e6e81e26..adff1da4ad5e 100644
--- a/clang/lib/Basic/Targets/RISCV.h
+++ b/clang/lib/Basic/Targets/RISCV.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/RISCVISAInfo.h"
+#include <optional>
namespace clang {
namespace targets {
@@ -27,7 +28,6 @@ class RISCVTargetInfo : public TargetInfo {
protected:
std::string ABI, CPU;
std::unique_ptr<llvm::RISCVISAInfo> ISAInfo;
- static const Builtin::Info BuiltinInfo[];
public:
RISCVTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
@@ -90,6 +90,9 @@ public:
StringRef CPU,
const std::vector<std::string> &FeaturesVec) const override;
+ std::optional<std::pair<unsigned, unsigned>>
+ getVScaleRange(const LangOptions &LangOpts) const override;
+
bool hasFeature(StringRef Feature) const override;
bool handleTargetFeatures(std::vector<std::string> &Features,
@@ -100,6 +103,11 @@ public:
bool useFP16ConversionIntrinsics() const override {
return false;
}
+
+ bool isValidCPUName(StringRef Name) const override;
+ void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
+ bool isValidTuneCPUName(StringRef Name) const override;
+ void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
};
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
public:
@@ -119,11 +127,6 @@ public:
return false;
}
- bool isValidCPUName(StringRef Name) const override;
- void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
- bool isValidTuneCPUName(StringRef Name) const override;
- void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
-
void setMaxAtomicWidth() override {
MaxAtomicPromoteWidth = 128;
@@ -137,7 +140,7 @@ public:
: RISCVTargetInfo(Triple, Opts) {
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
IntMaxType = Int64Type = SignedLong;
- resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n64-S128");
+ resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S128");
}
bool setABI(const std::string &Name) override {
@@ -148,11 +151,6 @@ public:
return false;
}
- bool isValidCPUName(StringRef Name) const override;
- void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
- bool isValidTuneCPUName(StringRef Name) const override;
- void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
-
void setMaxAtomicWidth() override {
MaxAtomicPromoteWidth = 128;
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 08c49f018ac7..69596c6eb6fe 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -17,6 +17,7 @@
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
+#include <optional>
namespace clang {
namespace targets {
@@ -42,7 +43,8 @@ static const unsigned SPIRDefIsPrivMap[] = {
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
- 0 // ptr64
+ 0, // ptr64
+ 0, // hlsl_groupshared
};
// Used by both the SPIR and SPIR-V targets.
@@ -71,7 +73,8 @@ static const unsigned SPIRDefIsGenMap[] = {
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
- 0 // ptr64
+ 0, // ptr64
+ 0, // hlsl_groupshared
};
// Base class for SPIR and SPIR-V target info.
@@ -102,11 +105,15 @@ public:
// memcpy as per section 3 of the SPIR spec.
bool useFP16ConversionIntrinsics() const override { return false; }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ return std::nullopt;
+ }
const char *getClobbers() const override { return ""; }
- ArrayRef<const char *> getGCCRegNames() const override { return None; }
+ ArrayRef<const char *> getGCCRegNames() const override {
+ return std::nullopt;
+ }
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override {
@@ -114,14 +121,14 @@ public:
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
}
- Optional<unsigned>
+ std::optional<unsigned>
getDWARFAddressSpace(unsigned AddressSpace) const override {
return AddressSpace;
}
diff --git a/clang/lib/Basic/Targets/Sparc.cpp b/clang/lib/Basic/Targets/Sparc.cpp
index 932102434801..4548902ca12b 100644
--- a/clang/lib/Basic/Targets/Sparc.cpp
+++ b/clang/lib/Basic/Targets/Sparc.cpp
@@ -33,7 +33,7 @@ const char *const SparcTargetInfo::GCCRegNames[] = {
};
ArrayRef<const char *> SparcTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = {
@@ -48,7 +48,7 @@ const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = {
};
ArrayRef<TargetInfo::GCCRegAlias> SparcTargetInfo::getGCCRegAliases() const {
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
bool SparcTargetInfo::hasFeature(StringRef Feature) const {
diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h
index 177a117520da..4860b023d6e6 100644
--- a/clang/lib/Basic/Targets/Sparc.h
+++ b/clang/lib/Basic/Targets/Sparc.h
@@ -50,7 +50,7 @@ public:
ArrayRef<Builtin::Info> getTargetBuiltins() const override {
// FIXME: Implement!
- return None;
+ return std::nullopt;
}
BuiltinVaListKind getBuiltinVaListKind() const override {
return TargetInfo::VoidPtrBuiltinVaList;
diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp
index 84874b58ba68..a9b5ca483861 100644
--- a/clang/lib/Basic/Targets/SystemZ.cpp
+++ b/clang/lib/Basic/Targets/SystemZ.cpp
@@ -20,11 +20,11 @@
using namespace clang;
using namespace clang::targets;
-const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsSystemZ.def"
};
@@ -46,11 +46,11 @@ const TargetInfo::AddlRegName GCCAddlRegNames[] = {
};
ArrayRef<const char *> SystemZTargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::AddlRegName> SystemZTargetInfo::getGCCAddlRegNames() const {
- return llvm::makeArrayRef(GCCAddlRegNames);
+ return llvm::ArrayRef(GCCAddlRegNames);
}
bool SystemZTargetInfo::validateAsmConstraint(
@@ -69,7 +69,7 @@ bool SystemZTargetInfo::validateAsmConstraint(
case 'T': // Likewise, plus an index
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 'a': // Address register
case 'd': // Data register (equivalent to 'r')
case 'f': // Floating-point register
@@ -161,6 +161,6 @@ void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts,
}
ArrayRef<Builtin::Info> SystemZTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
}
diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h
index e4f242e624cb..030f5ec7d69b 100644
--- a/clang/lib/Basic/Targets/SystemZ.h
+++ b/clang/lib/Basic/Targets/SystemZ.h
@@ -23,7 +23,6 @@ namespace targets {
class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
static const char *const GCCRegNames[];
std::string CPU;
int ISARevision;
@@ -40,6 +39,7 @@ public:
TLSSupported = true;
IntWidth = IntAlign = 32;
LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
+ Int128Align = 64;
PointerWidth = PointerAlign = 64;
LongDoubleWidth = 128;
LongDoubleAlign = 64;
@@ -50,13 +50,13 @@ public:
// All vector types are default aligned on an 8-byte boundary, even if the
// vector facility is not available. That is different from Linux.
MaxVectorAlign = 64;
- // Compared to Linux/ELF, the data layout differs only in some details:
- // - name mangling is GOFF
- // - 128 bit vector types are 64 bit aligned
+ // Compared to Linux/ELF, the data layout differs only in that name
+ // mangling is GOFF.
resetDataLayout(
"E-m:l-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64");
} else
- resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64");
+ resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64"
+ "-v128:64-a:8:16-n32:64");
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
HasStrictFP = true;
}
@@ -70,7 +70,7 @@ public:
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
// No aliases.
- return None;
+ return std::nullopt;
}
ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override;
@@ -170,12 +170,14 @@ public:
}
HasVector &= !SoftFloat;
- // If we use the vector ABI, vector types are 64-bit aligned.
- if (HasVector && !getTriple().isOSzOS()) {
+ // If we use the vector ABI, vector types are 64-bit aligned. The
+ // DataLayout string is always set to this alignment as it is not a
+ // requirement that it follows the alignment emitted by the front end. It
+ // is assumed generally that the Datalayout should reflect only the
+ // target triple and not any specific feature.
+ if (HasVector && !getTriple().isOSzOS())
MaxVectorAlign = 64;
- resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64"
- "-v128:64-a:8:16-n32:64");
- }
+
return true;
}
diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h
index 251b4d4b56f7..430ace3ab237 100644
--- a/clang/lib/Basic/Targets/TCE.h
+++ b/clang/lib/Basic/Targets/TCE.h
@@ -50,6 +50,7 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = {
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
+ 0, // hlsl_groupshared
};
class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo {
@@ -91,7 +92,9 @@ public:
bool hasFeature(StringRef Feature) const override { return Feature == "tce"; }
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override {
+ return std::nullopt;
+ }
const char *getClobbers() const override { return ""; }
@@ -99,7 +102,9 @@ public:
return TargetInfo::VoidPtrBuiltinVaList;
}
- ArrayRef<const char *> getGCCRegNames() const override { return None; }
+ ArrayRef<const char *> getGCCRegNames() const override {
+ return std::nullopt;
+ }
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override {
@@ -107,7 +112,7 @@ public:
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
};
diff --git a/clang/lib/Basic/Targets/VE.cpp b/clang/lib/Basic/Targets/VE.cpp
index 4d66c98edc92..a223b65a8fa7 100644
--- a/clang/lib/Basic/Targets/VE.cpp
+++ b/clang/lib/Basic/Targets/VE.cpp
@@ -18,9 +18,9 @@
using namespace clang;
using namespace clang::targets;
-const Builtin::Info VETargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsVE.def"
};
@@ -38,9 +38,14 @@ void VETargetInfo::getTargetDefines(const LangOptions &Opts,
// FIXME: define __FAST_MATH__ 1 if -ffast-math is enabled
// FIXME: define __OPTIMIZE__ n if -On is enabled
// FIXME: define __VECTOR__ n 1 if automatic vectorization is enabled
+
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
}
ArrayRef<Builtin::Info> VETargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo,
- clang::VE::LastTSBuiltin - Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::VE::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
diff --git a/clang/lib/Basic/Targets/VE.h b/clang/lib/Basic/Targets/VE.h
index 71d6fc08d859..d42d3e9199b1 100644
--- a/clang/lib/Basic/Targets/VE.h
+++ b/clang/lib/Basic/Targets/VE.h
@@ -22,7 +22,6 @@ namespace clang {
namespace targets {
class LLVM_LIBRARY_VISIBILITY VETargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
public:
VETargetInfo(const llvm::Triple &Triple, const TargetOptions &)
@@ -84,7 +83,7 @@ public:
"sx48", "sx49", "sx50", "sx51", "sx52", "sx53", "sx54", "sx55",
"sx56", "sx57", "sx58", "sx59", "sx60", "sx61", "sx62", "sx63",
};
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
@@ -154,7 +153,7 @@ public:
{{"s62"}, "sx62"},
{{"s63"}, "sx63"},
};
- return llvm::makeArrayRef(GCCRegAliases);
+ return llvm::ArrayRef(GCCRegAliases);
}
bool validateAsmConstraint(const char *&Name,
diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index b3b6c2be5c13..3a5e0350192e 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -20,13 +20,13 @@
using namespace clang;
using namespace clang::targets;
-const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsWebAssembly.def"
};
@@ -96,6 +96,11 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__wasm_reference_types__");
if (HasExtendedConst)
Builder.defineMacro("__wasm_extended_const__");
+
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
}
void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features,
@@ -104,10 +109,10 @@ void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features,
switch (Level) {
case RelaxedSIMD:
Features["relaxed-simd"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SIMD128:
Features["simd128"] = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NoSIMD:
break;
}
@@ -118,7 +123,7 @@ void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features,
case NoSIMD:
case SIMD128:
Features["simd128"] = false;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case RelaxedSIMD:
Features["relaxed-simd"] = false;
break;
@@ -147,6 +152,9 @@ bool WebAssemblyTargetInfo::initFeatureMap(
Features["mutable-globals"] = true;
Features["tail-call"] = true;
setSIMDLevel(Features, SIMD128, true);
+ } else if (CPU == "generic") {
+ Features["sign-ext"] = true;
+ Features["mutable-globals"] = true;
}
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
@@ -260,8 +268,8 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
}
ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
}
void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags,
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 63418869d10a..1e73450fdd0c 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -22,7 +22,6 @@ namespace clang {
namespace targets {
class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
enum SIMDEnum {
NoSIMD,
@@ -96,10 +95,10 @@ private:
return VoidPtrBuiltinVaList;
}
- ArrayRef<const char *> getGCCRegNames() const final { return None; }
+ ArrayRef<const char *> getGCCRegNames() const final { return std::nullopt; }
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const final {
- return None;
+ return std::nullopt;
}
bool validateAsmConstraint(const char *&Name,
diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp
index 69afdf8a3584..cb3171227530 100644
--- a/clang/lib/Basic/Targets/X86.cpp
+++ b/clang/lib/Basic/Targets/X86.cpp
@@ -18,25 +18,26 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/X86TargetParser.h"
+#include <optional>
namespace clang {
namespace targets {
-const Builtin::Info BuiltinInfoX86[] = {
+static constexpr Builtin::Info BuiltinInfoX86[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
- {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS},
#include "clang/Basic/BuiltinsX86.def"
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \
- {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE},
+ {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::HEADER, LANGS},
#include "clang/Basic/BuiltinsX86_64.def"
};
@@ -239,6 +240,7 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasAVX512ER = true;
} else if (Feature == "+avx512fp16") {
HasAVX512FP16 = true;
+ HasLegalHalfType = true;
} else if (Feature == "+avx512pf") {
HasAVX512PF = true;
} else if (Feature == "+avx512dq") {
@@ -289,6 +291,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasCLWB = true;
} else if (Feature == "+wbnoinvd") {
HasWBNOINVD = true;
+ } else if (Feature == "+prefetchi") {
+ HasPREFETCHI = true;
} else if (Feature == "+prefetchwt1") {
HasPREFETCHWT1 = true;
} else if (Feature == "+clzero") {
@@ -325,12 +329,24 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasHRESET = true;
} else if (Feature == "+amx-bf16") {
HasAMXBF16 = true;
+ } else if (Feature == "+amx-fp16") {
+ HasAMXFP16 = true;
} else if (Feature == "+amx-int8") {
HasAMXINT8 = true;
} else if (Feature == "+amx-tile") {
HasAMXTILE = true;
+ } else if (Feature == "+cmpccxadd") {
+ HasCMPCCXADD = true;
+ } else if (Feature == "+raoint") {
+ HasRAOINT = true;
+ } else if (Feature == "+avxifma") {
+ HasAVXIFMA = true;
+ } else if (Feature == "+avxneconvert") {
+ HasAVXNECONVERT= true;
} else if (Feature == "+avxvnni") {
HasAVXVNNI = true;
+ } else if (Feature == "+avxvnniint8") {
+ HasAVXVNNIINT8 = true;
} else if (Feature == "+serialize") {
HasSERIALIZE = true;
} else if (Feature == "+tsxldtrk") {
@@ -358,6 +374,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasFloat16 = SSELevel >= SSE2;
+ HasBFloat16 = SSELevel >= SSE2;
+
MMX3DNowEnum ThreeDNowLevel = llvm::StringSwitch<MMX3DNowEnum>(Feature)
.Case("+3dnowa", AMD3DNowAthlon)
.Case("+3dnow", AMD3DNow)
@@ -444,7 +462,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_PentiumMMX:
Builder.defineMacro("__pentium_mmx__");
Builder.defineMacro("__tune_pentium_mmx__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CK_i586:
case CK_Pentium:
defineCPUMacros(Builder, "i586");
@@ -453,11 +471,11 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_Pentium3:
case CK_PentiumM:
Builder.defineMacro("__tune_pentium3__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CK_Pentium2:
case CK_C3_2:
Builder.defineMacro("__tune_pentium2__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CK_PentiumPro:
case CK_i686:
defineCPUMacros(Builder, "i686");
@@ -507,6 +525,12 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_Tigerlake:
case CK_SapphireRapids:
case CK_Alderlake:
+ case CK_Raptorlake:
+ case CK_Meteorlake:
+ case CK_Sierraforest:
+ case CK_Grandridge:
+ case CK_Graniterapids:
+ case CK_Emeraldrapids:
// 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.
@@ -525,7 +549,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_K6_2:
Builder.defineMacro("__k6_2__");
Builder.defineMacro("__tune_k6_2__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CK_K6_3:
if (CPU != CK_K6_2) { // In case of fallthrough
// FIXME: GCC may be enabling these in cases where some other k6
@@ -534,7 +558,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__k6_3__");
Builder.defineMacro("__tune_k6_3__");
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CK_K6:
defineCPUMacros(Builder, "k6");
break;
@@ -585,6 +609,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_ZNVER3:
defineCPUMacros(Builder, "znver3");
break;
+ case CK_ZNVER4:
+ defineCPUMacros(Builder, "znver4");
+ break;
case CK_Geode:
defineCPUMacros(Builder, "geode");
break;
@@ -660,13 +687,13 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
switch (XOPLevel) {
case XOP:
Builder.defineMacro("__XOP__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case FMA4:
Builder.defineMacro("__FMA4__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SSE4A:
Builder.defineMacro("__SSE4A__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NoXOP:
break;
}
@@ -735,6 +762,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__SHSTK__");
if (HasSGX)
Builder.defineMacro("__SGX__");
+ if (HasPREFETCHI)
+ Builder.defineMacro("__PREFETCHI__");
if (HasPREFETCHWT1)
Builder.defineMacro("__PREFETCHWT1__");
if (HasCLZERO)
@@ -771,8 +800,20 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__AMXINT8__");
if (HasAMXBF16)
Builder.defineMacro("__AMXBF16__");
+ if (HasAMXFP16)
+ Builder.defineMacro("__AMXFP16__");
+ if (HasCMPCCXADD)
+ Builder.defineMacro("__CMPCCXADD__");
+ if (HasRAOINT)
+ Builder.defineMacro("__RAOINT__");
+ if (HasAVXIFMA)
+ Builder.defineMacro("__AVXIFMA__");
+ if (HasAVXNECONVERT)
+ Builder.defineMacro("__AVXNECONVERT__");
if (HasAVXVNNI)
Builder.defineMacro("__AVXVNNI__");
+ if (HasAVXVNNIINT8)
+ Builder.defineMacro("__AVXVNNIINT8__");
if (HasSERIALIZE)
Builder.defineMacro("__SERIALIZE__");
if (HasTSXLDTRK)
@@ -786,33 +827,33 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
switch (SSELevel) {
case AVX512F:
Builder.defineMacro("__AVX512F__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AVX2:
Builder.defineMacro("__AVX2__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AVX:
Builder.defineMacro("__AVX__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SSE42:
Builder.defineMacro("__SSE4_2__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SSE41:
Builder.defineMacro("__SSE4_1__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SSSE3:
Builder.defineMacro("__SSSE3__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SSE3:
Builder.defineMacro("__SSE3__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SSE2:
Builder.defineMacro("__SSE2__");
Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SSE1:
Builder.defineMacro("__SSE__");
Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NoSSE:
break;
}
@@ -842,13 +883,13 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
switch (MMX3DNowLevel) {
case AMD3DNowAthlon:
Builder.defineMacro("__3dNOW_A__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AMD3DNow:
Builder.defineMacro("__3dNOW__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case MMX:
Builder.defineMacro("__MMX__");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NoMMX3DNow:
break;
}
@@ -874,6 +915,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("adx", true)
.Case("aes", true)
.Case("amx-bf16", true)
+ .Case("amx-fp16", true)
.Case("amx-int8", true)
.Case("amx-tile", true)
.Case("avx", true)
@@ -894,13 +936,17 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("avx512vbmi2", true)
.Case("avx512ifma", true)
.Case("avx512vp2intersect", true)
+ .Case("avxifma", true)
+ .Case("avxneconvert", true)
.Case("avxvnni", true)
+ .Case("avxvnniint8", true)
.Case("bmi", true)
.Case("bmi2", true)
.Case("cldemote", true)
.Case("clflushopt", true)
.Case("clwb", true)
.Case("clzero", true)
+ .Case("cmpccxadd", true)
.Case("crc32", true)
.Case("cx16", true)
.Case("enqcmd", true)
@@ -926,9 +972,11 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("pconfig", true)
.Case("pku", true)
.Case("popcnt", true)
+ .Case("prefetchi", true)
.Case("prefetchwt1", true)
.Case("prfchw", true)
.Case("ptwrite", true)
+ .Case("raoint", true)
.Case("rdpid", true)
.Case("rdpru", true)
.Case("rdrnd", true)
@@ -968,9 +1016,9 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("adx", HasADX)
.Case("aes", HasAES)
.Case("amx-bf16", HasAMXBF16)
+ .Case("amx-fp16", HasAMXFP16)
.Case("amx-int8", HasAMXINT8)
.Case("amx-tile", HasAMXTILE)
- .Case("avxvnni", HasAVXVNNI)
.Case("avx", SSELevel >= AVX)
.Case("avx2", SSELevel >= AVX2)
.Case("avx512f", SSELevel >= AVX512F)
@@ -989,12 +1037,17 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("avx512vbmi2", HasAVX512VBMI2)
.Case("avx512ifma", HasAVX512IFMA)
.Case("avx512vp2intersect", HasAVX512VP2INTERSECT)
+ .Case("avxifma", HasAVXIFMA)
+ .Case("avxneconvert", HasAVXNECONVERT)
+ .Case("avxvnni", HasAVXVNNI)
+ .Case("avxvnniint8", HasAVXVNNIINT8)
.Case("bmi", HasBMI)
.Case("bmi2", HasBMI2)
.Case("cldemote", HasCLDEMOTE)
.Case("clflushopt", HasCLFLUSHOPT)
.Case("clwb", HasCLWB)
.Case("clzero", HasCLZERO)
+ .Case("cmpccxadd", HasCMPCCXADD)
.Case("crc32", HasCRC32)
.Case("cx8", HasCX8)
.Case("cx16", HasCX16)
@@ -1022,9 +1075,11 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("pconfig", HasPCONFIG)
.Case("pku", HasPKU)
.Case("popcnt", HasPOPCNT)
+ .Case("prefetchi", HasPREFETCHI)
.Case("prefetchwt1", HasPREFETCHWT1)
.Case("prfchw", HasPRFCHW)
.Case("ptwrite", HasPTWRITE)
+ .Case("raoint", HasRAOINT)
.Case("rdpid", HasRDPID)
.Case("rdpru", HasRDPRU)
.Case("rdrnd", HasRDRND)
@@ -1070,7 +1125,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const {
return llvm::StringSwitch<bool>(FeatureStr)
#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) .Case(STR, true)
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
.Default(false);
}
@@ -1079,7 +1134,7 @@ static llvm::X86::ProcessorFeatures getFeature(StringRef Name) {
#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \
.Case(STR, llvm::X86::FEATURE_##ENUM)
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
;
// Note, this function should only be used after ensuring the value is
// correct, so it asserts if the value is out of range.
@@ -1104,21 +1159,21 @@ bool X86TargetInfo::validateCPUSpecificCPUDispatch(StringRef Name) const {
return llvm::StringSwitch<bool>(Name)
#define CPU_SPECIFIC(NAME, TUNE_NAME, MANGLING, FEATURES) .Case(NAME, true)
#define CPU_SPECIFIC_ALIAS(NEW_NAME, TUNE_NAME, NAME) .Case(NEW_NAME, true)
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
.Default(false);
}
static StringRef CPUSpecificCPUDispatchNameDealias(StringRef Name) {
return llvm::StringSwitch<StringRef>(Name)
#define CPU_SPECIFIC_ALIAS(NEW_NAME, TUNE_NAME, NAME) .Case(NEW_NAME, NAME)
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
.Default(Name);
}
char X86TargetInfo::CPUSpecificManglingCharacter(StringRef Name) const {
return llvm::StringSwitch<char>(CPUSpecificCPUDispatchNameDealias(Name))
#define CPU_SPECIFIC(NAME, TUNE_NAME, MANGLING, FEATURES) .Case(NAME, MANGLING)
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
.Default(0);
}
@@ -1127,7 +1182,7 @@ void X86TargetInfo::getCPUSpecificCPUDispatchFeatures(
StringRef WholeList =
llvm::StringSwitch<StringRef>(CPUSpecificCPUDispatchNameDealias(Name))
#define CPU_SPECIFIC(NAME, TUNE_NAME, MANGLING, FEATURES) .Case(NAME, FEATURES)
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
.Default("");
WholeList.split(Features, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
}
@@ -1136,7 +1191,7 @@ StringRef X86TargetInfo::getCPUSpecificTuneName(StringRef Name) const {
return llvm::StringSwitch<StringRef>(Name)
#define CPU_SPECIFIC(NAME, TUNE_NAME, MANGLING, FEATURES) .Case(NAME, TUNE_NAME)
#define CPU_SPECIFIC_ALIAS(NEW_NAME, TUNE_NAME, NAME) .Case(NEW_NAME, TUNE_NAME)
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
.Default("");
}
@@ -1149,8 +1204,9 @@ bool X86TargetInfo::validateCpuIs(StringRef FeatureStr) const {
#define X86_VENDOR(ENUM, STRING) .Case(STRING, true)
#define X86_CPU_TYPE_ALIAS(ENUM, ALIAS) .Case(ALIAS, true)
#define X86_CPU_TYPE(ENUM, STR) .Case(STR, true)
+#define X86_CPU_SUBTYPE_ALIAS(ENUM, ALIAS) .Case(ALIAS, true)
#define X86_CPU_SUBTYPE(ENUM, STR) .Case(STR, true)
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
.Default(false);
}
@@ -1302,7 +1358,7 @@ bool X86TargetInfo::validateAsmConstraint(
// | Knights Landing | 64 | https://software.intel.com/en-us/articles/intel-xeon-phi-processor-7200-family-memory-management-optimizations "The Intel® Xeon Phi™ Processor Architecture" |
// | Knights Mill | 64 | https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf?countrylabel=Colombia "2.5.5.2 L1 DCache " |
// +------------------------------------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
-Optional<unsigned> X86TargetInfo::getCPUCacheLineSize() const {
+std::optional<unsigned> X86TargetInfo::getCPUCacheLineSize() const {
using namespace llvm::X86;
switch (CPU) {
// i386
@@ -1363,6 +1419,12 @@ Optional<unsigned> X86TargetInfo::getCPUCacheLineSize() const {
case CK_Rocketlake:
case CK_IcelakeServer:
case CK_Alderlake:
+ case CK_Raptorlake:
+ case CK_Meteorlake:
+ case CK_Sierraforest:
+ case CK_Grandridge:
+ case CK_Graniterapids:
+ case CK_Emeraldrapids:
case CK_KNL:
case CK_KNM:
// K7
@@ -1384,6 +1446,7 @@ Optional<unsigned> X86TargetInfo::getCPUCacheLineSize() const {
case CK_ZNVER1:
case CK_ZNVER2:
case CK_ZNVER3:
+ case CK_ZNVER4:
// Deprecated
case CK_x86_64:
case CK_x86_64_v2:
@@ -1397,7 +1460,7 @@ Optional<unsigned> X86TargetInfo::getCPUCacheLineSize() const {
// The following currently have unknown cache line sizes (but they are probably all 64):
// Core
case CK_None:
- return None;
+ return std::nullopt;
}
llvm_unreachable("Unknown CPU kind");
}
@@ -1521,7 +1584,7 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const {
// to the next constraint.
return std::string("^") + std::string(Constraint++, 2);
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return std::string(1, *Constraint);
}
@@ -1537,19 +1600,19 @@ void X86TargetInfo::fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) con
}
ArrayRef<const char *> X86TargetInfo::getGCCRegNames() const {
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::AddlRegName> X86TargetInfo::getGCCAddlRegNames() const {
- return llvm::makeArrayRef(AddlRegNames);
+ return llvm::ArrayRef(AddlRegNames);
}
ArrayRef<Builtin::Info> X86_32TargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin -
- Builtin::FirstTSBuiltin + 1);
+ return llvm::ArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin -
+ Builtin::FirstTSBuiltin + 1);
}
ArrayRef<Builtin::Info> X86_64TargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfoX86,
- X86::LastTSBuiltin - Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfoX86,
+ X86::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index 0affa58b2f4c..5fcc97e95c2b 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/X86TargetParser.h"
+#include <optional>
namespace clang {
namespace targets {
@@ -43,7 +44,8 @@ static const unsigned X86AddrSpaceMap[] = {
0, // sycl_private
270, // ptr32_sptr
271, // ptr32_uptr
- 272 // ptr64
+ 272, // ptr64
+ 0, // hlsl_groupshared
};
// X86 target abstract base class; x86-32 and x86-64 are very close, so
@@ -103,6 +105,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasAVX512VL = false;
bool HasAVX512VBMI = false;
bool HasAVX512VBMI2 = false;
+ bool HasAVXIFMA = false;
bool HasAVX512IFMA = false;
bool HasAVX512VP2INTERSECT = false;
bool HasSHA = false;
@@ -123,6 +126,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasCLFLUSHOPT = false;
bool HasCLWB = false;
bool HasMOVBE = false;
+ bool HasPREFETCHI = false;
bool HasPREFETCHWT1 = false;
bool HasRDPID = false;
bool HasRDPRU = false;
@@ -135,6 +139,11 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasPTWRITE = false;
bool HasINVPCID = false;
bool HasENQCMD = false;
+ bool HasAMXFP16 = false;
+ bool HasCMPCCXADD = false;
+ bool HasRAOINT = false;
+ bool HasAVXVNNIINT8 = false;
+ bool HasAVXNECONVERT = false;
bool HasKL = false; // For key locker
bool HasWIDEKL = false; // For wide key locker
bool HasHRESET = false;
@@ -156,6 +165,8 @@ protected:
public:
X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &)
: TargetInfo(Triple) {
+ BFloat16Width = BFloat16Align = 16;
+ BFloat16Format = &llvm::APFloat::BFloat();
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended();
AddrSpaceMap = &X86AddrSpaceMap;
HasStrictFP = true;
@@ -182,7 +193,7 @@ public:
ArrayRef<const char *> getGCCRegNames() const override;
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override;
@@ -205,7 +216,7 @@ public:
StringRef getCPUSpecificTuneName(StringRef Name) const override;
- Optional<unsigned> getCPUCacheLineSize() const override;
+ std::optional<unsigned> getCPUCacheLineSize() const override;
bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &info) const override;
@@ -231,12 +242,16 @@ public:
bool
checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override {
- return true;
+ if (CPU == llvm::X86::CK_None || CPU >= llvm::X86::CK_PentiumPro)
+ return true;
+ return TargetInfo::checkCFProtectionReturnSupported(Diags);
};
bool
checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const override {
- return true;
+ if (CPU == llvm::X86::CK_None || CPU >= llvm::X86::CK_PentiumPro)
+ return true;
+ return TargetInfo::checkCFProtectionBranchSupported(Diags);
};
virtual bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap,
@@ -385,17 +400,20 @@ public:
void setSupportedOpenCLOpts() override { supportAllOpenCLOpts(); }
- uint64_t getPointerWidthV(unsigned AddrSpace) const override {
- if (AddrSpace == ptr32_sptr || AddrSpace == ptr32_uptr)
+ uint64_t getPointerWidthV(LangAS AS) const override {
+ unsigned TargetAddrSpace = getTargetAddressSpace(AS);
+ if (TargetAddrSpace == ptr32_sptr || TargetAddrSpace == ptr32_uptr)
return 32;
- if (AddrSpace == ptr64)
+ if (TargetAddrSpace == ptr64)
return 64;
return PointerWidth;
}
- uint64_t getPointerAlignV(unsigned AddrSpace) const override {
+ uint64_t getPointerAlignV(LangAS AddrSpace) const override {
return getPointerWidthV(AddrSpace);
}
+
+ const char *getBFloat16Mangling() const override { return "u6__bf16"; };
};
// X86-32 generic target
@@ -471,6 +489,9 @@ public:
ArrayRef<Builtin::Info> getTargetBuiltins() const override;
bool hasBitIntType() const override { return true; }
+ size_t getMaxBitIntWidth() const override {
+ return llvm::IntegerType::MAX_INT_BITS;
+ }
};
class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo
@@ -778,6 +799,9 @@ public:
ArrayRef<Builtin::Info> getTargetBuiltins() const override;
bool hasBitIntType() const override { return true; }
+ size_t getMaxBitIntWidth() const override {
+ return llvm::IntegerType::MAX_INT_BITS;
+ }
};
// x86-64 Windows target
diff --git a/clang/lib/Basic/Targets/XCore.cpp b/clang/lib/Basic/Targets/XCore.cpp
index ba64f15f3394..fd377bbfb90e 100644
--- a/clang/lib/Basic/Targets/XCore.cpp
+++ b/clang/lib/Basic/Targets/XCore.cpp
@@ -18,11 +18,11 @@
using namespace clang;
using namespace clang::targets;
-const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = {
+static constexpr Builtin::Info BuiltinInfo[] = {
#define BUILTIN(ID, TYPE, ATTRS) \
- {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \
- {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr},
+ {#ID, TYPE, ATTRS, nullptr, HeaderDesc::HEADER, ALL_LANGUAGES},
#include "clang/Basic/BuiltinsXCore.def"
};
@@ -33,6 +33,6 @@ void XCoreTargetInfo::getTargetDefines(const LangOptions &Opts,
}
ArrayRef<Builtin::Info> XCoreTargetInfo::getTargetBuiltins() const {
- return llvm::makeArrayRef(BuiltinInfo, clang::XCore::LastTSBuiltin -
- Builtin::FirstTSBuiltin);
+ return llvm::ArrayRef(BuiltinInfo,
+ clang::XCore::LastTSBuiltin - Builtin::FirstTSBuiltin);
}
diff --git a/clang/lib/Basic/Targets/XCore.h b/clang/lib/Basic/Targets/XCore.h
index 25f20581839d..8eef9de0356e 100644
--- a/clang/lib/Basic/Targets/XCore.h
+++ b/clang/lib/Basic/Targets/XCore.h
@@ -22,7 +22,6 @@ namespace clang {
namespace targets {
class LLVM_LIBRARY_VISIBILITY XCoreTargetInfo : public TargetInfo {
- static const Builtin::Info BuiltinInfo[];
public:
XCoreTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
@@ -57,11 +56,11 @@ public:
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr"
};
- return llvm::makeArrayRef(GCCRegNames);
+ return llvm::ArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override {
- return None;
+ return std::nullopt;
}
bool validateAsmConstraint(const char *&Name,
diff --git a/clang/lib/Basic/TypeTraits.cpp b/clang/lib/Basic/TypeTraits.cpp
index 3b723afff70b..4dbf678dc395 100644
--- a/clang/lib/Basic/TypeTraits.cpp
+++ b/clang/lib/Basic/TypeTraits.cpp
@@ -55,6 +55,15 @@ static constexpr const char *UnaryExprOrTypeTraitSpellings[] = {
#include "clang/Basic/TokenKinds.def"
};
+static constexpr const unsigned TypeTraitArities[] = {
+#define TYPE_TRAIT_1(Spelling, Name, Key) 1,
+#include "clang/Basic/TokenKinds.def"
+#define TYPE_TRAIT_2(Spelling, Name, Key) 2,
+#include "clang/Basic/TokenKinds.def"
+#define TYPE_TRAIT_N(Spelling, Name, Key) 0,
+#include "clang/Basic/TokenKinds.def"
+};
+
const char *clang::getTraitName(TypeTrait T) {
assert(T <= TT_Last && "invalid enum value!");
return TypeTraitNames[T];
@@ -84,3 +93,8 @@ const char *clang::getTraitSpelling(UnaryExprOrTypeTrait T) {
assert(T <= UETT_Last && "invalid enum value!");
return UnaryExprOrTypeTraitSpellings[T];
}
+
+unsigned clang::getTypeTraitArity(TypeTrait T) {
+ assert(T <= TT_Last && "invalid enum value!");
+ return TypeTraitArities[T];
+}
diff --git a/clang/lib/CodeGen/ABIInfo.h b/clang/lib/CodeGen/ABIInfo.h
index c1eb8a975796..755d2aaa7beb 100644
--- a/clang/lib/CodeGen/ABIInfo.h
+++ b/clang/lib/CodeGen/ABIInfo.h
@@ -33,7 +33,6 @@ namespace CodeGen {
class CGFunctionInfo;
class CodeGenFunction;
class CodeGenTypes;
- class SwiftABIInfo;
// FIXME: All of this stuff should be part of the target interface
// somehow. It is currently here because it is not clear how to factor
@@ -44,9 +43,8 @@ namespace CodeGen {
/// ABIInfo - Target specific hooks for defining how a type should be
/// passed or returned from functions.
class ABIInfo {
- public:
- CodeGen::CodeGenTypes &CGT;
protected:
+ CodeGen::CodeGenTypes &CGT;
llvm::CallingConv::ID RuntimeCC;
public:
ABIInfo(CodeGen::CodeGenTypes &cgt)
@@ -54,8 +52,6 @@ namespace CodeGen {
virtual ~ABIInfo();
- virtual bool supportsSwift() const { return false; }
-
virtual bool allowBFloatArgsAndRet() const { return false; }
CodeGen::CGCXXABI &getCXXABI() const;
@@ -114,33 +110,33 @@ namespace CodeGen {
CodeGen::ABIArgInfo
getNaturalAlignIndirectInReg(QualType Ty, bool Realign = false) const;
-
-
};
- /// A refining implementation of ABIInfo for targets that support swiftcall.
- ///
- /// If we find ourselves wanting multiple such refinements, they'll probably
- /// be independent refinements, and we should probably find another way
- /// to do it than simple inheritance.
- class SwiftABIInfo : public ABIInfo {
- public:
- SwiftABIInfo(CodeGen::CodeGenTypes &cgt) : ABIInfo(cgt) {}
+ /// Target specific hooks for defining how a type should be passed or returned
+ /// from functions with one of the Swift calling conventions.
+ class SwiftABIInfo {
+ protected:
+ CodeGenTypes &CGT;
+ bool SwiftErrorInRegister;
- bool supportsSwift() const final { return true; }
+ public:
+ SwiftABIInfo(CodeGen::CodeGenTypes &CGT, bool SwiftErrorInRegister)
+ : CGT(CGT), SwiftErrorInRegister(SwiftErrorInRegister) {}
- virtual bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> types,
- bool asReturnValue) const = 0;
+ virtual ~SwiftABIInfo();
- virtual bool isLegalVectorTypeForSwift(CharUnits totalSize,
- llvm::Type *eltTy,
- unsigned elts) const;
+ /// Returns true if an aggregate which expands to the given type sequence
+ /// should be passed / returned indirectly.
+ virtual bool shouldPassIndirectly(ArrayRef<llvm::Type *> ComponentTys,
+ bool AsReturnValue) const;
- virtual bool isSwiftErrorInRegister() const = 0;
+ /// Returns true if the given vector type is legal from Swift's calling
+ /// convention perspective.
+ virtual bool isLegalVectorType(CharUnits VectorSize, llvm::Type *EltTy,
+ unsigned NumElts) const;
- static bool classof(const ABIInfo *info) {
- return info->supportsSwift();
- }
+ /// Returns true if swifterror is lowered to a register by the target ABI.
+ bool isSwiftErrorInRegister() const { return SwiftErrorInRegister; };
};
} // end namespace CodeGen
} // end namespace clang
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 7c4e35634e5d..10d6bff25e6d 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/StackSafetyAnalysis.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
@@ -29,12 +30,13 @@
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/IRPrintingPasses.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Verifier.h"
+#include "llvm/IRPrinter/IRPrintingPasses.h"
#include "llvm/LTO/LTOBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/SubtargetFeature.h"
@@ -70,14 +72,17 @@
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
+#include "llvm/Transforms/Instrumentation/KCFI.h"
#include "llvm/Transforms/Instrumentation/MemProfiler.h"
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
+#include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h"
#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/EarlyCSE.h"
#include "llvm/Transforms/Scalar/GVN.h"
+#include "llvm/Transforms/Scalar/JumpThreading.h"
#include "llvm/Transforms/Scalar/LowerMatrixIntrinsics.h"
#include "llvm/Transforms/Utils.h"
#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
@@ -87,6 +92,7 @@
#include "llvm/Transforms/Utils/NameAnonGlobals.h"
#include "llvm/Transforms/Utils/SymbolRewriter.h"
#include <memory>
+#include <optional>
using namespace clang;
using namespace llvm;
@@ -96,6 +102,11 @@ using namespace llvm;
namespace llvm {
extern cl::opt<bool> DebugInfoCorrelate;
+
+// Experiment to move sanitizers earlier.
+static cl::opt<bool> ClSanitizeOnOptimizerEarlyEP(
+ "sanitizer-early-opt-ep", cl::Optional,
+ cl::desc("Insert sanitizers on OptimizerEarlyEP."), cl::init(false));
}
namespace {
@@ -215,6 +226,16 @@ getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) {
Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth;
Opts.TraceLoads = CGOpts.SanitizeCoverageTraceLoads;
Opts.TraceStores = CGOpts.SanitizeCoverageTraceStores;
+ Opts.CollectControlFlow = CGOpts.SanitizeCoverageControlFlow;
+ return Opts;
+}
+
+static SanitizerBinaryMetadataOptions
+getSanitizerBinaryMetadataOptions(const CodeGenOptions &CGOpts) {
+ SanitizerBinaryMetadataOptions Opts;
+ Opts.Covered = CGOpts.SanitizeBinaryMetadataCovered;
+ Opts.Atomics = CGOpts.SanitizeBinaryMetadataAtomics;
+ Opts.UAR = CGOpts.SanitizeBinaryMetadataUAR;
return Opts;
}
@@ -250,27 +271,28 @@ static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple,
switch (CodeGenOpts.getVecLib()) {
case CodeGenOptions::Accelerate:
- TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::Accelerate);
+ TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::Accelerate,
+ TargetTriple);
break;
case CodeGenOptions::LIBMVEC:
- switch(TargetTriple.getArch()) {
- default:
- break;
- case llvm::Triple::x86_64:
- TLII->addVectorizableFunctionsFromVecLib
- (TargetLibraryInfoImpl::LIBMVEC_X86);
- break;
- }
+ TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::LIBMVEC_X86,
+ TargetTriple);
break;
case CodeGenOptions::MASSV:
- TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::MASSV);
+ TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::MASSV,
+ TargetTriple);
break;
case CodeGenOptions::SVML:
- TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::SVML);
+ TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::SVML,
+ TargetTriple);
+ break;
+ case CodeGenOptions::SLEEF:
+ TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::SLEEFGNUABI,
+ TargetTriple);
break;
case CodeGenOptions::Darwin_libsystem_m:
TLII->addVectorizableFunctionsFromVecLib(
- TargetLibraryInfoImpl::DarwinLibSystemM);
+ TargetLibraryInfoImpl::DarwinLibSystemM, TargetTriple);
break;
default:
break;
@@ -278,22 +300,7 @@ static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple,
return TLII;
}
-static CodeGenOpt::Level getCGOptLevel(const CodeGenOptions &CodeGenOpts) {
- switch (CodeGenOpts.OptimizationLevel) {
- default:
- llvm_unreachable("Invalid optimization level!");
- case 0:
- return CodeGenOpt::None;
- case 1:
- return CodeGenOpt::Less;
- case 2:
- return CodeGenOpt::Default; // O2/Os/Oz
- case 3:
- return CodeGenOpt::Aggressive;
- }
-}
-
-static Optional<llvm::CodeModel::Model>
+static std::optional<llvm::CodeModel::Model>
getCodeModel(const CodeGenOptions &CodeGenOpts) {
unsigned CodeModel = llvm::StringSwitch<unsigned>(CodeGenOpts.CodeModel)
.Case("tiny", llvm::CodeModel::Tiny)
@@ -305,7 +312,7 @@ getCodeModel(const CodeGenOptions &CodeGenOpts) {
.Default(~0u);
assert(CodeModel != ~0u && "invalid code model!");
if (CodeModel == ~1u)
- return None;
+ return std::nullopt;
return static_cast<llvm::CodeModel::Model>(CodeModel);
}
@@ -391,7 +398,12 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
Options.NoInfsFPMath = LangOpts.NoHonorInfs;
Options.NoNaNsFPMath = LangOpts.NoHonorNaNs;
Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
- Options.UnsafeFPMath = LangOpts.UnsafeFPMath;
+ Options.UnsafeFPMath = LangOpts.AllowFPReassoc && LangOpts.AllowRecip &&
+ LangOpts.NoSignedZero && LangOpts.ApproxFunc &&
+ (LangOpts.getDefaultFPContractMode() ==
+ LangOptions::FPModeKind::FPM_Fast ||
+ LangOpts.getDefaultFPContractMode() ==
+ LangOptions::FPModeKind::FPM_FastHonorPragmas);
Options.ApproxFuncFPMath = LangOpts.ApproxFunc;
Options.BBSections =
@@ -422,7 +434,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
CodeGenOpts.UniqueBasicBlockSectionNames;
Options.TLSSize = CodeGenOpts.TLSSize;
Options.EmulatedTLS = CodeGenOpts.EmulatedTLS;
- Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS;
+ Options.ExplicitEmulatedTLS = true;
Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning();
Options.EmitStackSizeSection = CodeGenOpts.StackSizeSection;
Options.StackUsageOutput = CodeGenOpts.StackUsageOutput;
@@ -478,15 +490,16 @@ static bool initTargetOptions(DiagnosticsEngine &Diags,
Entry.IgnoreSysRoot ? Entry.Path : HSOpts.Sysroot + Entry.Path);
Options.MCOptions.Argv0 = CodeGenOpts.Argv0;
Options.MCOptions.CommandLineArgs = CodeGenOpts.CommandLineArgs;
+ Options.MCOptions.AsSecureLogFile = CodeGenOpts.AsSecureLogFile;
Options.MisExpect = CodeGenOpts.MisExpect;
return true;
}
-static Optional<GCOVOptions> getGCOVOptions(const CodeGenOptions &CodeGenOpts,
- const LangOptions &LangOpts) {
+static std::optional<GCOVOptions>
+getGCOVOptions(const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts) {
if (!CodeGenOpts.EmitGcovArcs && !CodeGenOpts.EmitGcovNotes)
- return None;
+ return std::nullopt;
// Not using 'GCOVOptions::getDefault' allows us to avoid exiting if
// LLVM's -default-gcov-version flag is set to something invalid.
GCOVOptions Options;
@@ -500,11 +513,11 @@ static Optional<GCOVOptions> getGCOVOptions(const CodeGenOptions &CodeGenOpts,
return Options;
}
-static Optional<InstrProfOptions>
+static std::optional<InstrProfOptions>
getInstrProfOptions(const CodeGenOptions &CodeGenOpts,
const LangOptions &LangOpts) {
if (!CodeGenOpts.hasProfileClangInstr())
- return None;
+ return std::nullopt;
InstrProfOptions Options;
Options.NoRedZone = CodeGenOpts.DisableRedZone;
Options.InstrProfileOutput = CodeGenOpts.InstrProfileOutput;
@@ -547,11 +560,14 @@ void EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
return;
}
- Optional<llvm::CodeModel::Model> CM = getCodeModel(CodeGenOpts);
+ std::optional<llvm::CodeModel::Model> CM = getCodeModel(CodeGenOpts);
std::string FeaturesStr =
llvm::join(TargetOpts.Features.begin(), TargetOpts.Features.end(), ",");
llvm::Reloc::Model RM = CodeGenOpts.RelocationModel;
- CodeGenOpt::Level OptLevel = getCGOptLevel(CodeGenOpts);
+ std::optional<CodeGenOpt::Level> OptLevelOrNone =
+ CodeGenOpt::getLevel(CodeGenOpts.OptimizationLevel);
+ assert(OptLevelOrNone && "Invalid optimization level!");
+ CodeGenOpt::Level OptLevel = *OptLevelOrNone;
llvm::TargetOptions Options;
if (!initTargetOptions(Diags, Options, CodeGenOpts, TargetOpts, LangOpts,
@@ -620,18 +636,48 @@ static OptimizationLevel mapToLevel(const CodeGenOptions &Opts) {
}
}
+static void addKCFIPass(const Triple &TargetTriple, const LangOptions &LangOpts,
+ PassBuilder &PB) {
+ // If the back-end supports KCFI operand bundle lowering, skip KCFIPass.
+ if (TargetTriple.getArch() == llvm::Triple::x86_64 ||
+ TargetTriple.isAArch64(64))
+ return;
+
+ // Ensure we lower KCFI operand bundles with -O0.
+ PB.registerOptimizerLastEPCallback(
+ [&](ModulePassManager &MPM, OptimizationLevel Level) {
+ if (Level == OptimizationLevel::O0 &&
+ LangOpts.Sanitize.has(SanitizerKind::KCFI))
+ MPM.addPass(createModuleToFunctionPassAdaptor(KCFIPass()));
+ });
+
+ // When optimizations are requested, run KCIFPass after InstCombine to
+ // avoid unnecessary checks.
+ PB.registerPeepholeEPCallback(
+ [&](FunctionPassManager &FPM, OptimizationLevel Level) {
+ if (Level != OptimizationLevel::O0 &&
+ LangOpts.Sanitize.has(SanitizerKind::KCFI))
+ FPM.addPass(KCFIPass());
+ });
+}
+
static void addSanitizers(const Triple &TargetTriple,
const CodeGenOptions &CodeGenOpts,
const LangOptions &LangOpts, PassBuilder &PB) {
- PB.registerOptimizerLastEPCallback([&](ModulePassManager &MPM,
- OptimizationLevel Level) {
+ auto SanitizersCallback = [&](ModulePassManager &MPM,
+ OptimizationLevel Level) {
if (CodeGenOpts.hasSanitizeCoverage()) {
auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts);
- MPM.addPass(ModuleSanitizerCoveragePass(
+ MPM.addPass(SanitizerCoveragePass(
SancovOpts, CodeGenOpts.SanitizeCoverageAllowlistFiles,
CodeGenOpts.SanitizeCoverageIgnorelistFiles));
}
+ if (CodeGenOpts.hasSanitizeBinaryMetadata()) {
+ MPM.addPass(SanitizerBinaryMetadataPass(
+ getSanitizerBinaryMetadataOptions(CodeGenOpts)));
+ }
+
auto MSanPass = [&](SanitizerMask Mask, bool CompileKernel) {
if (LangOpts.Sanitize.has(Mask)) {
int TrackOrigins = CodeGenOpts.SanitizeMemoryTrackOrigins;
@@ -639,22 +685,21 @@ static void addSanitizers(const Triple &TargetTriple,
MemorySanitizerOptions options(TrackOrigins, Recover, CompileKernel,
CodeGenOpts.SanitizeMemoryParamRetval);
- MPM.addPass(ModuleMemorySanitizerPass(options));
- FunctionPassManager FPM;
- FPM.addPass(MemorySanitizerPass(options));
+ MPM.addPass(MemorySanitizerPass(options));
if (Level != OptimizationLevel::O0) {
- // MemorySanitizer inserts complex instrumentation that mostly
- // follows the logic of the original code, but operates on
- // "shadow" values. It can benefit from re-running some
- // general purpose optimization passes.
- FPM.addPass(EarlyCSEPass());
- // TODO: Consider add more passes like in
- // addGeneralOptsForMemorySanitizer. EarlyCSEPass makes visible
- // difference on size. It's not clear if the rest is still
- // usefull. InstCombinePass breakes
- // compiler-rt/test/msan/select_origin.cpp.
+ // MemorySanitizer inserts complex instrumentation that mostly follows
+ // the logic of the original code, but operates on "shadow" values. It
+ // can benefit from re-running some general purpose optimization
+ // passes.
+ MPM.addPass(RequireAnalysisPass<GlobalsAA, Module>());
+ FunctionPassManager FPM;
+ FPM.addPass(EarlyCSEPass(true /* Enable mem-ssa. */));
+ FPM.addPass(InstCombinePass());
+ FPM.addPass(JumpThreadingPass());
+ FPM.addPass(GVNPass());
+ FPM.addPass(InstCombinePass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
}
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
}
};
MSanPass(SanitizerKind::Memory, false);
@@ -676,8 +721,8 @@ static void addSanitizers(const Triple &TargetTriple,
Opts.Recover = CodeGenOpts.SanitizeRecover.has(Mask);
Opts.UseAfterScope = CodeGenOpts.SanitizeAddressUseAfterScope;
Opts.UseAfterReturn = CodeGenOpts.getSanitizeAddressUseAfterReturn();
- MPM.addPass(ModuleAddressSanitizerPass(
- Opts, UseGlobalGC, UseOdrIndicator, DestructorKind));
+ MPM.addPass(AddressSanitizerPass(Opts, UseGlobalGC, UseOdrIndicator,
+ DestructorKind));
}
};
ASanPass(SanitizerKind::Address, false);
@@ -697,13 +742,28 @@ static void addSanitizers(const Triple &TargetTriple,
if (LangOpts.Sanitize.has(SanitizerKind::DataFlow)) {
MPM.addPass(DataFlowSanitizerPass(LangOpts.NoSanitizeFiles));
}
- });
+ };
+ if (ClSanitizeOnOptimizerEarlyEP) {
+ PB.registerOptimizerEarlyEPCallback(
+ [SanitizersCallback](ModulePassManager &MPM, OptimizationLevel Level) {
+ ModulePassManager NewMPM;
+ SanitizersCallback(NewMPM, Level);
+ if (!NewMPM.isEmpty()) {
+ // Sanitizers can abandon<GlobalsAA>.
+ NewMPM.addPass(RequireAnalysisPass<GlobalsAA, Module>());
+ MPM.addPass(std::move(NewMPM));
+ }
+ });
+ } else {
+ // LastEP does not need GlobalsAA.
+ PB.registerOptimizerLastEPCallback(SanitizersCallback);
+ }
}
void EmitAssemblyHelper::RunOptimizationPipeline(
BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS,
std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS) {
- Optional<PGOOptions> PGOOpt;
+ std::optional<PGOOptions> PGOOpt;
if (CodeGenOpts.hasProfileIRInstr())
// -fprofile-generate.
@@ -782,12 +842,20 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
PrintPassOptions PrintPassOpts;
PrintPassOpts.Indent = DebugPassStructure;
PrintPassOpts.SkipAnalyses = DebugPassStructure;
- StandardInstrumentations SI(CodeGenOpts.DebugPassManager ||
- DebugPassStructure,
- /*VerifyEach*/ false, PrintPassOpts);
+ StandardInstrumentations SI(
+ TheModule->getContext(),
+ (CodeGenOpts.DebugPassManager || DebugPassStructure),
+ /*VerifyEach*/ false, PrintPassOpts);
SI.registerCallbacks(PIC, &FAM);
PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC);
+ if (CodeGenOpts.EnableAssignmentTracking) {
+ PB.registerPipelineStartEPCallback(
+ [&](ModulePassManager &MPM, OptimizationLevel Level) {
+ MPM.addPass(AssignmentTrackingPass());
+ });
+ }
+
// Enable verify-debuginfo-preserve-each for new PM.
DebugifyEachInstrumentation Debugify;
DebugInfoPerPass DebugInfoBeforePass;
@@ -896,15 +964,18 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
// Don't add sanitizers if we are here from ThinLTO PostLink. That already
// done on PreLink stage.
- if (!IsThinLTOPostLink)
+ if (!IsThinLTOPostLink) {
addSanitizers(TargetTriple, CodeGenOpts, LangOpts, PB);
+ addKCFIPass(TargetTriple, LangOpts, PB);
+ }
- if (Optional<GCOVOptions> Options = getGCOVOptions(CodeGenOpts, LangOpts))
+ if (std::optional<GCOVOptions> Options =
+ getGCOVOptions(CodeGenOpts, LangOpts))
PB.registerPipelineStartEPCallback(
[Options](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(GCOVProfilerPass(*Options));
});
- if (Optional<InstrProfOptions> Options =
+ if (std::optional<InstrProfOptions> Options =
getInstrProfOptions(CodeGenOpts, LangOpts))
PB.registerPipelineStartEPCallback(
[Options](ModulePassManager &MPM, OptimizationLevel Level) {
@@ -933,19 +1004,24 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
if (!actionRequiresCodeGen(Action) && CodeGenOpts.VerifyModule)
MPM.addPass(VerifierPass());
- switch (Action) {
- case Backend_EmitBC:
+ if (Action == Backend_EmitBC || Action == Backend_EmitLL) {
if (CodeGenOpts.PrepareForThinLTO && !CodeGenOpts.DisableLLVMPasses) {
- if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) {
- ThinLinkOS = openOutputFile(CodeGenOpts.ThinLinkBitcodeFile);
- if (!ThinLinkOS)
- return;
- }
if (!TheModule->getModuleFlag("EnableSplitLTOUnit"))
TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit",
CodeGenOpts.EnableSplitLTOUnit);
- MPM.addPass(ThinLTOBitcodeWriterPass(*OS, ThinLinkOS ? &ThinLinkOS->os()
- : nullptr));
+ if (Action == Backend_EmitBC) {
+ if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) {
+ ThinLinkOS = openOutputFile(CodeGenOpts.ThinLinkBitcodeFile);
+ if (!ThinLinkOS)
+ return;
+ }
+ MPM.addPass(ThinLTOBitcodeWriterPass(*OS, ThinLinkOS ? &ThinLinkOS->os()
+ : nullptr));
+ } else {
+ MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists,
+ /*EmitLTOSummary=*/true));
+ }
+
} else {
// Emit a module summary by default for Regular LTO except for ld64
// targets
@@ -957,17 +1033,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit",
uint32_t(1));
}
- MPM.addPass(
- BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists, EmitLTOSummary));
+ if (Action == Backend_EmitBC)
+ MPM.addPass(BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists,
+ EmitLTOSummary));
+ else
+ MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists,
+ EmitLTOSummary));
}
- break;
-
- case Backend_EmitLL:
- MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists));
- break;
-
- default:
- break;
}
// Now that we have all of the passes ready, run them.
@@ -1059,7 +1131,7 @@ static void runThinLTOBackend(
if (!lto::initImportList(*M, *CombinedIndex, ImportList))
return;
- auto AddStream = [&](size_t Task) {
+ auto AddStream = [&](size_t Task, const Twine &ModuleName) {
return std::make_unique<CachedFileStream>(std::move(OS),
CGOpts.ObjectFilenameForDebug);
};
@@ -1077,7 +1149,10 @@ static void runThinLTOBackend(
Conf.CodeModel = getCodeModel(CGOpts);
Conf.MAttrs = TOpts.Features;
Conf.RelocModel = CGOpts.RelocationModel;
- Conf.CGOptLevel = getCGOptLevel(CGOpts);
+ std::optional<CodeGenOpt::Level> OptLevelOrNone =
+ CodeGenOpt::getLevel(CGOpts.OptimizationLevel);
+ assert(OptLevelOrNone && "Invalid optimization level!");
+ Conf.CGOptLevel = *OptLevelOrNone;
Conf.OptLevel = CGOpts.OptimizationLevel;
initTargetOptions(Diags, Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts);
Conf.SampleProfile = std::move(SampleProfile);
diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index dee0cb64be97..8ef95bb80846 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -609,7 +609,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
case AtomicExpr::AO__atomic_add_fetch:
PostOp = E->getValueType()->isFloatingType() ? llvm::Instruction::FAdd
: llvm::Instruction::Add;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_add:
case AtomicExpr::AO__hip_atomic_fetch_add:
case AtomicExpr::AO__opencl_atomic_fetch_add:
@@ -621,7 +621,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
case AtomicExpr::AO__atomic_sub_fetch:
PostOp = E->getValueType()->isFloatingType() ? llvm::Instruction::FSub
: llvm::Instruction::Sub;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_sub:
case AtomicExpr::AO__opencl_atomic_fetch_sub:
case AtomicExpr::AO__atomic_fetch_sub:
@@ -631,7 +631,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
case AtomicExpr::AO__atomic_min_fetch:
PostOpMinMax = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_min:
case AtomicExpr::AO__hip_atomic_fetch_min:
case AtomicExpr::AO__opencl_atomic_fetch_min:
@@ -642,7 +642,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
case AtomicExpr::AO__atomic_max_fetch:
PostOpMinMax = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_max:
case AtomicExpr::AO__hip_atomic_fetch_max:
case AtomicExpr::AO__opencl_atomic_fetch_max:
@@ -653,7 +653,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
case AtomicExpr::AO__atomic_and_fetch:
PostOp = llvm::Instruction::And;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_and:
case AtomicExpr::AO__hip_atomic_fetch_and:
case AtomicExpr::AO__opencl_atomic_fetch_and:
@@ -663,7 +663,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
case AtomicExpr::AO__atomic_or_fetch:
PostOp = llvm::Instruction::Or;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_or:
case AtomicExpr::AO__hip_atomic_fetch_or:
case AtomicExpr::AO__opencl_atomic_fetch_or:
@@ -673,7 +673,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
case AtomicExpr::AO__atomic_xor_fetch:
PostOp = llvm::Instruction::Xor;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_xor:
case AtomicExpr::AO__hip_atomic_fetch_xor:
case AtomicExpr::AO__opencl_atomic_fetch_xor:
@@ -683,7 +683,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest,
case AtomicExpr::AO__atomic_nand_fetch:
PostOp = llvm::Instruction::And; // the NOT is special cased below
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_nand:
case AtomicExpr::AO__atomic_fetch_nand:
Op = llvm::AtomicRMWInst::Nand;
@@ -914,13 +914,13 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Temp, Val1Ty));
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_sub:
case AtomicExpr::AO__atomic_add_fetch:
case AtomicExpr::AO__atomic_sub_fetch:
ShouldCastToIntPtrTy = !MemTy->isFloatingType();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_store:
case AtomicExpr::AO__c11_atomic_exchange:
@@ -1045,7 +1045,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// suitably aligned for the optimized version.
if (Misaligned)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_load:
case AtomicExpr::AO__c11_atomic_store:
case AtomicExpr::AO__c11_atomic_exchange:
@@ -1176,7 +1176,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// T __atomic_fetch_add_N(T *mem, T val, int order)
case AtomicExpr::AO__atomic_add_fetch:
PostOp = llvm::Instruction::Add;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_add:
case AtomicExpr::AO__opencl_atomic_fetch_add:
case AtomicExpr::AO__atomic_fetch_add:
@@ -1189,7 +1189,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// T __atomic_fetch_and_N(T *mem, T val, int order)
case AtomicExpr::AO__atomic_and_fetch:
PostOp = llvm::Instruction::And;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_and:
case AtomicExpr::AO__opencl_atomic_fetch_and:
case AtomicExpr::AO__hip_atomic_fetch_and:
@@ -1202,7 +1202,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// T __atomic_fetch_or_N(T *mem, T val, int order)
case AtomicExpr::AO__atomic_or_fetch:
PostOp = llvm::Instruction::Or;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_or:
case AtomicExpr::AO__opencl_atomic_fetch_or:
case AtomicExpr::AO__hip_atomic_fetch_or:
@@ -1215,7 +1215,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// T __atomic_fetch_sub_N(T *mem, T val, int order)
case AtomicExpr::AO__atomic_sub_fetch:
PostOp = llvm::Instruction::Sub;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_sub:
case AtomicExpr::AO__opencl_atomic_fetch_sub:
case AtomicExpr::AO__atomic_fetch_sub:
@@ -1227,7 +1227,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// T __atomic_fetch_xor_N(T *mem, T val, int order)
case AtomicExpr::AO__atomic_xor_fetch:
PostOp = llvm::Instruction::Xor;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_xor:
case AtomicExpr::AO__opencl_atomic_fetch_xor:
case AtomicExpr::AO__hip_atomic_fetch_xor:
@@ -1238,7 +1238,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
break;
case AtomicExpr::AO__atomic_min_fetch:
PostOpMinMax = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_min:
case AtomicExpr::AO__atomic_fetch_min:
case AtomicExpr::AO__hip_atomic_fetch_min:
@@ -1251,7 +1251,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
break;
case AtomicExpr::AO__atomic_max_fetch:
PostOpMinMax = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_max:
case AtomicExpr::AO__atomic_fetch_max:
case AtomicExpr::AO__hip_atomic_fetch_max:
@@ -1266,7 +1266,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
// T __atomic_fetch_nand_N(T *mem, T val, int order)
case AtomicExpr::AO__atomic_nand_fetch:
PostOp = llvm::Instruction::And; // the NOT is special cased below
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case AtomicExpr::AO__c11_atomic_fetch_nand:
case AtomicExpr::AO__atomic_fetch_nand:
LibCallName = "__atomic_fetch_nand";
@@ -1594,7 +1594,7 @@ llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO,
/// we are operating under /volatile:ms *and* the LValue itself is volatile and
/// performing such an operation can be performed without a libcall.
bool CodeGenFunction::LValueIsSuitableForInlineAtomic(LValue LV) {
- if (!CGM.getCodeGenOpts().MSVolatile) return false;
+ if (!CGM.getLangOpts().MSVolatile) return false;
AtomicInfo AI(*this, LV);
bool IsVolatile = LV.isVolatile() || hasVolatileMember(LV.getType());
// An atomic is inline if we don't need to use a libcall.
diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp
index ff6ca0914e0d..6e4a0dbf2335 100644
--- a/clang/lib/CodeGen/CGBlocks.cpp
+++ b/clang/lib/CodeGen/CGBlocks.cpp
@@ -502,12 +502,10 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
if (CGM.getLangOpts().OpenCL) {
// The header is basically 'struct { int; int; generic void *;
// custom_fields; }'. Assert that struct is packed.
- auto GenericAS =
- CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic);
- auto GenPtrAlign =
- CharUnits::fromQuantity(CGM.getTarget().getPointerAlign(GenericAS) / 8);
- auto GenPtrSize =
- CharUnits::fromQuantity(CGM.getTarget().getPointerWidth(GenericAS) / 8);
+ auto GenPtrAlign = CharUnits::fromQuantity(
+ CGM.getTarget().getPointerAlign(LangAS::opencl_generic) / 8);
+ auto GenPtrSize = CharUnits::fromQuantity(
+ CGM.getTarget().getPointerWidth(LangAS::opencl_generic) / 8);
assert(CGM.getIntSize() <= GenPtrSize);
assert(CGM.getIntAlign() <= GenPtrAlign);
assert((2 * CGM.getIntSize()).isMultipleOf(GenPtrAlign));
@@ -521,10 +519,10 @@ static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info,
unsigned BlockAlign = GenPtrAlign.getQuantity();
if (auto *Helper =
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
- for (auto I : Helper->getCustomFieldTypes()) /* custom fields */ {
+ for (auto *I : Helper->getCustomFieldTypes()) /* custom fields */ {
// TargetOpenCLBlockHelp needs to make sure the struct is packed.
// If necessary, add padding fields to the custom fields.
- unsigned Align = CGM.getDataLayout().getABITypeAlignment(I);
+ unsigned Align = CGM.getDataLayout().getABITypeAlign(I).value();
if (BlockAlign < Align)
BlockAlign = Align;
assert(Offset % Align == 0);
@@ -806,9 +804,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
IsOpenCL ? CGM.getOpenCLRuntime().getGenericVoidPointerType() : VoidPtrTy;
LangAS GenVoidPtrAddr = IsOpenCL ? LangAS::opencl_generic : LangAS::Default;
auto GenVoidPtrSize = CharUnits::fromQuantity(
- CGM.getTarget().getPointerWidth(
- CGM.getContext().getTargetAddressSpace(GenVoidPtrAddr)) /
- 8);
+ CGM.getTarget().getPointerWidth(GenVoidPtrAddr) / 8);
// Using the computed layout, generate the actual block function.
bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda();
CodeGenFunction BlockCGF{CGM, true};
@@ -1356,7 +1352,7 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
fields.add(buildBlockDescriptor(CGM, blockInfo));
} else if (auto *Helper =
CGM.getTargetCodeGenInfo().getTargetOpenCLBlockHelper()) {
- for (auto I : Helper->getCustomFieldValues(CGM, blockInfo)) {
+ for (auto *I : Helper->getCustomFieldValues(CGM, blockInfo)) {
fields.add(I);
}
}
@@ -2676,7 +2672,7 @@ const BlockByrefInfo &CodeGenFunction::getBlockByrefInfo(const VarDecl *D) {
size = varOffset;
// Conversely, we might have to prevent LLVM from inserting padding.
- } else if (CGM.getDataLayout().getABITypeAlignment(varTy) >
+ } else if (CGM.getDataLayout().getABITypeAlign(varTy) >
uint64_t(varAlign.getQuantity())) {
packed = true;
}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 113c629bf9ed..f72e04a425d9 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -41,6 +41,7 @@
#include "llvm/IR/IntrinsicsARM.h"
#include "llvm/IR/IntrinsicsBPF.h"
#include "llvm/IR/IntrinsicsHexagon.h"
+#include "llvm/IR/IntrinsicsLoongArch.h"
#include "llvm/IR/IntrinsicsNVPTX.h"
#include "llvm/IR/IntrinsicsPowerPC.h"
#include "llvm/IR/IntrinsicsR600.h"
@@ -51,20 +52,17 @@
#include "llvm/IR/IntrinsicsX86.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/MatrixBuilder.h"
+#include "llvm/Support/AArch64TargetParser.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/X86TargetParser.h"
+#include <optional>
#include <sstream>
using namespace clang;
using namespace CodeGen;
using namespace llvm;
-static
-int64_t clamp(int64_t Value, int64_t Low, int64_t High) {
- return std::min(High, std::max(Low, Value));
-}
-
static void initializeAlloca(CodeGenFunction &CGF, AllocaInst *AI, Value *Size,
Align AlignmentInBytes) {
ConstantInt *Byte;
@@ -110,6 +108,15 @@ llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
{Builtin::BI__builtin_nexttowardf128, "__nexttowardieee128"},
};
+ // The AIX library functions frexpl, ldexpl, and modfl are for 128-bit
+ // IBM 'long double' (i.e. __ibm128). Map to the 'double' versions
+ // if it is 64-bit 'long double' mode.
+ static SmallDenseMap<unsigned, StringRef, 4> AIXLongDouble64Builtins{
+ {Builtin::BI__builtin_frexpl, "frexp"},
+ {Builtin::BI__builtin_ldexpl, "ldexp"},
+ {Builtin::BI__builtin_modfl, "modf"},
+ };
+
// If the builtin has been declared explicitly with an assembler label,
// use the mangled name. This differs from the plain label on platforms
// that prefix labels.
@@ -122,8 +129,14 @@ llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
&getTarget().getLongDoubleFormat() == &llvm::APFloat::IEEEquad() &&
F128Builtins.find(BuiltinID) != F128Builtins.end())
Name = F128Builtins[BuiltinID];
+ else if (getTriple().isOSAIX() &&
+ &getTarget().getLongDoubleFormat() ==
+ &llvm::APFloat::IEEEdouble() &&
+ AIXLongDouble64Builtins.find(BuiltinID) !=
+ AIXLongDouble64Builtins.end())
+ Name = AIXLongDouble64Builtins[BuiltinID];
else
- Name = Context.BuiltinInfo.getName(BuiltinID) + 10;
+ Name = Context.BuiltinInfo.getName(BuiltinID).substr(10);
}
llvm::FunctionType *Ty =
@@ -675,6 +688,8 @@ static Value *emitRangedBuiltin(CodeGenFunction &CGF,
Function *F = CGF.CGM.getIntrinsic(IntrinsicID, {});
llvm::Instruction *Call = CGF.Builder.CreateCall(F);
Call->setMetadata(llvm::LLVMContext::MD_range, RNode);
+ Call->setMetadata(llvm::LLVMContext::MD_noundef,
+ llvm::MDNode::get(CGF.getLLVMContext(), std::nullopt));
return Call;
}
@@ -1164,12 +1179,12 @@ enum class CodeGenFunction::MSVCIntrin {
__fastfail,
};
-static Optional<CodeGenFunction::MSVCIntrin>
+static std::optional<CodeGenFunction::MSVCIntrin>
translateArmToMsvcIntrin(unsigned BuiltinID) {
using MSVCIntrin = CodeGenFunction::MSVCIntrin;
switch (BuiltinID) {
default:
- return None;
+ return std::nullopt;
case clang::ARM::BI_BitScanForward:
case clang::ARM::BI_BitScanForward64:
return MSVCIntrin::_BitScanForward;
@@ -1310,12 +1325,12 @@ translateArmToMsvcIntrin(unsigned BuiltinID) {
llvm_unreachable("must return from switch");
}
-static Optional<CodeGenFunction::MSVCIntrin>
+static std::optional<CodeGenFunction::MSVCIntrin>
translateAarch64ToMsvcIntrin(unsigned BuiltinID) {
using MSVCIntrin = CodeGenFunction::MSVCIntrin;
switch (BuiltinID) {
default:
- return None;
+ return std::nullopt;
case clang::AArch64::BI_BitScanForward:
case clang::AArch64::BI_BitScanForward64:
return MSVCIntrin::_BitScanForward;
@@ -1464,12 +1479,12 @@ translateAarch64ToMsvcIntrin(unsigned BuiltinID) {
llvm_unreachable("must return from switch");
}
-static Optional<CodeGenFunction::MSVCIntrin>
+static std::optional<CodeGenFunction::MSVCIntrin>
translateX86ToMsvcIntrin(unsigned BuiltinID) {
using MSVCIntrin = CodeGenFunction::MSVCIntrin;
switch (BuiltinID) {
default:
- return None;
+ return std::nullopt;
case clang::X86::BI_BitScanForward:
case clang::X86::BI_BitScanForward64:
return MSVCIntrin::_BitScanForward;
@@ -1704,7 +1719,7 @@ Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E,
SanitizerHandler::InvalidBuiltin,
{EmitCheckSourceLocation(E->getExprLoc()),
llvm::ConstantInt::get(Builder.getInt8Ty(), Kind)},
- None);
+ std::nullopt);
return ArgValue;
}
@@ -2204,7 +2219,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// might. Also, math builtins have the same semantics as their math library
// twins. Thus, we can transform math library and builtin calls to their
// LLVM counterparts if the call is marked 'const' (known to never set errno).
- if (FD->hasAttr<ConstAttr>()) {
+ // In case FP exceptions are enabled, the experimental versions of the
+ // intrinsics model those.
+ bool ConstWithoutErrnoAndExceptions =
+ getContext().BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
+ bool ConstWithoutExceptions =
+ getContext().BuiltinInfo.isConstWithoutExceptions(BuiltinID);
+ if (FD->hasAttr<ConstAttr>() ||
+ ((ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) &&
+ (!ConstWithoutErrnoAndExceptions || (!getLangOpts().MathErrno)))) {
switch (BuiltinIDIfNoAsmLabel) {
case Builtin::BIceil:
case Builtin::BIceilf:
@@ -2515,11 +2538,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_va_start:
case Builtin::BI__va_start:
case Builtin::BI__builtin_va_end:
- return RValue::get(
- EmitVAStartEnd(BuiltinID == Builtin::BI__va_start
- ? EmitScalarExpr(E->getArg(0))
- : EmitVAListRef(E->getArg(0)).getPointer(),
- BuiltinID != Builtin::BI__builtin_va_end));
+ EmitVAStartEnd(BuiltinID == Builtin::BI__va_start
+ ? EmitScalarExpr(E->getArg(0))
+ : EmitVAListRef(E->getArg(0)).getPointer(),
+ BuiltinID != Builtin::BI__builtin_va_end);
+ return RValue::get(nullptr);
case Builtin::BI__builtin_va_copy: {
Value *DstPtr = EmitVAListRef(E->getArg(0)).getPointer();
Value *SrcPtr = EmitVAListRef(E->getArg(1)).getPointer();
@@ -2528,8 +2551,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
DstPtr = Builder.CreateBitCast(DstPtr, Type);
SrcPtr = Builder.CreateBitCast(SrcPtr, Type);
- return RValue::get(Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy),
- {DstPtr, SrcPtr}));
+ Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy), {DstPtr, SrcPtr});
+ return RValue::get(nullptr);
}
case Builtin::BI__builtin_abs:
case Builtin::BI__builtin_labs:
@@ -2778,6 +2801,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_assume_aligned: {
const Expr *Ptr = E->getArg(0);
Value *PtrValue = EmitScalarExpr(Ptr);
+ if (PtrValue->getType() != VoidPtrTy)
+ PtrValue = EmitCastToVoidPtr(PtrValue);
Value *OffsetValue =
(E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : nullptr;
@@ -2799,7 +2824,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *ArgValue = EmitScalarExpr(E->getArg(0));
Function *FnAssume = CGM.getIntrinsic(Intrinsic::assume);
- return RValue::get(Builder.CreateCall(FnAssume, ArgValue));
+ Builder.CreateCall(FnAssume, ArgValue);
+ return RValue::get(nullptr);
}
case Builtin::BI__arithmetic_fence: {
// Create the builtin call if FastMath is selected, and the target
@@ -2920,7 +2946,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::ConstantInt::get(Int32Ty, 3);
Value *Data = llvm::ConstantInt::get(Int32Ty, 1);
Function *F = CGM.getIntrinsic(Intrinsic::prefetch, Address->getType());
- return RValue::get(Builder.CreateCall(F, {Address, RW, Locality, Data}));
+ Builder.CreateCall(F, {Address, RW, Locality, Data});
+ return RValue::get(nullptr);
}
case Builtin::BI__builtin_readcyclecounter: {
Function *F = CGM.getIntrinsic(Intrinsic::readcyclecounter);
@@ -2933,9 +2960,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Builder.CreateCall(F, {Begin, End}));
}
case Builtin::BI__builtin_trap:
- return RValue::get(EmitTrapCall(Intrinsic::trap));
+ EmitTrapCall(Intrinsic::trap);
+ return RValue::get(nullptr);
case Builtin::BI__debugbreak:
- return RValue::get(EmitTrapCall(Intrinsic::debugtrap));
+ EmitTrapCall(Intrinsic::debugtrap);
+ return RValue::get(nullptr);
case Builtin::BI__builtin_unreachable: {
EmitUnreachable(E->getExprLoc());
@@ -2971,7 +3000,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// Ordered comparisons: we know the arguments to these are matching scalar
// floating point values.
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
- // FIXME: for strictfp/IEEE-754 we need to not trap on SNaN here.
Value *LHS = EmitScalarExpr(E->getArg(0));
Value *RHS = EmitScalarExpr(E->getArg(1));
@@ -3051,16 +3079,27 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_elementwise_ceil:
return RValue::get(
emitUnaryBuiltin(*this, E, llvm::Intrinsic::ceil, "elt.ceil"));
+ case Builtin::BI__builtin_elementwise_cos:
+ return RValue::get(
+ emitUnaryBuiltin(*this, E, llvm::Intrinsic::cos, "elt.cos"));
case Builtin::BI__builtin_elementwise_floor:
return RValue::get(
emitUnaryBuiltin(*this, E, llvm::Intrinsic::floor, "elt.floor"));
case Builtin::BI__builtin_elementwise_roundeven:
return RValue::get(emitUnaryBuiltin(*this, E, llvm::Intrinsic::roundeven,
"elt.roundeven"));
+ case Builtin::BI__builtin_elementwise_sin:
+ return RValue::get(
+ emitUnaryBuiltin(*this, E, llvm::Intrinsic::sin, "elt.sin"));
+
case Builtin::BI__builtin_elementwise_trunc:
return RValue::get(
emitUnaryBuiltin(*this, E, llvm::Intrinsic::trunc, "elt.trunc"));
-
+ case Builtin::BI__builtin_elementwise_canonicalize:
+ return RValue::get(
+ emitUnaryBuiltin(*this, E, llvm::Intrinsic::canonicalize, "elt.trunc"));
+ case Builtin::BI__builtin_elementwise_copysign:
+ return RValue::get(emitBinaryBuiltin(*this, E, llvm::Intrinsic::copysign));
case Builtin::BI__builtin_elementwise_add_sat:
case Builtin::BI__builtin_elementwise_sub_sat: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
@@ -3294,7 +3333,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_flt_rounds: {
- Function *F = CGM.getIntrinsic(Intrinsic::flt_rounds);
+ Function *F = CGM.getIntrinsic(Intrinsic::get_rounding);
llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F);
@@ -3717,7 +3756,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_unwind_init: {
Function *F = CGM.getIntrinsic(Intrinsic::eh_unwind_init);
- return RValue::get(Builder.CreateCall(F));
+ Builder.CreateCall(F);
+ return RValue::get(nullptr);
}
case Builtin::BI__builtin_extend_pointer: {
// Extends a pointer to the size of an _Unwind_Word, which is
@@ -4210,7 +4250,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
StringRef WideBytes = Str->getBytes();
std::string StrUtf8;
if (!convertUTF16ToUTF8String(
- makeArrayRef(WideBytes.data(), WideBytes.size()), StrUtf8)) {
+ ArrayRef(WideBytes.data(), WideBytes.size()), StrUtf8)) {
CGM.ErrorUnsupported(E, "non-UTF16 __annotation argument");
continue;
}
@@ -4226,8 +4266,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
}
case Builtin::BI__builtin_annotation: {
llvm::Value *AnnVal = EmitScalarExpr(E->getArg(0));
- llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::annotation,
- AnnVal->getType());
+ llvm::Function *F =
+ CGM.getIntrinsic(llvm::Intrinsic::annotation,
+ {AnnVal->getType(), CGM.ConstGlobalsPtrTy});
// Get the annotation string, go through casts. Sema requires this to be a
// non-wide string literal, potentially casted, so the cast<> is safe.
@@ -4478,8 +4519,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return EmitBuiltinNewDeleteCall(
E->getCallee()->getType()->castAs<FunctionProtoType>(), E, false);
case Builtin::BI__builtin_operator_delete:
- return EmitBuiltinNewDeleteCall(
+ EmitBuiltinNewDeleteCall(
E->getCallee()->getType()->castAs<FunctionProtoType>(), E, true);
+ return RValue::get(nullptr);
case Builtin::BI__builtin_is_aligned:
return EmitBuiltinIsAligned(E);
@@ -4644,20 +4686,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__fastfail:
return RValue::get(EmitMSVCBuiltinExpr(MSVCIntrin::__fastfail, E));
- case Builtin::BI__builtin_coro_size: {
- auto & Context = getContext();
- auto SizeTy = Context.getSizeType();
- auto T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
- Function *F = CGM.getIntrinsic(Intrinsic::coro_size, T);
- return RValue::get(Builder.CreateCall(F));
- }
-
case Builtin::BI__builtin_coro_id:
return EmitCoroutineIntrinsic(E, Intrinsic::coro_id);
case Builtin::BI__builtin_coro_promise:
return EmitCoroutineIntrinsic(E, Intrinsic::coro_promise);
case Builtin::BI__builtin_coro_resume:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_resume);
+ EmitCoroutineIntrinsic(E, Intrinsic::coro_resume);
+ return RValue::get(nullptr);
case Builtin::BI__builtin_coro_frame:
return EmitCoroutineIntrinsic(E, Intrinsic::coro_frame);
case Builtin::BI__builtin_coro_noop:
@@ -4665,7 +4700,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_coro_free:
return EmitCoroutineIntrinsic(E, Intrinsic::coro_free);
case Builtin::BI__builtin_coro_destroy:
- return EmitCoroutineIntrinsic(E, Intrinsic::coro_destroy);
+ EmitCoroutineIntrinsic(E, Intrinsic::coro_destroy);
+ return RValue::get(nullptr);
case Builtin::BI__builtin_coro_done:
return EmitCoroutineIntrinsic(E, Intrinsic::coro_done);
case Builtin::BI__builtin_coro_alloc:
@@ -4676,6 +4712,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return EmitCoroutineIntrinsic(E, Intrinsic::coro_end);
case Builtin::BI__builtin_coro_suspend:
return EmitCoroutineIntrinsic(E, Intrinsic::coro_suspend);
+ case Builtin::BI__builtin_coro_size:
+ return EmitCoroutineIntrinsic(E, Intrinsic::coro_size);
+ case Builtin::BI__builtin_coro_align:
+ return EmitCoroutineIntrinsic(E, Intrinsic::coro_align);
// OpenCL v2.0 s6.13.16.2, Built-in pipe read and write functions
case Builtin::BIread_pipe:
@@ -5034,7 +5074,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
EmitLifetimeEnd(TmpSize, TmpPtr);
return Call;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
// OpenCL v2.0 s6.13.17.6 - Kernel query functions need bitcast of block
// parameter.
@@ -5094,7 +5134,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *Val = EmitScalarExpr(E->getArg(0));
Address Address = EmitPointerWithAlignment(E->getArg(1));
Value *HalfVal = Builder.CreateFPTrunc(Val, Builder.getHalfTy());
- return RValue::get(Builder.CreateStore(HalfVal, Address));
+ Builder.CreateStore(HalfVal, Address);
+ return RValue::get(nullptr);
}
case Builtin::BI__builtin_load_half: {
Address Address = EmitPointerWithAlignment(E->getArg(0));
@@ -5265,7 +5306,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
LargestVectorWidth = std::max(LargestVectorWidth, VectorWidth);
// See if we have a target specific intrinsic.
- const char *Name = getContext().BuiltinInfo.getName(BuiltinID);
+ StringRef Name = getContext().BuiltinInfo.getName(BuiltinID);
Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic;
StringRef Prefix =
llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch());
@@ -5359,6 +5400,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
V = Builder.CreateBitCast(V, RetTy);
}
+ if (RetTy->isVoidTy())
+ return RValue::get(nullptr);
+
return RValue::get(V);
}
@@ -5376,6 +5420,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E, ReturnValue)) {
switch (EvalKind) {
case TEK_Scalar:
+ if (V->getType()->isVoidTy())
+ return RValue::get(nullptr);
return RValue::get(V);
case TEK_Aggregate:
return RValue::getAggregate(ReturnValue.getValue(),
@@ -5433,6 +5479,9 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue);
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ return CGF->EmitLoongArchBuiltinExpr(BuiltinID, E);
default:
return nullptr;
}
@@ -5630,7 +5679,7 @@ struct ARMVectorIntrinsicInfo {
TypeModifier }
static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
- NEONMAP1(__a32_vcvt_bf16_v, arm_neon_vcvtfp2bf, 0),
+ NEONMAP1(__a32_vcvt_bf16_f32, arm_neon_vcvtfp2bf, 0),
NEONMAP0(splat_lane_v),
NEONMAP0(splat_laneq_v),
NEONMAP0(splatq_lane_v),
@@ -5642,21 +5691,27 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP0(vadd_v),
NEONMAP0(vaddhn_v),
NEONMAP0(vaddq_v),
- NEONMAP1(vaesdq_v, arm_neon_aesd, 0),
- NEONMAP1(vaeseq_v, arm_neon_aese, 0),
- NEONMAP1(vaesimcq_v, arm_neon_aesimc, 0),
- NEONMAP1(vaesmcq_v, arm_neon_aesmc, 0),
- NEONMAP1(vbfdot_v, arm_neon_bfdot, 0),
- NEONMAP1(vbfdotq_v, arm_neon_bfdot, 0),
- NEONMAP1(vbfmlalbq_v, arm_neon_bfmlalb, 0),
- NEONMAP1(vbfmlaltq_v, arm_neon_bfmlalt, 0),
- NEONMAP1(vbfmmlaq_v, arm_neon_bfmmla, 0),
+ NEONMAP1(vaesdq_u8, arm_neon_aesd, 0),
+ NEONMAP1(vaeseq_u8, arm_neon_aese, 0),
+ NEONMAP1(vaesimcq_u8, arm_neon_aesimc, 0),
+ NEONMAP1(vaesmcq_u8, arm_neon_aesmc, 0),
+ NEONMAP1(vbfdot_f32, arm_neon_bfdot, 0),
+ NEONMAP1(vbfdotq_f32, arm_neon_bfdot, 0),
+ NEONMAP1(vbfmlalbq_f32, arm_neon_bfmlalb, 0),
+ NEONMAP1(vbfmlaltq_f32, arm_neon_bfmlalt, 0),
+ NEONMAP1(vbfmmlaq_f32, arm_neon_bfmmla, 0),
NEONMAP1(vbsl_v, arm_neon_vbsl, AddRetType),
NEONMAP1(vbslq_v, arm_neon_vbsl, AddRetType),
- NEONMAP1(vcadd_rot270_v, arm_neon_vcadd_rot270, Add1ArgType),
- NEONMAP1(vcadd_rot90_v, arm_neon_vcadd_rot90, Add1ArgType),
- NEONMAP1(vcaddq_rot270_v, arm_neon_vcadd_rot270, Add1ArgType),
- NEONMAP1(vcaddq_rot90_v, arm_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcadd_rot270_f16, arm_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcadd_rot270_f32, arm_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcadd_rot90_f16, arm_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcadd_rot90_f32, arm_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcaddq_rot270_f16, arm_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcaddq_rot270_f32, arm_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcaddq_rot270_f64, arm_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcaddq_rot90_f16, arm_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcaddq_rot90_f32, arm_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcaddq_rot90_f64, arm_neon_vcadd_rot90, Add1ArgType),
NEONMAP1(vcage_v, arm_neon_vacge, 0),
NEONMAP1(vcageq_v, arm_neon_vacge, 0),
NEONMAP1(vcagt_v, arm_neon_vacgt, 0),
@@ -5682,90 +5737,96 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP1(vcnt_v, ctpop, Add1ArgType),
NEONMAP1(vcntq_v, ctpop, Add1ArgType),
NEONMAP1(vcvt_f16_f32, arm_neon_vcvtfp2hf, 0),
- NEONMAP0(vcvt_f16_v),
+ NEONMAP0(vcvt_f16_s16),
+ NEONMAP0(vcvt_f16_u16),
NEONMAP1(vcvt_f32_f16, arm_neon_vcvthf2fp, 0),
NEONMAP0(vcvt_f32_v),
- NEONMAP2(vcvt_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvt_n_f16_s16, arm_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvt_n_f16_u16, arm_neon_vcvtfxu2fp, 0),
NEONMAP2(vcvt_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
- NEONMAP1(vcvt_n_s16_v, arm_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvt_n_s16_f16, arm_neon_vcvtfp2fxs, 0),
NEONMAP1(vcvt_n_s32_v, arm_neon_vcvtfp2fxs, 0),
NEONMAP1(vcvt_n_s64_v, arm_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvt_n_u16_v, arm_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvt_n_u16_f16, arm_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvt_n_u32_v, arm_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvt_n_u64_v, arm_neon_vcvtfp2fxu, 0),
- NEONMAP0(vcvt_s16_v),
+ NEONMAP0(vcvt_s16_f16),
NEONMAP0(vcvt_s32_v),
NEONMAP0(vcvt_s64_v),
- NEONMAP0(vcvt_u16_v),
+ NEONMAP0(vcvt_u16_f16),
NEONMAP0(vcvt_u32_v),
NEONMAP0(vcvt_u64_v),
- NEONMAP1(vcvta_s16_v, arm_neon_vcvtas, 0),
+ NEONMAP1(vcvta_s16_f16, arm_neon_vcvtas, 0),
NEONMAP1(vcvta_s32_v, arm_neon_vcvtas, 0),
NEONMAP1(vcvta_s64_v, arm_neon_vcvtas, 0),
- NEONMAP1(vcvta_u16_v, arm_neon_vcvtau, 0),
+ NEONMAP1(vcvta_u16_f16, arm_neon_vcvtau, 0),
NEONMAP1(vcvta_u32_v, arm_neon_vcvtau, 0),
NEONMAP1(vcvta_u64_v, arm_neon_vcvtau, 0),
- NEONMAP1(vcvtaq_s16_v, arm_neon_vcvtas, 0),
+ NEONMAP1(vcvtaq_s16_f16, arm_neon_vcvtas, 0),
NEONMAP1(vcvtaq_s32_v, arm_neon_vcvtas, 0),
NEONMAP1(vcvtaq_s64_v, arm_neon_vcvtas, 0),
- NEONMAP1(vcvtaq_u16_v, arm_neon_vcvtau, 0),
+ NEONMAP1(vcvtaq_u16_f16, arm_neon_vcvtau, 0),
NEONMAP1(vcvtaq_u32_v, arm_neon_vcvtau, 0),
NEONMAP1(vcvtaq_u64_v, arm_neon_vcvtau, 0),
NEONMAP1(vcvth_bf16_f32, arm_neon_vcvtbfp2bf, 0),
- NEONMAP1(vcvtm_s16_v, arm_neon_vcvtms, 0),
+ NEONMAP1(vcvtm_s16_f16, arm_neon_vcvtms, 0),
NEONMAP1(vcvtm_s32_v, arm_neon_vcvtms, 0),
NEONMAP1(vcvtm_s64_v, arm_neon_vcvtms, 0),
- NEONMAP1(vcvtm_u16_v, arm_neon_vcvtmu, 0),
+ NEONMAP1(vcvtm_u16_f16, arm_neon_vcvtmu, 0),
NEONMAP1(vcvtm_u32_v, arm_neon_vcvtmu, 0),
NEONMAP1(vcvtm_u64_v, arm_neon_vcvtmu, 0),
- NEONMAP1(vcvtmq_s16_v, arm_neon_vcvtms, 0),
+ NEONMAP1(vcvtmq_s16_f16, arm_neon_vcvtms, 0),
NEONMAP1(vcvtmq_s32_v, arm_neon_vcvtms, 0),
NEONMAP1(vcvtmq_s64_v, arm_neon_vcvtms, 0),
- NEONMAP1(vcvtmq_u16_v, arm_neon_vcvtmu, 0),
+ NEONMAP1(vcvtmq_u16_f16, arm_neon_vcvtmu, 0),
NEONMAP1(vcvtmq_u32_v, arm_neon_vcvtmu, 0),
NEONMAP1(vcvtmq_u64_v, arm_neon_vcvtmu, 0),
- NEONMAP1(vcvtn_s16_v, arm_neon_vcvtns, 0),
+ NEONMAP1(vcvtn_s16_f16, arm_neon_vcvtns, 0),
NEONMAP1(vcvtn_s32_v, arm_neon_vcvtns, 0),
NEONMAP1(vcvtn_s64_v, arm_neon_vcvtns, 0),
- NEONMAP1(vcvtn_u16_v, arm_neon_vcvtnu, 0),
+ NEONMAP1(vcvtn_u16_f16, arm_neon_vcvtnu, 0),
NEONMAP1(vcvtn_u32_v, arm_neon_vcvtnu, 0),
NEONMAP1(vcvtn_u64_v, arm_neon_vcvtnu, 0),
- NEONMAP1(vcvtnq_s16_v, arm_neon_vcvtns, 0),
+ NEONMAP1(vcvtnq_s16_f16, arm_neon_vcvtns, 0),
NEONMAP1(vcvtnq_s32_v, arm_neon_vcvtns, 0),
NEONMAP1(vcvtnq_s64_v, arm_neon_vcvtns, 0),
- NEONMAP1(vcvtnq_u16_v, arm_neon_vcvtnu, 0),
+ NEONMAP1(vcvtnq_u16_f16, arm_neon_vcvtnu, 0),
NEONMAP1(vcvtnq_u32_v, arm_neon_vcvtnu, 0),
NEONMAP1(vcvtnq_u64_v, arm_neon_vcvtnu, 0),
- NEONMAP1(vcvtp_s16_v, arm_neon_vcvtps, 0),
+ NEONMAP1(vcvtp_s16_f16, arm_neon_vcvtps, 0),
NEONMAP1(vcvtp_s32_v, arm_neon_vcvtps, 0),
NEONMAP1(vcvtp_s64_v, arm_neon_vcvtps, 0),
- NEONMAP1(vcvtp_u16_v, arm_neon_vcvtpu, 0),
+ NEONMAP1(vcvtp_u16_f16, arm_neon_vcvtpu, 0),
NEONMAP1(vcvtp_u32_v, arm_neon_vcvtpu, 0),
NEONMAP1(vcvtp_u64_v, arm_neon_vcvtpu, 0),
- NEONMAP1(vcvtpq_s16_v, arm_neon_vcvtps, 0),
+ NEONMAP1(vcvtpq_s16_f16, arm_neon_vcvtps, 0),
NEONMAP1(vcvtpq_s32_v, arm_neon_vcvtps, 0),
NEONMAP1(vcvtpq_s64_v, arm_neon_vcvtps, 0),
- NEONMAP1(vcvtpq_u16_v, arm_neon_vcvtpu, 0),
+ NEONMAP1(vcvtpq_u16_f16, arm_neon_vcvtpu, 0),
NEONMAP1(vcvtpq_u32_v, arm_neon_vcvtpu, 0),
NEONMAP1(vcvtpq_u64_v, arm_neon_vcvtpu, 0),
- NEONMAP0(vcvtq_f16_v),
+ NEONMAP0(vcvtq_f16_s16),
+ NEONMAP0(vcvtq_f16_u16),
NEONMAP0(vcvtq_f32_v),
- NEONMAP2(vcvtq_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvtq_n_f16_s16, arm_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvtq_n_f16_u16, arm_neon_vcvtfxu2fp, 0),
NEONMAP2(vcvtq_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0),
- NEONMAP1(vcvtq_n_s16_v, arm_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvtq_n_s16_f16, arm_neon_vcvtfp2fxs, 0),
NEONMAP1(vcvtq_n_s32_v, arm_neon_vcvtfp2fxs, 0),
NEONMAP1(vcvtq_n_s64_v, arm_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvtq_n_u16_v, arm_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvtq_n_u16_f16, arm_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvtq_n_u32_v, arm_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvtq_n_u64_v, arm_neon_vcvtfp2fxu, 0),
- NEONMAP0(vcvtq_s16_v),
+ NEONMAP0(vcvtq_s16_f16),
NEONMAP0(vcvtq_s32_v),
NEONMAP0(vcvtq_s64_v),
- NEONMAP0(vcvtq_u16_v),
+ NEONMAP0(vcvtq_u16_f16),
NEONMAP0(vcvtq_u32_v),
NEONMAP0(vcvtq_u64_v),
- NEONMAP2(vdot_v, arm_neon_udot, arm_neon_sdot, 0),
- NEONMAP2(vdotq_v, arm_neon_udot, arm_neon_sdot, 0),
+ NEONMAP1(vdot_s32, arm_neon_sdot, 0),
+ NEONMAP1(vdot_u32, arm_neon_udot, 0),
+ NEONMAP1(vdotq_s32, arm_neon_sdot, 0),
+ NEONMAP1(vdotq_u32, arm_neon_udot, 0),
NEONMAP0(vext_v),
NEONMAP0(vextq_v),
NEONMAP0(vfma_v),
@@ -5810,7 +5871,8 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP1(vminnm_v, arm_neon_vminnm, Add1ArgType),
NEONMAP1(vminnmq_v, arm_neon_vminnm, Add1ArgType),
NEONMAP2(vminq_v, arm_neon_vminu, arm_neon_vmins, Add1ArgType | UnsignedAlts),
- NEONMAP2(vmmlaq_v, arm_neon_ummla, arm_neon_smmla, 0),
+ NEONMAP1(vmmlaq_s32, arm_neon_smmla, 0),
+ NEONMAP1(vmmlaq_u32, arm_neon_ummla, 0),
NEONMAP0(vmovl_v),
NEONMAP0(vmovn_v),
NEONMAP1(vmul_v, arm_neon_vmulp, Add1ArgType),
@@ -5837,10 +5899,14 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP1(vqmovun_v, arm_neon_vqmovnsu, Add1ArgType),
NEONMAP1(vqneg_v, arm_neon_vqneg, Add1ArgType),
NEONMAP1(vqnegq_v, arm_neon_vqneg, Add1ArgType),
- NEONMAP1(vqrdmlah_v, arm_neon_vqrdmlah, Add1ArgType),
- NEONMAP1(vqrdmlahq_v, arm_neon_vqrdmlah, Add1ArgType),
- NEONMAP1(vqrdmlsh_v, arm_neon_vqrdmlsh, Add1ArgType),
- NEONMAP1(vqrdmlshq_v, arm_neon_vqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlah_s16, arm_neon_vqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlah_s32, arm_neon_vqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlahq_s16, arm_neon_vqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlahq_s32, arm_neon_vqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlsh_s16, arm_neon_vqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlsh_s32, arm_neon_vqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlshq_s16, arm_neon_vqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlshq_s32, arm_neon_vqrdmlsh, Add1ArgType),
NEONMAP1(vqrdmulh_v, arm_neon_vqrdmulh, Add1ArgType),
NEONMAP1(vqrdmulhq_v, arm_neon_vqrdmulh, Add1ArgType),
NEONMAP2(vqrshl_v, arm_neon_vqrshiftu, arm_neon_vqrshifts, Add1ArgType | UnsignedAlts),
@@ -5883,12 +5949,12 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP1(vrsqrts_v, arm_neon_vrsqrts, Add1ArgType),
NEONMAP1(vrsqrtsq_v, arm_neon_vrsqrts, Add1ArgType),
NEONMAP1(vrsubhn_v, arm_neon_vrsubhn, Add1ArgType),
- NEONMAP1(vsha1su0q_v, arm_neon_sha1su0, 0),
- NEONMAP1(vsha1su1q_v, arm_neon_sha1su1, 0),
- NEONMAP1(vsha256h2q_v, arm_neon_sha256h2, 0),
- NEONMAP1(vsha256hq_v, arm_neon_sha256h, 0),
- NEONMAP1(vsha256su0q_v, arm_neon_sha256su0, 0),
- NEONMAP1(vsha256su1q_v, arm_neon_sha256su1, 0),
+ NEONMAP1(vsha1su0q_u32, arm_neon_sha1su0, 0),
+ NEONMAP1(vsha1su1q_u32, arm_neon_sha1su1, 0),
+ NEONMAP1(vsha256h2q_u32, arm_neon_sha256h2, 0),
+ NEONMAP1(vsha256hq_u32, arm_neon_sha256h, 0),
+ NEONMAP1(vsha256su0q_u32, arm_neon_sha256su0, 0),
+ NEONMAP1(vsha256su1q_u32, arm_neon_sha256su1, 0),
NEONMAP0(vshl_n_v),
NEONMAP2(vshl_v, arm_neon_vshiftu, arm_neon_vshifts, Add1ArgType | UnsignedAlts),
NEONMAP0(vshll_n_v),
@@ -5922,9 +5988,9 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
NEONMAP0(vtrnq_v),
NEONMAP0(vtst_v),
NEONMAP0(vtstq_v),
- NEONMAP1(vusdot_v, arm_neon_usdot, 0),
- NEONMAP1(vusdotq_v, arm_neon_usdot, 0),
- NEONMAP1(vusmmlaq_v, arm_neon_usmmla, 0),
+ NEONMAP1(vusdot_s32, arm_neon_usdot, 0),
+ NEONMAP1(vusdotq_s32, arm_neon_usdot, 0),
+ NEONMAP1(vusmmlaq_s32, arm_neon_usmmla, 0),
NEONMAP0(vuzp_v),
NEONMAP0(vuzpq_v),
NEONMAP0(vzip_v),
@@ -5932,7 +5998,7 @@ static const ARMVectorIntrinsicInfo ARMSIMDIntrinsicMap [] = {
};
static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
- NEONMAP1(__a64_vcvtq_low_bf16_v, aarch64_neon_bfcvtn, 0),
+ NEONMAP1(__a64_vcvtq_low_bf16_f32, aarch64_neon_bfcvtn, 0),
NEONMAP0(splat_lane_v),
NEONMAP0(splat_laneq_v),
NEONMAP0(splatq_lane_v),
@@ -5943,20 +6009,33 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP0(vaddhn_v),
NEONMAP0(vaddq_p128),
NEONMAP0(vaddq_v),
- NEONMAP1(vaesdq_v, aarch64_crypto_aesd, 0),
- NEONMAP1(vaeseq_v, aarch64_crypto_aese, 0),
- NEONMAP1(vaesimcq_v, aarch64_crypto_aesimc, 0),
- NEONMAP1(vaesmcq_v, aarch64_crypto_aesmc, 0),
- NEONMAP2(vbcaxq_v, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
- NEONMAP1(vbfdot_v, aarch64_neon_bfdot, 0),
- NEONMAP1(vbfdotq_v, aarch64_neon_bfdot, 0),
- NEONMAP1(vbfmlalbq_v, aarch64_neon_bfmlalb, 0),
- NEONMAP1(vbfmlaltq_v, aarch64_neon_bfmlalt, 0),
- NEONMAP1(vbfmmlaq_v, aarch64_neon_bfmmla, 0),
- NEONMAP1(vcadd_rot270_v, aarch64_neon_vcadd_rot270, Add1ArgType),
- NEONMAP1(vcadd_rot90_v, aarch64_neon_vcadd_rot90, Add1ArgType),
- NEONMAP1(vcaddq_rot270_v, aarch64_neon_vcadd_rot270, Add1ArgType),
- NEONMAP1(vcaddq_rot90_v, aarch64_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vaesdq_u8, aarch64_crypto_aesd, 0),
+ NEONMAP1(vaeseq_u8, aarch64_crypto_aese, 0),
+ NEONMAP1(vaesimcq_u8, aarch64_crypto_aesimc, 0),
+ NEONMAP1(vaesmcq_u8, aarch64_crypto_aesmc, 0),
+ NEONMAP2(vbcaxq_s16, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vbcaxq_s32, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vbcaxq_s64, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vbcaxq_s8, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vbcaxq_u16, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vbcaxq_u32, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vbcaxq_u64, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP2(vbcaxq_u8, aarch64_crypto_bcaxu, aarch64_crypto_bcaxs, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vbfdot_f32, aarch64_neon_bfdot, 0),
+ NEONMAP1(vbfdotq_f32, aarch64_neon_bfdot, 0),
+ NEONMAP1(vbfmlalbq_f32, aarch64_neon_bfmlalb, 0),
+ NEONMAP1(vbfmlaltq_f32, aarch64_neon_bfmlalt, 0),
+ NEONMAP1(vbfmmlaq_f32, aarch64_neon_bfmmla, 0),
+ NEONMAP1(vcadd_rot270_f16, aarch64_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcadd_rot270_f32, aarch64_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcadd_rot90_f16, aarch64_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcadd_rot90_f32, aarch64_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcaddq_rot270_f16, aarch64_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcaddq_rot270_f32, aarch64_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcaddq_rot270_f64, aarch64_neon_vcadd_rot270, Add1ArgType),
+ NEONMAP1(vcaddq_rot90_f16, aarch64_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcaddq_rot90_f32, aarch64_neon_vcadd_rot90, Add1ArgType),
+ NEONMAP1(vcaddq_rot90_f64, aarch64_neon_vcadd_rot90, Add1ArgType),
NEONMAP1(vcage_v, aarch64_neon_facge, 0),
NEONMAP1(vcageq_v, aarch64_neon_facge, 0),
NEONMAP1(vcagt_v, aarch64_neon_facgt, 0),
@@ -5979,57 +6058,82 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP0(vcltzq_v),
NEONMAP1(vclz_v, ctlz, Add1ArgType),
NEONMAP1(vclzq_v, ctlz, Add1ArgType),
- NEONMAP1(vcmla_rot180_v, aarch64_neon_vcmla_rot180, Add1ArgType),
- NEONMAP1(vcmla_rot270_v, aarch64_neon_vcmla_rot270, Add1ArgType),
- NEONMAP1(vcmla_rot90_v, aarch64_neon_vcmla_rot90, Add1ArgType),
- NEONMAP1(vcmla_v, aarch64_neon_vcmla_rot0, Add1ArgType),
- NEONMAP1(vcmlaq_rot180_v, aarch64_neon_vcmla_rot180, Add1ArgType),
- NEONMAP1(vcmlaq_rot270_v, aarch64_neon_vcmla_rot270, Add1ArgType),
- NEONMAP1(vcmlaq_rot90_v, aarch64_neon_vcmla_rot90, Add1ArgType),
- NEONMAP1(vcmlaq_v, aarch64_neon_vcmla_rot0, Add1ArgType),
+ NEONMAP1(vcmla_f16, aarch64_neon_vcmla_rot0, Add1ArgType),
+ NEONMAP1(vcmla_f32, aarch64_neon_vcmla_rot0, Add1ArgType),
+ NEONMAP1(vcmla_rot180_f16, aarch64_neon_vcmla_rot180, Add1ArgType),
+ NEONMAP1(vcmla_rot180_f32, aarch64_neon_vcmla_rot180, Add1ArgType),
+ NEONMAP1(vcmla_rot270_f16, aarch64_neon_vcmla_rot270, Add1ArgType),
+ NEONMAP1(vcmla_rot270_f32, aarch64_neon_vcmla_rot270, Add1ArgType),
+ NEONMAP1(vcmla_rot90_f16, aarch64_neon_vcmla_rot90, Add1ArgType),
+ NEONMAP1(vcmla_rot90_f32, aarch64_neon_vcmla_rot90, Add1ArgType),
+ NEONMAP1(vcmlaq_f16, aarch64_neon_vcmla_rot0, Add1ArgType),
+ NEONMAP1(vcmlaq_f32, aarch64_neon_vcmla_rot0, Add1ArgType),
+ NEONMAP1(vcmlaq_f64, aarch64_neon_vcmla_rot0, Add1ArgType),
+ NEONMAP1(vcmlaq_rot180_f16, aarch64_neon_vcmla_rot180, Add1ArgType),
+ NEONMAP1(vcmlaq_rot180_f32, aarch64_neon_vcmla_rot180, Add1ArgType),
+ NEONMAP1(vcmlaq_rot180_f64, aarch64_neon_vcmla_rot180, Add1ArgType),
+ NEONMAP1(vcmlaq_rot270_f16, aarch64_neon_vcmla_rot270, Add1ArgType),
+ NEONMAP1(vcmlaq_rot270_f32, aarch64_neon_vcmla_rot270, Add1ArgType),
+ NEONMAP1(vcmlaq_rot270_f64, aarch64_neon_vcmla_rot270, Add1ArgType),
+ NEONMAP1(vcmlaq_rot90_f16, aarch64_neon_vcmla_rot90, Add1ArgType),
+ NEONMAP1(vcmlaq_rot90_f32, aarch64_neon_vcmla_rot90, Add1ArgType),
+ NEONMAP1(vcmlaq_rot90_f64, aarch64_neon_vcmla_rot90, Add1ArgType),
NEONMAP1(vcnt_v, ctpop, Add1ArgType),
NEONMAP1(vcntq_v, ctpop, Add1ArgType),
NEONMAP1(vcvt_f16_f32, aarch64_neon_vcvtfp2hf, 0),
- NEONMAP0(vcvt_f16_v),
+ NEONMAP0(vcvt_f16_s16),
+ NEONMAP0(vcvt_f16_u16),
NEONMAP1(vcvt_f32_f16, aarch64_neon_vcvthf2fp, 0),
NEONMAP0(vcvt_f32_v),
- NEONMAP2(vcvt_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvt_n_f16_s16, aarch64_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvt_n_f16_u16, aarch64_neon_vcvtfxu2fp, 0),
NEONMAP2(vcvt_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
NEONMAP2(vcvt_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
- NEONMAP1(vcvt_n_s16_v, aarch64_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvt_n_s16_f16, aarch64_neon_vcvtfp2fxs, 0),
NEONMAP1(vcvt_n_s32_v, aarch64_neon_vcvtfp2fxs, 0),
NEONMAP1(vcvt_n_s64_v, aarch64_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvt_n_u16_v, aarch64_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvt_n_u16_f16, aarch64_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvt_n_u32_v, aarch64_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvt_n_u64_v, aarch64_neon_vcvtfp2fxu, 0),
- NEONMAP0(vcvtq_f16_v),
+ NEONMAP0(vcvtq_f16_s16),
+ NEONMAP0(vcvtq_f16_u16),
NEONMAP0(vcvtq_f32_v),
- NEONMAP1(vcvtq_high_bf16_v, aarch64_neon_bfcvtn2, 0),
- NEONMAP2(vcvtq_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvtq_high_bf16_f32, aarch64_neon_bfcvtn2, 0),
+ NEONMAP1(vcvtq_n_f16_s16, aarch64_neon_vcvtfxs2fp, 0),
+ NEONMAP1(vcvtq_n_f16_u16, aarch64_neon_vcvtfxu2fp, 0),
NEONMAP2(vcvtq_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
NEONMAP2(vcvtq_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0),
- NEONMAP1(vcvtq_n_s16_v, aarch64_neon_vcvtfp2fxs, 0),
+ NEONMAP1(vcvtq_n_s16_f16, aarch64_neon_vcvtfp2fxs, 0),
NEONMAP1(vcvtq_n_s32_v, aarch64_neon_vcvtfp2fxs, 0),
NEONMAP1(vcvtq_n_s64_v, aarch64_neon_vcvtfp2fxs, 0),
- NEONMAP1(vcvtq_n_u16_v, aarch64_neon_vcvtfp2fxu, 0),
+ NEONMAP1(vcvtq_n_u16_f16, aarch64_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvtq_n_u32_v, aarch64_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvtq_n_u64_v, aarch64_neon_vcvtfp2fxu, 0),
NEONMAP1(vcvtx_f32_v, aarch64_neon_fcvtxn, AddRetType | Add1ArgType),
- NEONMAP2(vdot_v, aarch64_neon_udot, aarch64_neon_sdot, 0),
- NEONMAP2(vdotq_v, aarch64_neon_udot, aarch64_neon_sdot, 0),
- NEONMAP2(veor3q_v, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
+ NEONMAP1(vdot_s32, aarch64_neon_sdot, 0),
+ NEONMAP1(vdot_u32, aarch64_neon_udot, 0),
+ NEONMAP1(vdotq_s32, aarch64_neon_sdot, 0),
+ NEONMAP1(vdotq_u32, aarch64_neon_udot, 0),
+ NEONMAP2(veor3q_s16, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
+ NEONMAP2(veor3q_s32, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
+ NEONMAP2(veor3q_s64, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
+ NEONMAP2(veor3q_s8, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
+ NEONMAP2(veor3q_u16, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
+ NEONMAP2(veor3q_u32, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
+ NEONMAP2(veor3q_u64, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
+ NEONMAP2(veor3q_u8, aarch64_crypto_eor3u, aarch64_crypto_eor3s, Add1ArgType | UnsignedAlts),
NEONMAP0(vext_v),
NEONMAP0(vextq_v),
NEONMAP0(vfma_v),
NEONMAP0(vfmaq_v),
- NEONMAP1(vfmlal_high_v, aarch64_neon_fmlal2, 0),
- NEONMAP1(vfmlal_low_v, aarch64_neon_fmlal, 0),
- NEONMAP1(vfmlalq_high_v, aarch64_neon_fmlal2, 0),
- NEONMAP1(vfmlalq_low_v, aarch64_neon_fmlal, 0),
- NEONMAP1(vfmlsl_high_v, aarch64_neon_fmlsl2, 0),
- NEONMAP1(vfmlsl_low_v, aarch64_neon_fmlsl, 0),
- NEONMAP1(vfmlslq_high_v, aarch64_neon_fmlsl2, 0),
- NEONMAP1(vfmlslq_low_v, aarch64_neon_fmlsl, 0),
+ NEONMAP1(vfmlal_high_f16, aarch64_neon_fmlal2, 0),
+ NEONMAP1(vfmlal_low_f16, aarch64_neon_fmlal, 0),
+ NEONMAP1(vfmlalq_high_f16, aarch64_neon_fmlal2, 0),
+ NEONMAP1(vfmlalq_low_f16, aarch64_neon_fmlal, 0),
+ NEONMAP1(vfmlsl_high_f16, aarch64_neon_fmlsl2, 0),
+ NEONMAP1(vfmlsl_low_f16, aarch64_neon_fmlsl, 0),
+ NEONMAP1(vfmlslq_high_f16, aarch64_neon_fmlsl2, 0),
+ NEONMAP1(vfmlslq_low_f16, aarch64_neon_fmlsl, 0),
NEONMAP2(vhadd_v, aarch64_neon_uhadd, aarch64_neon_shadd, Add1ArgType | UnsignedAlts),
NEONMAP2(vhaddq_v, aarch64_neon_uhadd, aarch64_neon_shadd, Add1ArgType | UnsignedAlts),
NEONMAP2(vhsub_v, aarch64_neon_uhsub, aarch64_neon_shsub, Add1ArgType | UnsignedAlts),
@@ -6040,7 +6144,8 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP1(vld1q_x2_v, aarch64_neon_ld1x2, 0),
NEONMAP1(vld1q_x3_v, aarch64_neon_ld1x3, 0),
NEONMAP1(vld1q_x4_v, aarch64_neon_ld1x4, 0),
- NEONMAP2(vmmlaq_v, aarch64_neon_ummla, aarch64_neon_smmla, 0),
+ NEONMAP1(vmmlaq_s32, aarch64_neon_smmla, 0),
+ NEONMAP1(vmmlaq_u32, aarch64_neon_ummla, 0),
NEONMAP0(vmovl_v),
NEONMAP0(vmovn_v),
NEONMAP1(vmul_v, aarch64_neon_pmul, Add1ArgType),
@@ -6066,10 +6171,14 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP1(vqmovun_v, aarch64_neon_sqxtun, Add1ArgType),
NEONMAP1(vqneg_v, aarch64_neon_sqneg, Add1ArgType),
NEONMAP1(vqnegq_v, aarch64_neon_sqneg, Add1ArgType),
- NEONMAP1(vqrdmlah_v, aarch64_neon_sqrdmlah, Add1ArgType),
- NEONMAP1(vqrdmlahq_v, aarch64_neon_sqrdmlah, Add1ArgType),
- NEONMAP1(vqrdmlsh_v, aarch64_neon_sqrdmlsh, Add1ArgType),
- NEONMAP1(vqrdmlshq_v, aarch64_neon_sqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlah_s16, aarch64_neon_sqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlah_s32, aarch64_neon_sqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlahq_s16, aarch64_neon_sqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlahq_s32, aarch64_neon_sqrdmlah, Add1ArgType),
+ NEONMAP1(vqrdmlsh_s16, aarch64_neon_sqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlsh_s32, aarch64_neon_sqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlshq_s16, aarch64_neon_sqrdmlsh, Add1ArgType),
+ NEONMAP1(vqrdmlshq_s32, aarch64_neon_sqrdmlsh, Add1ArgType),
NEONMAP1(vqrdmulh_lane_v, aarch64_neon_sqrdmulh_lane, 0),
NEONMAP1(vqrdmulh_laneq_v, aarch64_neon_sqrdmulh_laneq, 0),
NEONMAP1(vqrdmulh_v, aarch64_neon_sqrdmulh, Add1ArgType),
@@ -6087,21 +6196,21 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP2(vqsub_v, aarch64_neon_uqsub, aarch64_neon_sqsub, Add1ArgType | UnsignedAlts),
NEONMAP2(vqsubq_v, aarch64_neon_uqsub, aarch64_neon_sqsub, Add1ArgType | UnsignedAlts),
NEONMAP1(vraddhn_v, aarch64_neon_raddhn, Add1ArgType),
- NEONMAP1(vrax1q_v, aarch64_crypto_rax1, 0),
+ NEONMAP1(vrax1q_u64, aarch64_crypto_rax1, 0),
NEONMAP2(vrecpe_v, aarch64_neon_frecpe, aarch64_neon_urecpe, 0),
NEONMAP2(vrecpeq_v, aarch64_neon_frecpe, aarch64_neon_urecpe, 0),
NEONMAP1(vrecps_v, aarch64_neon_frecps, Add1ArgType),
NEONMAP1(vrecpsq_v, aarch64_neon_frecps, Add1ArgType),
NEONMAP2(vrhadd_v, aarch64_neon_urhadd, aarch64_neon_srhadd, Add1ArgType | UnsignedAlts),
NEONMAP2(vrhaddq_v, aarch64_neon_urhadd, aarch64_neon_srhadd, Add1ArgType | UnsignedAlts),
- NEONMAP1(vrnd32x_v, aarch64_neon_frint32x, Add1ArgType),
- NEONMAP1(vrnd32xq_v, aarch64_neon_frint32x, Add1ArgType),
- NEONMAP1(vrnd32z_v, aarch64_neon_frint32z, Add1ArgType),
- NEONMAP1(vrnd32zq_v, aarch64_neon_frint32z, Add1ArgType),
- NEONMAP1(vrnd64x_v, aarch64_neon_frint64x, Add1ArgType),
- NEONMAP1(vrnd64xq_v, aarch64_neon_frint64x, Add1ArgType),
- NEONMAP1(vrnd64z_v, aarch64_neon_frint64z, Add1ArgType),
- NEONMAP1(vrnd64zq_v, aarch64_neon_frint64z, Add1ArgType),
+ NEONMAP1(vrnd32x_f32, aarch64_neon_frint32x, Add1ArgType),
+ NEONMAP1(vrnd32xq_f32, aarch64_neon_frint32x, Add1ArgType),
+ NEONMAP1(vrnd32z_f32, aarch64_neon_frint32z, Add1ArgType),
+ NEONMAP1(vrnd32zq_f32, aarch64_neon_frint32z, Add1ArgType),
+ NEONMAP1(vrnd64x_f32, aarch64_neon_frint64x, Add1ArgType),
+ NEONMAP1(vrnd64xq_f32, aarch64_neon_frint64x, Add1ArgType),
+ NEONMAP1(vrnd64z_f32, aarch64_neon_frint64z, Add1ArgType),
+ NEONMAP1(vrnd64zq_f32, aarch64_neon_frint64z, Add1ArgType),
NEONMAP0(vrndi_v),
NEONMAP0(vrndiq_v),
NEONMAP2(vrshl_v, aarch64_neon_urshl, aarch64_neon_srshl, Add1ArgType | UnsignedAlts),
@@ -6113,16 +6222,16 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP1(vrsqrts_v, aarch64_neon_frsqrts, Add1ArgType),
NEONMAP1(vrsqrtsq_v, aarch64_neon_frsqrts, Add1ArgType),
NEONMAP1(vrsubhn_v, aarch64_neon_rsubhn, Add1ArgType),
- NEONMAP1(vsha1su0q_v, aarch64_crypto_sha1su0, 0),
- NEONMAP1(vsha1su1q_v, aarch64_crypto_sha1su1, 0),
- NEONMAP1(vsha256h2q_v, aarch64_crypto_sha256h2, 0),
- NEONMAP1(vsha256hq_v, aarch64_crypto_sha256h, 0),
- NEONMAP1(vsha256su0q_v, aarch64_crypto_sha256su0, 0),
- NEONMAP1(vsha256su1q_v, aarch64_crypto_sha256su1, 0),
- NEONMAP1(vsha512h2q_v, aarch64_crypto_sha512h2, 0),
- NEONMAP1(vsha512hq_v, aarch64_crypto_sha512h, 0),
- NEONMAP1(vsha512su0q_v, aarch64_crypto_sha512su0, 0),
- NEONMAP1(vsha512su1q_v, aarch64_crypto_sha512su1, 0),
+ NEONMAP1(vsha1su0q_u32, aarch64_crypto_sha1su0, 0),
+ NEONMAP1(vsha1su1q_u32, aarch64_crypto_sha1su1, 0),
+ NEONMAP1(vsha256h2q_u32, aarch64_crypto_sha256h2, 0),
+ NEONMAP1(vsha256hq_u32, aarch64_crypto_sha256h, 0),
+ NEONMAP1(vsha256su0q_u32, aarch64_crypto_sha256su0, 0),
+ NEONMAP1(vsha256su1q_u32, aarch64_crypto_sha256su1, 0),
+ NEONMAP1(vsha512h2q_u64, aarch64_crypto_sha512h2, 0),
+ NEONMAP1(vsha512hq_u64, aarch64_crypto_sha512h, 0),
+ NEONMAP1(vsha512su0q_u64, aarch64_crypto_sha512su0, 0),
+ NEONMAP1(vsha512su1q_u64, aarch64_crypto_sha512su1, 0),
NEONMAP0(vshl_n_v),
NEONMAP2(vshl_v, aarch64_neon_ushl, aarch64_neon_sshl, Add1ArgType | UnsignedAlts),
NEONMAP0(vshll_n_v),
@@ -6131,15 +6240,15 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP0(vshr_n_v),
NEONMAP0(vshrn_n_v),
NEONMAP0(vshrq_n_v),
- NEONMAP1(vsm3partw1q_v, aarch64_crypto_sm3partw1, 0),
- NEONMAP1(vsm3partw2q_v, aarch64_crypto_sm3partw2, 0),
- NEONMAP1(vsm3ss1q_v, aarch64_crypto_sm3ss1, 0),
- NEONMAP1(vsm3tt1aq_v, aarch64_crypto_sm3tt1a, 0),
- NEONMAP1(vsm3tt1bq_v, aarch64_crypto_sm3tt1b, 0),
- NEONMAP1(vsm3tt2aq_v, aarch64_crypto_sm3tt2a, 0),
- NEONMAP1(vsm3tt2bq_v, aarch64_crypto_sm3tt2b, 0),
- NEONMAP1(vsm4ekeyq_v, aarch64_crypto_sm4ekey, 0),
- NEONMAP1(vsm4eq_v, aarch64_crypto_sm4e, 0),
+ NEONMAP1(vsm3partw1q_u32, aarch64_crypto_sm3partw1, 0),
+ NEONMAP1(vsm3partw2q_u32, aarch64_crypto_sm3partw2, 0),
+ NEONMAP1(vsm3ss1q_u32, aarch64_crypto_sm3ss1, 0),
+ NEONMAP1(vsm3tt1aq_u32, aarch64_crypto_sm3tt1a, 0),
+ NEONMAP1(vsm3tt1bq_u32, aarch64_crypto_sm3tt1b, 0),
+ NEONMAP1(vsm3tt2aq_u32, aarch64_crypto_sm3tt2a, 0),
+ NEONMAP1(vsm3tt2bq_u32, aarch64_crypto_sm3tt2b, 0),
+ NEONMAP1(vsm4ekeyq_u32, aarch64_crypto_sm4ekey, 0),
+ NEONMAP1(vsm4eq_u32, aarch64_crypto_sm4e, 0),
NEONMAP1(vst1_x2_v, aarch64_neon_st1x2, 0),
NEONMAP1(vst1_x3_v, aarch64_neon_st1x3, 0),
NEONMAP1(vst1_x4_v, aarch64_neon_st1x4, 0),
@@ -6149,10 +6258,10 @@ static const ARMVectorIntrinsicInfo AArch64SIMDIntrinsicMap[] = {
NEONMAP0(vsubhn_v),
NEONMAP0(vtst_v),
NEONMAP0(vtstq_v),
- NEONMAP1(vusdot_v, aarch64_neon_usdot, 0),
- NEONMAP1(vusdotq_v, aarch64_neon_usdot, 0),
- NEONMAP1(vusmmlaq_v, aarch64_neon_usmmla, 0),
- NEONMAP1(vxarq_v, aarch64_crypto_xar, 0),
+ NEONMAP1(vusdot_s32, aarch64_neon_usdot, 0),
+ NEONMAP1(vusdotq_s32, aarch64_neon_usdot, 0),
+ NEONMAP1(vusmmlaq_s32, aarch64_neon_usmmla, 0),
+ NEONMAP1(vxarq_u64, aarch64_crypto_xar, 0),
};
static const ARMVectorIntrinsicInfo AArch64SISDIntrinsicMap[] = {
@@ -6394,6 +6503,148 @@ static const ARMVectorIntrinsicInfo AArch64SISDIntrinsicMap[] = {
NEONMAP1(vrsqrtsh_f16, aarch64_neon_frsqrts, Add1ArgType),
};
+// Some intrinsics are equivalent for codegen.
+static const std::pair<unsigned, unsigned> NEONEquivalentIntrinsicMap[] = {
+ { NEON::BI__builtin_neon_splat_lane_bf16, NEON::BI__builtin_neon_splat_lane_v, },
+ { NEON::BI__builtin_neon_splat_laneq_bf16, NEON::BI__builtin_neon_splat_laneq_v, },
+ { NEON::BI__builtin_neon_splatq_lane_bf16, NEON::BI__builtin_neon_splatq_lane_v, },
+ { NEON::BI__builtin_neon_splatq_laneq_bf16, NEON::BI__builtin_neon_splatq_laneq_v, },
+ { NEON::BI__builtin_neon_vabd_f16, NEON::BI__builtin_neon_vabd_v, },
+ { NEON::BI__builtin_neon_vabdq_f16, NEON::BI__builtin_neon_vabdq_v, },
+ { NEON::BI__builtin_neon_vabs_f16, NEON::BI__builtin_neon_vabs_v, },
+ { NEON::BI__builtin_neon_vabsq_f16, NEON::BI__builtin_neon_vabsq_v, },
+ { NEON::BI__builtin_neon_vbsl_f16, NEON::BI__builtin_neon_vbsl_v, },
+ { NEON::BI__builtin_neon_vbslq_f16, NEON::BI__builtin_neon_vbslq_v, },
+ { NEON::BI__builtin_neon_vcage_f16, NEON::BI__builtin_neon_vcage_v, },
+ { NEON::BI__builtin_neon_vcageq_f16, NEON::BI__builtin_neon_vcageq_v, },
+ { NEON::BI__builtin_neon_vcagt_f16, NEON::BI__builtin_neon_vcagt_v, },
+ { NEON::BI__builtin_neon_vcagtq_f16, NEON::BI__builtin_neon_vcagtq_v, },
+ { NEON::BI__builtin_neon_vcale_f16, NEON::BI__builtin_neon_vcale_v, },
+ { NEON::BI__builtin_neon_vcaleq_f16, NEON::BI__builtin_neon_vcaleq_v, },
+ { NEON::BI__builtin_neon_vcalt_f16, NEON::BI__builtin_neon_vcalt_v, },
+ { NEON::BI__builtin_neon_vcaltq_f16, NEON::BI__builtin_neon_vcaltq_v, },
+ { NEON::BI__builtin_neon_vceqz_f16, NEON::BI__builtin_neon_vceqz_v, },
+ { NEON::BI__builtin_neon_vceqzq_f16, NEON::BI__builtin_neon_vceqzq_v, },
+ { NEON::BI__builtin_neon_vcgez_f16, NEON::BI__builtin_neon_vcgez_v, },
+ { NEON::BI__builtin_neon_vcgezq_f16, NEON::BI__builtin_neon_vcgezq_v, },
+ { NEON::BI__builtin_neon_vcgtz_f16, NEON::BI__builtin_neon_vcgtz_v, },
+ { NEON::BI__builtin_neon_vcgtzq_f16, NEON::BI__builtin_neon_vcgtzq_v, },
+ { NEON::BI__builtin_neon_vclez_f16, NEON::BI__builtin_neon_vclez_v, },
+ { NEON::BI__builtin_neon_vclezq_f16, NEON::BI__builtin_neon_vclezq_v, },
+ { NEON::BI__builtin_neon_vcltz_f16, NEON::BI__builtin_neon_vcltz_v, },
+ { NEON::BI__builtin_neon_vcltzq_f16, NEON::BI__builtin_neon_vcltzq_v, },
+ { NEON::BI__builtin_neon_vext_f16, NEON::BI__builtin_neon_vext_v, },
+ { NEON::BI__builtin_neon_vextq_f16, NEON::BI__builtin_neon_vextq_v, },
+ { NEON::BI__builtin_neon_vfma_f16, NEON::BI__builtin_neon_vfma_v, },
+ { NEON::BI__builtin_neon_vfma_lane_f16, NEON::BI__builtin_neon_vfma_lane_v, },
+ { NEON::BI__builtin_neon_vfma_laneq_f16, NEON::BI__builtin_neon_vfma_laneq_v, },
+ { NEON::BI__builtin_neon_vfmaq_f16, NEON::BI__builtin_neon_vfmaq_v, },
+ { NEON::BI__builtin_neon_vfmaq_lane_f16, NEON::BI__builtin_neon_vfmaq_lane_v, },
+ { NEON::BI__builtin_neon_vfmaq_laneq_f16, NEON::BI__builtin_neon_vfmaq_laneq_v, },
+ { NEON::BI__builtin_neon_vld1_bf16_x2, NEON::BI__builtin_neon_vld1_x2_v },
+ { NEON::BI__builtin_neon_vld1_bf16_x3, NEON::BI__builtin_neon_vld1_x3_v },
+ { NEON::BI__builtin_neon_vld1_bf16_x4, NEON::BI__builtin_neon_vld1_x4_v },
+ { NEON::BI__builtin_neon_vld1_bf16, NEON::BI__builtin_neon_vld1_v },
+ { NEON::BI__builtin_neon_vld1_dup_bf16, NEON::BI__builtin_neon_vld1_dup_v },
+ { NEON::BI__builtin_neon_vld1_lane_bf16, NEON::BI__builtin_neon_vld1_lane_v },
+ { NEON::BI__builtin_neon_vld1q_bf16_x2, NEON::BI__builtin_neon_vld1q_x2_v },
+ { NEON::BI__builtin_neon_vld1q_bf16_x3, NEON::BI__builtin_neon_vld1q_x3_v },
+ { NEON::BI__builtin_neon_vld1q_bf16_x4, NEON::BI__builtin_neon_vld1q_x4_v },
+ { NEON::BI__builtin_neon_vld1q_bf16, NEON::BI__builtin_neon_vld1q_v },
+ { NEON::BI__builtin_neon_vld1q_dup_bf16, NEON::BI__builtin_neon_vld1q_dup_v },
+ { NEON::BI__builtin_neon_vld1q_lane_bf16, NEON::BI__builtin_neon_vld1q_lane_v },
+ { NEON::BI__builtin_neon_vld2_bf16, NEON::BI__builtin_neon_vld2_v },
+ { NEON::BI__builtin_neon_vld2_dup_bf16, NEON::BI__builtin_neon_vld2_dup_v },
+ { NEON::BI__builtin_neon_vld2_lane_bf16, NEON::BI__builtin_neon_vld2_lane_v },
+ { NEON::BI__builtin_neon_vld2q_bf16, NEON::BI__builtin_neon_vld2q_v },
+ { NEON::BI__builtin_neon_vld2q_dup_bf16, NEON::BI__builtin_neon_vld2q_dup_v },
+ { NEON::BI__builtin_neon_vld2q_lane_bf16, NEON::BI__builtin_neon_vld2q_lane_v },
+ { NEON::BI__builtin_neon_vld3_bf16, NEON::BI__builtin_neon_vld3_v },
+ { NEON::BI__builtin_neon_vld3_dup_bf16, NEON::BI__builtin_neon_vld3_dup_v },
+ { NEON::BI__builtin_neon_vld3_lane_bf16, NEON::BI__builtin_neon_vld3_lane_v },
+ { NEON::BI__builtin_neon_vld3q_bf16, NEON::BI__builtin_neon_vld3q_v },
+ { NEON::BI__builtin_neon_vld3q_dup_bf16, NEON::BI__builtin_neon_vld3q_dup_v },
+ { NEON::BI__builtin_neon_vld3q_lane_bf16, NEON::BI__builtin_neon_vld3q_lane_v },
+ { NEON::BI__builtin_neon_vld4_bf16, NEON::BI__builtin_neon_vld4_v },
+ { NEON::BI__builtin_neon_vld4_dup_bf16, NEON::BI__builtin_neon_vld4_dup_v },
+ { NEON::BI__builtin_neon_vld4_lane_bf16, NEON::BI__builtin_neon_vld4_lane_v },
+ { NEON::BI__builtin_neon_vld4q_bf16, NEON::BI__builtin_neon_vld4q_v },
+ { NEON::BI__builtin_neon_vld4q_dup_bf16, NEON::BI__builtin_neon_vld4q_dup_v },
+ { NEON::BI__builtin_neon_vld4q_lane_bf16, NEON::BI__builtin_neon_vld4q_lane_v },
+ { NEON::BI__builtin_neon_vmax_f16, NEON::BI__builtin_neon_vmax_v, },
+ { NEON::BI__builtin_neon_vmaxnm_f16, NEON::BI__builtin_neon_vmaxnm_v, },
+ { NEON::BI__builtin_neon_vmaxnmq_f16, NEON::BI__builtin_neon_vmaxnmq_v, },
+ { NEON::BI__builtin_neon_vmaxq_f16, NEON::BI__builtin_neon_vmaxq_v, },
+ { NEON::BI__builtin_neon_vmin_f16, NEON::BI__builtin_neon_vmin_v, },
+ { NEON::BI__builtin_neon_vminnm_f16, NEON::BI__builtin_neon_vminnm_v, },
+ { NEON::BI__builtin_neon_vminnmq_f16, NEON::BI__builtin_neon_vminnmq_v, },
+ { NEON::BI__builtin_neon_vminq_f16, NEON::BI__builtin_neon_vminq_v, },
+ { NEON::BI__builtin_neon_vmulx_f16, NEON::BI__builtin_neon_vmulx_v, },
+ { NEON::BI__builtin_neon_vmulxq_f16, NEON::BI__builtin_neon_vmulxq_v, },
+ { NEON::BI__builtin_neon_vpadd_f16, NEON::BI__builtin_neon_vpadd_v, },
+ { NEON::BI__builtin_neon_vpaddq_f16, NEON::BI__builtin_neon_vpaddq_v, },
+ { NEON::BI__builtin_neon_vpmax_f16, NEON::BI__builtin_neon_vpmax_v, },
+ { NEON::BI__builtin_neon_vpmaxnm_f16, NEON::BI__builtin_neon_vpmaxnm_v, },
+ { NEON::BI__builtin_neon_vpmaxnmq_f16, NEON::BI__builtin_neon_vpmaxnmq_v, },
+ { NEON::BI__builtin_neon_vpmaxq_f16, NEON::BI__builtin_neon_vpmaxq_v, },
+ { NEON::BI__builtin_neon_vpmin_f16, NEON::BI__builtin_neon_vpmin_v, },
+ { NEON::BI__builtin_neon_vpminnm_f16, NEON::BI__builtin_neon_vpminnm_v, },
+ { NEON::BI__builtin_neon_vpminnmq_f16, NEON::BI__builtin_neon_vpminnmq_v, },
+ { NEON::BI__builtin_neon_vpminq_f16, NEON::BI__builtin_neon_vpminq_v, },
+ { NEON::BI__builtin_neon_vrecpe_f16, NEON::BI__builtin_neon_vrecpe_v, },
+ { NEON::BI__builtin_neon_vrecpeq_f16, NEON::BI__builtin_neon_vrecpeq_v, },
+ { NEON::BI__builtin_neon_vrecps_f16, NEON::BI__builtin_neon_vrecps_v, },
+ { NEON::BI__builtin_neon_vrecpsq_f16, NEON::BI__builtin_neon_vrecpsq_v, },
+ { NEON::BI__builtin_neon_vrnd_f16, NEON::BI__builtin_neon_vrnd_v, },
+ { NEON::BI__builtin_neon_vrnda_f16, NEON::BI__builtin_neon_vrnda_v, },
+ { NEON::BI__builtin_neon_vrndaq_f16, NEON::BI__builtin_neon_vrndaq_v, },
+ { NEON::BI__builtin_neon_vrndi_f16, NEON::BI__builtin_neon_vrndi_v, },
+ { NEON::BI__builtin_neon_vrndiq_f16, NEON::BI__builtin_neon_vrndiq_v, },
+ { NEON::BI__builtin_neon_vrndm_f16, NEON::BI__builtin_neon_vrndm_v, },
+ { NEON::BI__builtin_neon_vrndmq_f16, NEON::BI__builtin_neon_vrndmq_v, },
+ { NEON::BI__builtin_neon_vrndn_f16, NEON::BI__builtin_neon_vrndn_v, },
+ { NEON::BI__builtin_neon_vrndnq_f16, NEON::BI__builtin_neon_vrndnq_v, },
+ { NEON::BI__builtin_neon_vrndp_f16, NEON::BI__builtin_neon_vrndp_v, },
+ { NEON::BI__builtin_neon_vrndpq_f16, NEON::BI__builtin_neon_vrndpq_v, },
+ { NEON::BI__builtin_neon_vrndq_f16, NEON::BI__builtin_neon_vrndq_v, },
+ { NEON::BI__builtin_neon_vrndx_f16, NEON::BI__builtin_neon_vrndx_v, },
+ { NEON::BI__builtin_neon_vrndxq_f16, NEON::BI__builtin_neon_vrndxq_v, },
+ { NEON::BI__builtin_neon_vrsqrte_f16, NEON::BI__builtin_neon_vrsqrte_v, },
+ { NEON::BI__builtin_neon_vrsqrteq_f16, NEON::BI__builtin_neon_vrsqrteq_v, },
+ { NEON::BI__builtin_neon_vrsqrts_f16, NEON::BI__builtin_neon_vrsqrts_v, },
+ { NEON::BI__builtin_neon_vrsqrtsq_f16, NEON::BI__builtin_neon_vrsqrtsq_v, },
+ { NEON::BI__builtin_neon_vsqrt_f16, NEON::BI__builtin_neon_vsqrt_v, },
+ { NEON::BI__builtin_neon_vsqrtq_f16, NEON::BI__builtin_neon_vsqrtq_v, },
+ { NEON::BI__builtin_neon_vst1_bf16_x2, NEON::BI__builtin_neon_vst1_x2_v },
+ { NEON::BI__builtin_neon_vst1_bf16_x3, NEON::BI__builtin_neon_vst1_x3_v },
+ { NEON::BI__builtin_neon_vst1_bf16_x4, NEON::BI__builtin_neon_vst1_x4_v },
+ { NEON::BI__builtin_neon_vst1_bf16, NEON::BI__builtin_neon_vst1_v },
+ { NEON::BI__builtin_neon_vst1_lane_bf16, NEON::BI__builtin_neon_vst1_lane_v },
+ { NEON::BI__builtin_neon_vst1q_bf16_x2, NEON::BI__builtin_neon_vst1q_x2_v },
+ { NEON::BI__builtin_neon_vst1q_bf16_x3, NEON::BI__builtin_neon_vst1q_x3_v },
+ { NEON::BI__builtin_neon_vst1q_bf16_x4, NEON::BI__builtin_neon_vst1q_x4_v },
+ { NEON::BI__builtin_neon_vst1q_bf16, NEON::BI__builtin_neon_vst1q_v },
+ { NEON::BI__builtin_neon_vst1q_lane_bf16, NEON::BI__builtin_neon_vst1q_lane_v },
+ { NEON::BI__builtin_neon_vst2_bf16, NEON::BI__builtin_neon_vst2_v },
+ { NEON::BI__builtin_neon_vst2_lane_bf16, NEON::BI__builtin_neon_vst2_lane_v },
+ { NEON::BI__builtin_neon_vst2q_bf16, NEON::BI__builtin_neon_vst2q_v },
+ { NEON::BI__builtin_neon_vst2q_lane_bf16, NEON::BI__builtin_neon_vst2q_lane_v },
+ { NEON::BI__builtin_neon_vst3_bf16, NEON::BI__builtin_neon_vst3_v },
+ { NEON::BI__builtin_neon_vst3_lane_bf16, NEON::BI__builtin_neon_vst3_lane_v },
+ { NEON::BI__builtin_neon_vst3q_bf16, NEON::BI__builtin_neon_vst3q_v },
+ { NEON::BI__builtin_neon_vst3q_lane_bf16, NEON::BI__builtin_neon_vst3q_lane_v },
+ { NEON::BI__builtin_neon_vst4_bf16, NEON::BI__builtin_neon_vst4_v },
+ { NEON::BI__builtin_neon_vst4_lane_bf16, NEON::BI__builtin_neon_vst4_lane_v },
+ { NEON::BI__builtin_neon_vst4q_bf16, NEON::BI__builtin_neon_vst4q_v },
+ { NEON::BI__builtin_neon_vst4q_lane_bf16, NEON::BI__builtin_neon_vst4q_lane_v },
+ { NEON::BI__builtin_neon_vtrn_f16, NEON::BI__builtin_neon_vtrn_v, },
+ { NEON::BI__builtin_neon_vtrnq_f16, NEON::BI__builtin_neon_vtrnq_v, },
+ { NEON::BI__builtin_neon_vuzp_f16, NEON::BI__builtin_neon_vuzp_v, },
+ { NEON::BI__builtin_neon_vuzpq_f16, NEON::BI__builtin_neon_vuzpq_v, },
+ { NEON::BI__builtin_neon_vzip_f16, NEON::BI__builtin_neon_vzip_v, },
+ { NEON::BI__builtin_neon_vzipq_f16, NEON::BI__builtin_neon_vzipq_v, },
+};
+
#undef NEONMAP0
#undef NEONMAP1
#undef NEONMAP2
@@ -6531,13 +6782,13 @@ static Value *EmitCommonNeonSISDBuiltinExpr(
Ops[j] = CGF.Builder.CreateTruncOrBitCast(
Ops[j], cast<llvm::VectorType>(ArgTy)->getElementType());
Ops[j] =
- CGF.Builder.CreateInsertElement(UndefValue::get(ArgTy), Ops[j], C0);
+ CGF.Builder.CreateInsertElement(PoisonValue::get(ArgTy), Ops[j], C0);
}
Value *Result = CGF.EmitNeonCall(F, Ops, s);
llvm::Type *ResultType = CGF.ConvertType(E->getType());
- if (ResultType->getPrimitiveSizeInBits().getFixedSize() <
- Result->getType()->getPrimitiveSizeInBits().getFixedSize())
+ if (ResultType->getPrimitiveSizeInBits().getFixedValue() <
+ Result->getType()->getPrimitiveSizeInBits().getFixedValue())
return CGF.Builder.CreateExtractElement(Result, C0);
return CGF.Builder.CreateBitCast(Result, ResultType, s);
@@ -6550,7 +6801,7 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
llvm::Triple::ArchType Arch) {
// Get the last argument, which specifies the vector type.
const Expr *Arg = E->getArg(E->getNumArgs() - 1);
- Optional<llvm::APSInt> NeonTypeConst =
+ std::optional<llvm::APSInt> NeonTypeConst =
Arg->getIntegerConstantExpr(getContext());
if (!NeonTypeConst)
return nullptr;
@@ -6634,7 +6885,7 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
case NEON::BI__builtin_neon_vcalt_v:
case NEON::BI__builtin_neon_vcaltq_v:
std::swap(Ops[0], Ops[1]);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vcage_v:
case NEON::BI__builtin_neon_vcageq_v:
case NEON::BI__builtin_neon_vcagt_v:
@@ -6690,17 +6941,25 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
HasLegalHalfType);
return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
: Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
- case NEON::BI__builtin_neon_vcvt_f16_v:
- case NEON::BI__builtin_neon_vcvtq_f16_v:
+ case NEON::BI__builtin_neon_vcvt_f16_s16:
+ case NEON::BI__builtin_neon_vcvt_f16_u16:
+ case NEON::BI__builtin_neon_vcvtq_f16_s16:
+ case NEON::BI__builtin_neon_vcvtq_f16_u16:
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float16, false, Quad),
HasLegalHalfType);
return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt")
: Builder.CreateSIToFP(Ops[0], Ty, "vcvt");
- case NEON::BI__builtin_neon_vcvt_n_f16_v:
+ case NEON::BI__builtin_neon_vcvt_n_f16_s16:
+ case NEON::BI__builtin_neon_vcvt_n_f16_u16:
+ case NEON::BI__builtin_neon_vcvtq_n_f16_s16:
+ case NEON::BI__builtin_neon_vcvtq_n_f16_u16: {
+ llvm::Type *Tys[2] = { GetFloatNeonType(this, Type), Ty };
+ Function *F = CGM.getIntrinsic(Int, Tys);
+ return EmitNeonCall(F, Ops, "vcvt_n");
+ }
case NEON::BI__builtin_neon_vcvt_n_f32_v:
case NEON::BI__builtin_neon_vcvt_n_f64_v:
- case NEON::BI__builtin_neon_vcvtq_n_f16_v:
case NEON::BI__builtin_neon_vcvtq_n_f32_v:
case NEON::BI__builtin_neon_vcvtq_n_f64_v: {
llvm::Type *Tys[2] = { GetFloatNeonType(this, Type), Ty };
@@ -6708,15 +6967,15 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
Function *F = CGM.getIntrinsic(Int, Tys);
return EmitNeonCall(F, Ops, "vcvt_n");
}
- case NEON::BI__builtin_neon_vcvt_n_s16_v:
+ case NEON::BI__builtin_neon_vcvt_n_s16_f16:
case NEON::BI__builtin_neon_vcvt_n_s32_v:
- case NEON::BI__builtin_neon_vcvt_n_u16_v:
+ case NEON::BI__builtin_neon_vcvt_n_u16_f16:
case NEON::BI__builtin_neon_vcvt_n_u32_v:
case NEON::BI__builtin_neon_vcvt_n_s64_v:
case NEON::BI__builtin_neon_vcvt_n_u64_v:
- case NEON::BI__builtin_neon_vcvtq_n_s16_v:
+ case NEON::BI__builtin_neon_vcvtq_n_s16_f16:
case NEON::BI__builtin_neon_vcvtq_n_s32_v:
- case NEON::BI__builtin_neon_vcvtq_n_u16_v:
+ case NEON::BI__builtin_neon_vcvtq_n_u16_f16:
case NEON::BI__builtin_neon_vcvtq_n_u32_v:
case NEON::BI__builtin_neon_vcvtq_n_s64_v:
case NEON::BI__builtin_neon_vcvtq_n_u64_v: {
@@ -6728,64 +6987,64 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
case NEON::BI__builtin_neon_vcvt_u32_v:
case NEON::BI__builtin_neon_vcvt_s64_v:
case NEON::BI__builtin_neon_vcvt_u64_v:
- case NEON::BI__builtin_neon_vcvt_s16_v:
- case NEON::BI__builtin_neon_vcvt_u16_v:
+ case NEON::BI__builtin_neon_vcvt_s16_f16:
+ case NEON::BI__builtin_neon_vcvt_u16_f16:
case NEON::BI__builtin_neon_vcvtq_s32_v:
case NEON::BI__builtin_neon_vcvtq_u32_v:
case NEON::BI__builtin_neon_vcvtq_s64_v:
case NEON::BI__builtin_neon_vcvtq_u64_v:
- case NEON::BI__builtin_neon_vcvtq_s16_v:
- case NEON::BI__builtin_neon_vcvtq_u16_v: {
+ case NEON::BI__builtin_neon_vcvtq_s16_f16:
+ case NEON::BI__builtin_neon_vcvtq_u16_f16: {
Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type));
return Usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt")
: Builder.CreateFPToSI(Ops[0], Ty, "vcvt");
}
- case NEON::BI__builtin_neon_vcvta_s16_v:
+ case NEON::BI__builtin_neon_vcvta_s16_f16:
case NEON::BI__builtin_neon_vcvta_s32_v:
case NEON::BI__builtin_neon_vcvta_s64_v:
- case NEON::BI__builtin_neon_vcvta_u16_v:
+ case NEON::BI__builtin_neon_vcvta_u16_f16:
case NEON::BI__builtin_neon_vcvta_u32_v:
case NEON::BI__builtin_neon_vcvta_u64_v:
- case NEON::BI__builtin_neon_vcvtaq_s16_v:
+ case NEON::BI__builtin_neon_vcvtaq_s16_f16:
case NEON::BI__builtin_neon_vcvtaq_s32_v:
case NEON::BI__builtin_neon_vcvtaq_s64_v:
- case NEON::BI__builtin_neon_vcvtaq_u16_v:
+ case NEON::BI__builtin_neon_vcvtaq_u16_f16:
case NEON::BI__builtin_neon_vcvtaq_u32_v:
case NEON::BI__builtin_neon_vcvtaq_u64_v:
- case NEON::BI__builtin_neon_vcvtn_s16_v:
+ case NEON::BI__builtin_neon_vcvtn_s16_f16:
case NEON::BI__builtin_neon_vcvtn_s32_v:
case NEON::BI__builtin_neon_vcvtn_s64_v:
- case NEON::BI__builtin_neon_vcvtn_u16_v:
+ case NEON::BI__builtin_neon_vcvtn_u16_f16:
case NEON::BI__builtin_neon_vcvtn_u32_v:
case NEON::BI__builtin_neon_vcvtn_u64_v:
- case NEON::BI__builtin_neon_vcvtnq_s16_v:
+ case NEON::BI__builtin_neon_vcvtnq_s16_f16:
case NEON::BI__builtin_neon_vcvtnq_s32_v:
case NEON::BI__builtin_neon_vcvtnq_s64_v:
- case NEON::BI__builtin_neon_vcvtnq_u16_v:
+ case NEON::BI__builtin_neon_vcvtnq_u16_f16:
case NEON::BI__builtin_neon_vcvtnq_u32_v:
case NEON::BI__builtin_neon_vcvtnq_u64_v:
- case NEON::BI__builtin_neon_vcvtp_s16_v:
+ case NEON::BI__builtin_neon_vcvtp_s16_f16:
case NEON::BI__builtin_neon_vcvtp_s32_v:
case NEON::BI__builtin_neon_vcvtp_s64_v:
- case NEON::BI__builtin_neon_vcvtp_u16_v:
+ case NEON::BI__builtin_neon_vcvtp_u16_f16:
case NEON::BI__builtin_neon_vcvtp_u32_v:
case NEON::BI__builtin_neon_vcvtp_u64_v:
- case NEON::BI__builtin_neon_vcvtpq_s16_v:
+ case NEON::BI__builtin_neon_vcvtpq_s16_f16:
case NEON::BI__builtin_neon_vcvtpq_s32_v:
case NEON::BI__builtin_neon_vcvtpq_s64_v:
- case NEON::BI__builtin_neon_vcvtpq_u16_v:
+ case NEON::BI__builtin_neon_vcvtpq_u16_f16:
case NEON::BI__builtin_neon_vcvtpq_u32_v:
case NEON::BI__builtin_neon_vcvtpq_u64_v:
- case NEON::BI__builtin_neon_vcvtm_s16_v:
+ case NEON::BI__builtin_neon_vcvtm_s16_f16:
case NEON::BI__builtin_neon_vcvtm_s32_v:
case NEON::BI__builtin_neon_vcvtm_s64_v:
- case NEON::BI__builtin_neon_vcvtm_u16_v:
+ case NEON::BI__builtin_neon_vcvtm_u16_f16:
case NEON::BI__builtin_neon_vcvtm_u32_v:
case NEON::BI__builtin_neon_vcvtm_u64_v:
- case NEON::BI__builtin_neon_vcvtmq_s16_v:
+ case NEON::BI__builtin_neon_vcvtmq_s16_f16:
case NEON::BI__builtin_neon_vcvtmq_s32_v:
case NEON::BI__builtin_neon_vcvtmq_s64_v:
- case NEON::BI__builtin_neon_vcvtmq_u16_v:
+ case NEON::BI__builtin_neon_vcvtmq_u16_f16:
case NEON::BI__builtin_neon_vcvtmq_u32_v:
case NEON::BI__builtin_neon_vcvtmq_u64_v: {
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
@@ -6861,7 +7120,7 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
}
case NEON::BI__builtin_neon_vld1_dup_v:
case NEON::BI__builtin_neon_vld1q_dup_v: {
- Value *V = UndefValue::get(Ty);
+ Value *V = PoisonValue::get(Ty);
PtrOp0 = Builder.CreateElementBitCast(PtrOp0, VTy->getElementType());
LoadInst *Ld = Builder.CreateLoad(PtrOp0);
llvm::Constant *CI = ConstantInt::get(SizeTy, 0);
@@ -6879,7 +7138,7 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
for (unsigned I = 2; I < Ops.size() - 1; ++I)
Ops[I] = Builder.CreateBitCast(Ops[I], Ty);
Ops.push_back(getAlignmentValue32(PtrOp1));
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), NameHint);
+ Ops[1] = Builder.CreateCall(F, ArrayRef(Ops).slice(1), NameHint);
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
@@ -6983,10 +7242,10 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
case NEON::BI__builtin_neon_vrshrq_n_v:
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrshr_n",
1, true);
- case NEON::BI__builtin_neon_vsha512hq_v:
- case NEON::BI__builtin_neon_vsha512h2q_v:
- case NEON::BI__builtin_neon_vsha512su0q_v:
- case NEON::BI__builtin_neon_vsha512su1q_v: {
+ case NEON::BI__builtin_neon_vsha512hq_u64:
+ case NEON::BI__builtin_neon_vsha512h2q_u64:
+ case NEON::BI__builtin_neon_vsha512su0q_u64:
+ case NEON::BI__builtin_neon_vsha512su1q_u64: {
Function *F = CGM.getIntrinsic(Int);
return EmitNeonCall(F, Ops, "");
}
@@ -7038,18 +7297,18 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
Ops.push_back(getAlignmentValue32(PtrOp0));
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "");
}
- case NEON::BI__builtin_neon_vsm3partw1q_v:
- case NEON::BI__builtin_neon_vsm3partw2q_v:
- case NEON::BI__builtin_neon_vsm3ss1q_v:
- case NEON::BI__builtin_neon_vsm4ekeyq_v:
- case NEON::BI__builtin_neon_vsm4eq_v: {
+ case NEON::BI__builtin_neon_vsm3partw1q_u32:
+ case NEON::BI__builtin_neon_vsm3partw2q_u32:
+ case NEON::BI__builtin_neon_vsm3ss1q_u32:
+ case NEON::BI__builtin_neon_vsm4ekeyq_u32:
+ case NEON::BI__builtin_neon_vsm4eq_u32: {
Function *F = CGM.getIntrinsic(Int);
return EmitNeonCall(F, Ops, "");
}
- case NEON::BI__builtin_neon_vsm3tt1aq_v:
- case NEON::BI__builtin_neon_vsm3tt1bq_v:
- case NEON::BI__builtin_neon_vsm3tt2aq_v:
- case NEON::BI__builtin_neon_vsm3tt2bq_v: {
+ case NEON::BI__builtin_neon_vsm3tt1aq_u32:
+ case NEON::BI__builtin_neon_vsm3tt1bq_u32:
+ case NEON::BI__builtin_neon_vsm3tt2aq_u32:
+ case NEON::BI__builtin_neon_vsm3tt2bq_u32: {
Function *F = CGM.getIntrinsic(Int);
Ops[3] = Builder.CreateZExt(Ops[3], Int64Ty);
return EmitNeonCall(F, Ops, "");
@@ -7135,7 +7394,7 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
}
return SV;
}
- case NEON::BI__builtin_neon_vxarq_v: {
+ case NEON::BI__builtin_neon_vxarq_u64: {
Function *F = CGM.getIntrinsic(Int);
Ops[2] = Builder.CreateZExt(Ops[2], Int64Ty);
return EmitNeonCall(F, Ops, "");
@@ -7159,70 +7418,71 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr(
}
return SV;
}
- case NEON::BI__builtin_neon_vdot_v:
- case NEON::BI__builtin_neon_vdotq_v: {
+ case NEON::BI__builtin_neon_vdot_s32:
+ case NEON::BI__builtin_neon_vdot_u32:
+ case NEON::BI__builtin_neon_vdotq_s32:
+ case NEON::BI__builtin_neon_vdotq_u32: {
auto *InputTy =
llvm::FixedVectorType::get(Int8Ty, Ty->getPrimitiveSizeInBits() / 8);
llvm::Type *Tys[2] = { Ty, InputTy };
- Int = Usgn ? LLVMIntrinsic : AltLLVMIntrinsic;
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vdot");
}
- case NEON::BI__builtin_neon_vfmlal_low_v:
- case NEON::BI__builtin_neon_vfmlalq_low_v: {
+ case NEON::BI__builtin_neon_vfmlal_low_f16:
+ case NEON::BI__builtin_neon_vfmlalq_low_f16: {
auto *InputTy =
llvm::FixedVectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
llvm::Type *Tys[2] = { Ty, InputTy };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vfmlal_low");
}
- case NEON::BI__builtin_neon_vfmlsl_low_v:
- case NEON::BI__builtin_neon_vfmlslq_low_v: {
+ case NEON::BI__builtin_neon_vfmlsl_low_f16:
+ case NEON::BI__builtin_neon_vfmlslq_low_f16: {
auto *InputTy =
llvm::FixedVectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
llvm::Type *Tys[2] = { Ty, InputTy };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vfmlsl_low");
}
- case NEON::BI__builtin_neon_vfmlal_high_v:
- case NEON::BI__builtin_neon_vfmlalq_high_v: {
+ case NEON::BI__builtin_neon_vfmlal_high_f16:
+ case NEON::BI__builtin_neon_vfmlalq_high_f16: {
auto *InputTy =
llvm::FixedVectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
llvm::Type *Tys[2] = { Ty, InputTy };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vfmlal_high");
}
- case NEON::BI__builtin_neon_vfmlsl_high_v:
- case NEON::BI__builtin_neon_vfmlslq_high_v: {
+ case NEON::BI__builtin_neon_vfmlsl_high_f16:
+ case NEON::BI__builtin_neon_vfmlslq_high_f16: {
auto *InputTy =
llvm::FixedVectorType::get(HalfTy, Ty->getPrimitiveSizeInBits() / 16);
llvm::Type *Tys[2] = { Ty, InputTy };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vfmlsl_high");
}
- case NEON::BI__builtin_neon_vmmlaq_v: {
+ case NEON::BI__builtin_neon_vmmlaq_s32:
+ case NEON::BI__builtin_neon_vmmlaq_u32: {
auto *InputTy =
llvm::FixedVectorType::get(Int8Ty, Ty->getPrimitiveSizeInBits() / 8);
llvm::Type *Tys[2] = { Ty, InputTy };
- Int = Usgn ? LLVMIntrinsic : AltLLVMIntrinsic;
- return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmmla");
+ return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, "vmmla");
}
- case NEON::BI__builtin_neon_vusmmlaq_v: {
+ case NEON::BI__builtin_neon_vusmmlaq_s32: {
auto *InputTy =
llvm::FixedVectorType::get(Int8Ty, Ty->getPrimitiveSizeInBits() / 8);
llvm::Type *Tys[2] = { Ty, InputTy };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vusmmla");
}
- case NEON::BI__builtin_neon_vusdot_v:
- case NEON::BI__builtin_neon_vusdotq_v: {
+ case NEON::BI__builtin_neon_vusdot_s32:
+ case NEON::BI__builtin_neon_vusdotq_s32: {
auto *InputTy =
llvm::FixedVectorType::get(Int8Ty, Ty->getPrimitiveSizeInBits() / 8);
llvm::Type *Tys[2] = { Ty, InputTy };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vusdot");
}
- case NEON::BI__builtin_neon_vbfdot_v:
- case NEON::BI__builtin_neon_vbfdotq_v: {
+ case NEON::BI__builtin_neon_vbfdot_f32:
+ case NEON::BI__builtin_neon_vbfdotq_f32: {
llvm::Type *InputTy =
llvm::FixedVectorType::get(BFloatTy, Ty->getPrimitiveSizeInBits() / 16);
llvm::Type *Tys[2] = { Ty, InputTy };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vbfdot");
}
- case NEON::BI__builtin_neon___a32_vcvt_bf16_v: {
+ case NEON::BI__builtin_neon___a32_vcvt_bf16_f32: {
llvm::Type *Tys[1] = { Ty };
Function *F = CGM.getIntrinsic(Int, Tys);
return EmitNeonCall(F, Ops, "vcvtfp2bf");
@@ -7354,9 +7614,10 @@ static Value *EmitSpecialRegisterBuiltin(CodeGenFunction &CGF,
llvm::Type *ValueType,
SpecialRegisterAccessKind AccessKind,
StringRef SysReg = "") {
- // write and register intrinsics only support 32 and 64 bit operations.
- assert((RegisterType->isIntegerTy(32) || RegisterType->isIntegerTy(64))
- && "Unsupported size for register.");
+ // write and register intrinsics only support 32, 64 and 128 bit operations.
+ assert((RegisterType->isIntegerTy(32) || RegisterType->isIntegerTy(64) ||
+ RegisterType->isIntegerTy(128)) &&
+ "Unsupported size for register.");
CodeGen::CGBuilderTy &Builder = CGF.Builder;
CodeGen::CodeGenModule &CGM = CGF.CGM;
@@ -7741,7 +8002,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Value *Arg0 = EmitScalarExpr(E->getArg(0));
Value *Arg1 = EmitScalarExpr(E->getArg(1));
- // crc32{c,}d intrinsics are implemnted as two calls to crc32{c,}w
+ // crc32{c,}d intrinsics are implemented as two calls to crc32{c,}w
// intrinsics, hence we need different codegen for these cases.
if (BuiltinID == clang::ARM::BI__builtin_arm_crc32d ||
BuiltinID == clang::ARM::BI__builtin_arm_crc32cd) {
@@ -7802,7 +8063,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Handle MSVC intrinsics before argument evaluation to prevent double
// evaluation.
- if (Optional<MSVCIntrin> MsvcIntId = translateArmToMsvcIntrin(BuiltinID))
+ if (std::optional<MSVCIntrin> MsvcIntId = translateArmToMsvcIntrin(BuiltinID))
return EmitMSVCBuiltinExpr(*MsvcIntId, E);
// Deal with MVE builtins
@@ -7812,6 +8073,13 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
if (Value *Result = EmitARMCDEBuiltinExpr(BuiltinID, E, ReturnValue, Arch))
return Result;
+ // Some intrinsics are equivalent - if they are use the base intrinsic ID.
+ auto It = llvm::find_if(NEONEquivalentIntrinsicMap, [BuiltinID](auto &P) {
+ return P.first == BuiltinID;
+ });
+ if (It != end(NEONEquivalentIntrinsicMap))
+ BuiltinID = It->second;
+
// Find out if any arguments are required to be integer constant
// expressions.
unsigned ICEArguments = 0;
@@ -7971,7 +8239,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Get the last argument, which specifies the vector type.
assert(HasExtraArg);
const Expr *Arg = E->getArg(E->getNumArgs()-1);
- Optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(getContext());
+ std::optional<llvm::APSInt> Result =
+ Arg->getIntegerConstantExpr(getContext());
if (!Result)
return nullptr;
@@ -8007,7 +8276,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Many NEON builtins have identical semantics and uses in ARM and
// AArch64. Emit these in a single function.
- auto IntrinsicMap = makeArrayRef(ARMSIMDIntrinsicMap);
+ auto IntrinsicMap = ArrayRef(ARMSIMDIntrinsicMap);
const ARMVectorIntrinsicInfo *Builtin = findARMVectorIntrinsicInMap(
IntrinsicMap, BuiltinID, NEONSIMDIntrinsicsProvenSorted);
if (Builtin)
@@ -8037,7 +8306,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
int Indices[] = {1 - Lane, Lane};
return Builder.CreateShuffleVector(Ops[1], Ld, Indices, "vld1q_lane");
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vld1_lane_v: {
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
PtrOp0 = Builder.CreateElementBitCast(PtrOp0, VTy->getElementType());
@@ -8077,7 +8346,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vsri_n_v:
case NEON::BI__builtin_neon_vsriq_n_v:
rightShift = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vsli_n_v:
case NEON::BI__builtin_neon_vsliq_n_v:
Ops[2] = EmitNeonShiftVector(Ops[2], Ty, rightShift);
@@ -8100,7 +8369,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1,
Tys), Ops);
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vst1_lane_v: {
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[1] = Builder.CreateExtractElement(Ops[1], Ops[2]);
@@ -8301,9 +8570,9 @@ Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID,
Ops.push_back(EmitScalarExpr(Addr));
Tys.push_back(ConvertType(Addr->getType()));
- Function *F = CGM.getIntrinsic(IRIntr, makeArrayRef(Tys));
+ Function *F = CGM.getIntrinsic(IRIntr, ArrayRef(Tys));
Value *LoadResult = Builder.CreateCall(F, Ops);
- Value *MvecOut = UndefValue::get(MvecLType);
+ Value *MvecOut = PoisonValue::get(MvecLType);
for (unsigned i = 0; i < NumVectors; ++i) {
Value *Vec = Builder.CreateExtractValue(LoadResult, i);
MvecOut = Builder.CreateInsertValue(MvecOut, Vec, {0, i});
@@ -8343,7 +8612,7 @@ Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID,
for (unsigned i = 0; i < NumVectors; i++)
Ops.push_back(Builder.CreateExtractValue(Mvec, {0, i}));
- Function *F = CGM.getIntrinsic(IRIntr, makeArrayRef(Tys));
+ Function *F = CGM.getIntrinsic(IRIntr, ArrayRef(Tys));
Value *ToReturn = nullptr;
for (unsigned i = 0; i < NumVectors; i++) {
Ops.push_back(llvm::ConstantInt::get(Int32Ty, i));
@@ -8409,7 +8678,8 @@ static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID
// Get the last argument, which specifies the vector type.
const Expr *Arg = E->getArg(E->getNumArgs() - 1);
- Optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(CGF.getContext());
+ std::optional<llvm::APSInt> Result =
+ Arg->getIntegerConstantExpr(CGF.getContext());
if (!Result)
return nullptr;
@@ -8425,29 +8695,25 @@ static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID
// argument that specifies the vector type, need to handle each case.
switch (BuiltinID) {
case NEON::BI__builtin_neon_vtbl1_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(0, 1), nullptr,
- Ops[1], Ty, Intrinsic::aarch64_neon_tbl1,
- "vtbl1");
+ return packTBLDVectorList(CGF, ArrayRef(Ops).slice(0, 1), nullptr, Ops[1],
+ Ty, Intrinsic::aarch64_neon_tbl1, "vtbl1");
}
case NEON::BI__builtin_neon_vtbl2_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(0, 2), nullptr,
- Ops[2], Ty, Intrinsic::aarch64_neon_tbl1,
- "vtbl1");
+ return packTBLDVectorList(CGF, ArrayRef(Ops).slice(0, 2), nullptr, Ops[2],
+ Ty, Intrinsic::aarch64_neon_tbl1, "vtbl1");
}
case NEON::BI__builtin_neon_vtbl3_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(0, 3), nullptr,
- Ops[3], Ty, Intrinsic::aarch64_neon_tbl2,
- "vtbl2");
+ return packTBLDVectorList(CGF, ArrayRef(Ops).slice(0, 3), nullptr, Ops[3],
+ Ty, Intrinsic::aarch64_neon_tbl2, "vtbl2");
}
case NEON::BI__builtin_neon_vtbl4_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(0, 4), nullptr,
- Ops[4], Ty, Intrinsic::aarch64_neon_tbl2,
- "vtbl2");
+ return packTBLDVectorList(CGF, ArrayRef(Ops).slice(0, 4), nullptr, Ops[4],
+ Ty, Intrinsic::aarch64_neon_tbl2, "vtbl2");
}
case NEON::BI__builtin_neon_vtbx1_v: {
Value *TblRes =
- packTBLDVectorList(CGF, makeArrayRef(Ops).slice(1, 1), nullptr, Ops[2],
- Ty, Intrinsic::aarch64_neon_tbl1, "vtbl1");
+ packTBLDVectorList(CGF, ArrayRef(Ops).slice(1, 1), nullptr, Ops[2], Ty,
+ Intrinsic::aarch64_neon_tbl1, "vtbl1");
llvm::Constant *EightV = ConstantInt::get(Ty, 8);
Value *CmpRes = Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[2], EightV);
@@ -8458,14 +8724,13 @@ static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID
return Builder.CreateOr(EltsFromInput, EltsFromTbl, "vtbx");
}
case NEON::BI__builtin_neon_vtbx2_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(1, 2), Ops[0],
- Ops[3], Ty, Intrinsic::aarch64_neon_tbx1,
- "vtbx1");
+ return packTBLDVectorList(CGF, ArrayRef(Ops).slice(1, 2), Ops[0], Ops[3],
+ Ty, Intrinsic::aarch64_neon_tbx1, "vtbx1");
}
case NEON::BI__builtin_neon_vtbx3_v: {
Value *TblRes =
- packTBLDVectorList(CGF, makeArrayRef(Ops).slice(1, 3), nullptr, Ops[4],
- Ty, Intrinsic::aarch64_neon_tbl2, "vtbl2");
+ packTBLDVectorList(CGF, ArrayRef(Ops).slice(1, 3), nullptr, Ops[4], Ty,
+ Intrinsic::aarch64_neon_tbl2, "vtbl2");
llvm::Constant *TwentyFourV = ConstantInt::get(Ty, 24);
Value *CmpRes = Builder.CreateICmp(ICmpInst::ICMP_UGE, Ops[4],
@@ -8477,9 +8742,8 @@ static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID
return Builder.CreateOr(EltsFromInput, EltsFromTbl, "vtbx");
}
case NEON::BI__builtin_neon_vtbx4_v: {
- return packTBLDVectorList(CGF, makeArrayRef(Ops).slice(1, 4), Ops[0],
- Ops[5], Ty, Intrinsic::aarch64_neon_tbx2,
- "vtbx2");
+ return packTBLDVectorList(CGF, ArrayRef(Ops).slice(1, 4), Ops[0], Ops[5],
+ Ty, Intrinsic::aarch64_neon_tbx2, "vtbx2");
}
case NEON::BI__builtin_neon_vqtbl1_v:
case NEON::BI__builtin_neon_vqtbl1q_v:
@@ -8518,7 +8782,7 @@ static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID
Value *CodeGenFunction::vectorWrapScalar16(Value *Op) {
auto *VTy = llvm::FixedVectorType::get(Int16Ty, 4);
Op = Builder.CreateBitCast(Op, Int16Ty);
- Value *V = UndefValue::get(VTy);
+ Value *V = PoisonValue::get(VTy);
llvm::Constant *CI = ConstantInt::get(SizeTy, 0);
Op = Builder.CreateInsertElement(V, Op, CI);
return Op;
@@ -8732,8 +8996,7 @@ Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags,
if (!TypeFlags.isByteIndexed() && Ops[1]->getType()->isVectorTy()) {
unsigned BytesPerElt =
OverloadedTy->getElementType()->getScalarSizeInBits() / 8;
- Value *Scale = ConstantInt::get(Int64Ty, BytesPerElt);
- Ops[2] = Builder.CreateMul(Ops[2], Scale);
+ Ops[2] = Builder.CreateShl(Ops[2], Log2_32(BytesPerElt));
}
Value *Call = Builder.CreateCall(F, Ops);
@@ -8792,8 +9055,7 @@ Value *CodeGenFunction::EmitSVEScatterStore(const SVETypeFlags &TypeFlags,
if (!TypeFlags.isByteIndexed() && Ops[2]->getType()->isVectorTy()) {
unsigned BytesPerElt =
OverloadedTy->getElementType()->getScalarSizeInBits() / 8;
- Value *Scale = ConstantInt::get(Int64Ty, BytesPerElt);
- Ops[3] = Builder.CreateMul(Ops[3], Scale);
+ Ops[3] = Builder.CreateShl(Ops[3], Log2_32(BytesPerElt));
}
return Builder.CreateCall(F, Ops);
@@ -8823,8 +9085,8 @@ Value *CodeGenFunction::EmitSVEGatherPrefetch(const SVETypeFlags &TypeFlags,
// Index needs to be passed as scaled offset.
llvm::Type *MemEltTy = SVEBuiltinMemEltTy(TypeFlags);
unsigned BytesPerElt = MemEltTy->getPrimitiveSizeInBits() / 8;
- Value *Scale = ConstantInt::get(Int64Ty, BytesPerElt);
- Ops[2] = Builder.CreateMul(Ops[2], Scale);
+ if (BytesPerElt > 1)
+ Ops[2] = Builder.CreateShl(Ops[2], Log2_32(BytesPerElt));
}
}
@@ -8841,13 +9103,13 @@ Value *CodeGenFunction::EmitSVEStructLoad(const SVETypeFlags &TypeFlags,
unsigned N;
switch (IntID) {
- case Intrinsic::aarch64_sve_ld2:
+ case Intrinsic::aarch64_sve_ld2_sret:
N = 2;
break;
- case Intrinsic::aarch64_sve_ld3:
+ case Intrinsic::aarch64_sve_ld3_sret:
N = 3;
break;
- case Intrinsic::aarch64_sve_ld4:
+ case Intrinsic::aarch64_sve_ld4_sret:
N = 4;
break;
default:
@@ -8858,12 +9120,22 @@ Value *CodeGenFunction::EmitSVEStructLoad(const SVETypeFlags &TypeFlags,
Value *Predicate = EmitSVEPredicateCast(Ops[0], VTy);
Value *BasePtr= Builder.CreateBitCast(Ops[1], VecPtrTy);
- Value *Offset = Ops.size() > 2 ? Ops[2] : Builder.getInt32(0);
- BasePtr = Builder.CreateGEP(VTy, BasePtr, Offset);
- BasePtr = Builder.CreateBitCast(BasePtr, EltPtrTy);
- Function *F = CGM.getIntrinsic(IntID, {RetTy, Predicate->getType()});
- return Builder.CreateCall(F, { Predicate, BasePtr });
+ // Does the load have an offset?
+ if (Ops.size() > 2)
+ BasePtr = Builder.CreateGEP(VTy, BasePtr, Ops[2]);
+
+ BasePtr = Builder.CreateBitCast(BasePtr, EltPtrTy);
+ Function *F = CGM.getIntrinsic(IntID, {VTy});
+ Value *Call = Builder.CreateCall(F, {Predicate, BasePtr});
+ unsigned MinElts = VTy->getMinNumElements();
+ Value *Ret = llvm::PoisonValue::get(RetTy);
+ for (unsigned I = 0; I < N; I++) {
+ Value *Idx = ConstantInt::get(CGM.Int64Ty, I * MinElts);
+ Value *SRet = Builder.CreateExtractValue(Call, I);
+ Ret = Builder.CreateInsertVector(RetTy, Ret, SRet, Idx);
+ }
+ return Ret;
}
Value *CodeGenFunction::EmitSVEStructStore(const SVETypeFlags &TypeFlags,
@@ -8887,23 +9159,25 @@ Value *CodeGenFunction::EmitSVEStructStore(const SVETypeFlags &TypeFlags,
default:
llvm_unreachable("unknown intrinsic!");
}
- auto TupleTy =
- llvm::VectorType::get(VTy->getElementType(), VTy->getElementCount() * N);
Value *Predicate = EmitSVEPredicateCast(Ops[0], VTy);
Value *BasePtr = Builder.CreateBitCast(Ops[1], VecPtrTy);
- Value *Offset = Ops.size() > 3 ? Ops[2] : Builder.getInt32(0);
- Value *Val = Ops.back();
- BasePtr = Builder.CreateGEP(VTy, BasePtr, Offset);
+
+ // Does the store have an offset?
+ if (Ops.size() > 3)
+ BasePtr = Builder.CreateGEP(VTy, BasePtr, Ops[2]);
+
BasePtr = Builder.CreateBitCast(BasePtr, EltPtrTy);
+ Value *Val = Ops.back();
// The llvm.aarch64.sve.st2/3/4 intrinsics take legal part vectors, so we
// need to break up the tuple vector.
SmallVector<llvm::Value*, 5> Operands;
- Function *FExtr =
- CGM.getIntrinsic(Intrinsic::aarch64_sve_tuple_get, {VTy, TupleTy});
- for (unsigned I = 0; I < N; ++I)
- Operands.push_back(Builder.CreateCall(FExtr, {Val, Builder.getInt32(I)}));
+ unsigned MinElts = VTy->getElementCount().getKnownMinValue();
+ for (unsigned I = 0; I < N; ++I) {
+ Value *Idx = ConstantInt::get(CGM.Int64Ty, I * MinElts);
+ Operands.push_back(Builder.CreateExtractVector(VTy, Val, Idx));
+ }
Operands.append({Predicate, BasePtr});
Function *F = CGM.getIntrinsic(IntID, { VTy });
@@ -8978,8 +9252,10 @@ Value *CodeGenFunction::EmitSVEMaskedLoad(const CallExpr *E,
Value *Predicate = EmitSVEPredicateCast(Ops[0], MemoryTy);
Value *BasePtr = Builder.CreateBitCast(Ops[1], MemoryTy->getPointerTo());
- Value *Offset = Ops.size() > 2 ? Ops[2] : Builder.getInt32(0);
- BasePtr = Builder.CreateGEP(MemoryTy, BasePtr, Offset);
+
+ // Does the load have an offset?
+ if (Ops.size() > 2)
+ BasePtr = Builder.CreateGEP(MemoryTy, BasePtr, Ops[2]);
BasePtr = Builder.CreateBitCast(BasePtr, MemEltTy->getPointerTo());
Function *F = CGM.getIntrinsic(BuiltinID, MemoryTy);
@@ -9006,8 +9282,10 @@ Value *CodeGenFunction::EmitSVEMaskedStore(const CallExpr *E,
Value *Predicate = EmitSVEPredicateCast(Ops[0], MemoryTy);
Value *BasePtr = Builder.CreateBitCast(Ops[1], MemoryTy->getPointerTo());
- Value *Offset = Ops.size() == 4 ? Ops[2] : Builder.getInt32(0);
- BasePtr = Builder.CreateGEP(MemoryTy, BasePtr, Offset);
+
+ // Does the store have an offset?
+ if (Ops.size() == 4)
+ BasePtr = Builder.CreateGEP(MemoryTy, BasePtr, Ops[2]);
// Last value is always the data
llvm::Value *Val = Builder.CreateTrunc(Ops.back(), MemoryTy);
@@ -9024,8 +9302,8 @@ Value *CodeGenFunction::EmitSVEMaskedStore(const CallExpr *E,
// Limit the usage of scalable llvm IR generated by the ACLE by using the
// sve dup.x intrinsic instead of IRBuilder::CreateVectorSplat.
Value *CodeGenFunction::EmitSVEDupX(Value *Scalar, llvm::Type *Ty) {
- auto F = CGM.getIntrinsic(Intrinsic::aarch64_sve_dup_x, Ty);
- return Builder.CreateCall(F, Scalar);
+ return Builder.CreateVectorSplat(
+ cast<llvm::VectorType>(Ty)->getElementCount(), Scalar);
}
Value *CodeGenFunction::EmitSVEDupX(Value* Scalar) {
@@ -9069,16 +9347,46 @@ CodeGenFunction::getSVEOverloadTypes(const SVETypeFlags &TypeFlags,
if (TypeFlags.isOverloadWhileRW())
return {getSVEPredType(TypeFlags), Ops[0]->getType()};
- if (TypeFlags.isOverloadCvt() || TypeFlags.isTupleSet())
+ if (TypeFlags.isOverloadCvt())
return {Ops[0]->getType(), Ops.back()->getType()};
- if (TypeFlags.isTupleCreate() || TypeFlags.isTupleGet())
- return {ResultType, Ops[0]->getType()};
-
assert(TypeFlags.isOverloadDefault() && "Unexpected value for overloads");
return {DefaultType};
}
+Value *CodeGenFunction::EmitSVETupleSetOrGet(const SVETypeFlags &TypeFlags,
+ llvm::Type *Ty,
+ ArrayRef<Value *> Ops) {
+ assert((TypeFlags.isTupleSet() || TypeFlags.isTupleGet()) &&
+ "Expects TypleFlag isTupleSet or TypeFlags.isTupleSet()");
+
+ unsigned I = cast<ConstantInt>(Ops[1])->getSExtValue();
+ auto *SingleVecTy = dyn_cast<llvm::ScalableVectorType>(
+ TypeFlags.isTupleSet() ? Ops[2]->getType() : Ty);
+ Value *Idx = ConstantInt::get(CGM.Int64Ty,
+ I * SingleVecTy->getMinNumElements());
+
+ if (TypeFlags.isTupleSet())
+ return Builder.CreateInsertVector(Ty, Ops[0], Ops[2], Idx);
+ return Builder.CreateExtractVector(Ty, Ops[0], Idx);
+}
+
+Value *CodeGenFunction::EmitSVETupleCreate(const SVETypeFlags &TypeFlags,
+ llvm::Type *Ty,
+ ArrayRef<Value *> Ops) {
+ assert(TypeFlags.isTupleCreate() && "Expects TypleFlag isTupleCreate");
+
+ auto *SrcTy = dyn_cast<llvm::ScalableVectorType>(Ops[0]->getType());
+ unsigned MinElts = SrcTy->getMinNumElements();
+ Value *Call = llvm::PoisonValue::get(Ty);
+ for (unsigned I = 0; I < Ops.size(); I++) {
+ Value *Idx = ConstantInt::get(CGM.Int64Ty, I * MinElts);
+ Call = Builder.CreateInsertVector(Ty, Call, Ops[I], Idx);
+ }
+
+ return Call;
+}
+
Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
// Find out if any arguments are required to be integer constant expressions.
@@ -9101,7 +9409,7 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
else {
// If this is required to be a constant, constant fold it so that we know
// that the generated intrinsic gets a ConstantInt.
- Optional<llvm::APSInt> Result =
+ std::optional<llvm::APSInt> Result =
E->getArg(i)->getIntegerConstantExpr(getContext());
assert(Result && "Expected argument to be a constant");
@@ -9133,6 +9441,10 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
return EmitSVEStructLoad(TypeFlags, Ops, Builtin->LLVMIntrinsic);
else if (TypeFlags.isStructStore())
return EmitSVEStructStore(TypeFlags, Ops, Builtin->LLVMIntrinsic);
+ else if (TypeFlags.isTupleSet() || TypeFlags.isTupleGet())
+ return EmitSVETupleSetOrGet(TypeFlags, Ty, Ops);
+ else if (TypeFlags.isTupleCreate())
+ return EmitSVETupleCreate(TypeFlags, Ty, Ops);
else if (TypeFlags.isUndef())
return UndefValue::get(Ty);
else if (Builtin->LLVMIntrinsic != 0) {
@@ -9171,8 +9483,7 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
if (TypeFlags.getMergeType() == SVETypeFlags::MergeZero) {
llvm::Type *OpndTy = Ops[1]->getType();
auto *SplatZero = Constant::getNullValue(OpndTy);
- Function *Sel = CGM.getIntrinsic(Intrinsic::aarch64_sve_sel, OpndTy);
- Ops[1] = Builder.CreateCall(Sel, {Ops[0], Ops[1], SplatZero});
+ Ops[1] = Builder.CreateSelect(Ops[0], Ops[1], SplatZero);
}
Function *F = CGM.getIntrinsic(Builtin->LLVMIntrinsic,
@@ -9285,12 +9596,9 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
VecOps.push_back(Builder.CreateZExt(Ops[I], EltTy));
Value *Vec = BuildVector(VecOps);
- SVETypeFlags TypeFlags(Builtin->TypeModifier);
- Value *Pred = EmitSVEAllTruePred(TypeFlags);
-
llvm::Type *OverloadedTy = getSVEVectorForElementType(EltTy);
Value *InsertSubVec = Builder.CreateInsertVector(
- OverloadedTy, UndefValue::get(OverloadedTy), Vec, Builder.getInt64(0));
+ OverloadedTy, PoisonValue::get(OverloadedTy), Vec, Builder.getInt64(0));
Function *F =
CGM.getIntrinsic(Intrinsic::aarch64_sve_dupq_lane, OverloadedTy);
@@ -9300,6 +9608,9 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
if (!IsBoolTy)
return DupQLane;
+ SVETypeFlags TypeFlags(Builtin->TypeModifier);
+ Value *Pred = EmitSVEAllTruePred(TypeFlags);
+
// For svdupq_n_b* we need to add an additional 'cmpne' with '0'.
F = CGM.getIntrinsic(NumOpnds == 2 ? Intrinsic::aarch64_sve_cmpne
: Intrinsic::aarch64_sve_cmpne_wide,
@@ -9346,12 +9657,12 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
case SVE::BI__builtin_sve_svtbl2_f32:
case SVE::BI__builtin_sve_svtbl2_f64: {
SVETypeFlags TF(Builtin->TypeModifier);
- auto VTy = cast<llvm::VectorType>(getSVEType(TF));
- auto TupleTy = llvm::VectorType::getDoubleElementsVectorType(VTy);
- Function *FExtr =
- CGM.getIntrinsic(Intrinsic::aarch64_sve_tuple_get, {VTy, TupleTy});
- Value *V0 = Builder.CreateCall(FExtr, {Ops[0], Builder.getInt32(0)});
- Value *V1 = Builder.CreateCall(FExtr, {Ops[0], Builder.getInt32(1)});
+ auto VTy = cast<llvm::ScalableVectorType>(getSVEType(TF));
+ Value *V0 = Builder.CreateExtractVector(VTy, Ops[0],
+ ConstantInt::get(CGM.Int64Ty, 0));
+ unsigned MinElts = VTy->getMinNumElements();
+ Value *V1 = Builder.CreateExtractVector(
+ VTy, Ops[0], ConstantInt::get(CGM.Int64Ty, MinElts));
Function *F = CGM.getIntrinsic(Intrinsic::aarch64_sve_tbl2, VTy);
return Builder.CreateCall(F, {V0, V1, Ops[1]});
}
@@ -9398,7 +9709,7 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
case SVE::BI__builtin_sve_svdup_neonq_f32:
case SVE::BI__builtin_sve_svdup_neonq_f64:
case SVE::BI__builtin_sve_svdup_neonq_bf16: {
- Value *Insert = Builder.CreateInsertVector(Ty, UndefValue::get(Ty), Ops[0],
+ Value *Insert = Builder.CreateInsertVector(Ty, PoisonValue::get(Ty), Ops[0],
Builder.getInt64(0));
return Builder.CreateIntrinsic(Intrinsic::aarch64_sve_dupq_lane, {Ty},
{Insert, Builder.getInt64(0)});
@@ -9449,29 +9760,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
}
- if (BuiltinID == clang::AArch64::BI__builtin_arm_prefetch) {
- Value *Address = EmitScalarExpr(E->getArg(0));
- Value *RW = EmitScalarExpr(E->getArg(1));
- Value *CacheLevel = EmitScalarExpr(E->getArg(2));
- Value *RetentionPolicy = EmitScalarExpr(E->getArg(3));
- Value *IsData = EmitScalarExpr(E->getArg(4));
-
- Value *Locality = nullptr;
- if (cast<llvm::ConstantInt>(RetentionPolicy)->isZero()) {
- // Temporal fetch, needs to convert cache level to locality.
- Locality = llvm::ConstantInt::get(Int32Ty,
- -cast<llvm::ConstantInt>(CacheLevel)->getValue() + 3);
- } else {
- // Streaming fetch.
- Locality = llvm::ConstantInt::get(Int32Ty, 0);
- }
-
- // FIXME: We need AArch64 specific LLVM intrinsic if we want to specify
- // PLDL3STRM or PLDL2STRM.
- Function *F = CGM.getIntrinsic(Intrinsic::prefetch, Address->getType());
- return Builder.CreateCall(F, {Address, RW, Locality, IsData});
- }
-
if (BuiltinID == clang::AArch64::BI__builtin_arm_rbit) {
assert((getContext().getTypeSize(E->getType()) == 32) &&
"rbit of unusual size!");
@@ -9498,32 +9786,32 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
"cls");
}
- if (BuiltinID == clang::AArch64::BI__builtin_arm_frint32zf ||
- BuiltinID == clang::AArch64::BI__builtin_arm_frint32z) {
+ if (BuiltinID == clang::AArch64::BI__builtin_arm_rint32zf ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_rint32z) {
llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
llvm::Type *Ty = Arg->getType();
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint32z, Ty),
Arg, "frint32z");
}
- if (BuiltinID == clang::AArch64::BI__builtin_arm_frint64zf ||
- BuiltinID == clang::AArch64::BI__builtin_arm_frint64z) {
+ if (BuiltinID == clang::AArch64::BI__builtin_arm_rint64zf ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_rint64z) {
llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
llvm::Type *Ty = Arg->getType();
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint64z, Ty),
Arg, "frint64z");
}
- if (BuiltinID == clang::AArch64::BI__builtin_arm_frint32xf ||
- BuiltinID == clang::AArch64::BI__builtin_arm_frint32x) {
+ if (BuiltinID == clang::AArch64::BI__builtin_arm_rint32xf ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_rint32x) {
llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
llvm::Type *Ty = Arg->getType();
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint32x, Ty),
Arg, "frint32x");
}
- if (BuiltinID == clang::AArch64::BI__builtin_arm_frint64xf ||
- BuiltinID == clang::AArch64::BI__builtin_arm_frint64x) {
+ if (BuiltinID == clang::AArch64::BI__builtin_arm_rint64xf ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_rint64x) {
llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
llvm::Type *Ty = Arg->getType();
return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint64x, Ty),
@@ -9875,32 +10163,43 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
if (BuiltinID == clang::AArch64::BI__builtin_arm_rsr ||
BuiltinID == clang::AArch64::BI__builtin_arm_rsr64 ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_rsr128 ||
BuiltinID == clang::AArch64::BI__builtin_arm_rsrp ||
BuiltinID == clang::AArch64::BI__builtin_arm_wsr ||
BuiltinID == clang::AArch64::BI__builtin_arm_wsr64 ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_wsr128 ||
BuiltinID == clang::AArch64::BI__builtin_arm_wsrp) {
SpecialRegisterAccessKind AccessKind = Write;
if (BuiltinID == clang::AArch64::BI__builtin_arm_rsr ||
BuiltinID == clang::AArch64::BI__builtin_arm_rsr64 ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_rsr128 ||
BuiltinID == clang::AArch64::BI__builtin_arm_rsrp)
AccessKind = VolatileRead;
bool IsPointerBuiltin = BuiltinID == clang::AArch64::BI__builtin_arm_rsrp ||
BuiltinID == clang::AArch64::BI__builtin_arm_wsrp;
- bool Is64Bit = BuiltinID != clang::AArch64::BI__builtin_arm_rsr &&
- BuiltinID != clang::AArch64::BI__builtin_arm_wsr;
+ bool Is32Bit = BuiltinID == clang::AArch64::BI__builtin_arm_rsr ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_wsr;
+
+ bool Is128Bit = BuiltinID == clang::AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == clang::AArch64::BI__builtin_arm_wsr128;
llvm::Type *ValueType;
llvm::Type *RegisterType = Int64Ty;
- if (IsPointerBuiltin) {
+ if (Is32Bit) {
+ ValueType = Int32Ty;
+ } else if (Is128Bit) {
+ llvm::Type *Int128Ty =
+ llvm::IntegerType::getInt128Ty(CGM.getLLVMContext());
+ ValueType = Int128Ty;
+ RegisterType = Int128Ty;
+ } else if (IsPointerBuiltin) {
ValueType = VoidPtrTy;
- } else if (Is64Bit) {
- ValueType = Int64Ty;
} else {
- ValueType = Int32Ty;
- }
+ ValueType = Int64Ty;
+ };
return EmitSpecialRegisterBuiltin(*this, E, RegisterType, ValueType,
AccessKind);
@@ -10026,9 +10325,17 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
// Handle MSVC intrinsics before argument evaluation to prevent double
// evaluation.
- if (Optional<MSVCIntrin> MsvcIntId = translateAarch64ToMsvcIntrin(BuiltinID))
+ if (std::optional<MSVCIntrin> MsvcIntId =
+ translateAarch64ToMsvcIntrin(BuiltinID))
return EmitMSVCBuiltinExpr(*MsvcIntId, E);
+ // Some intrinsics are equivalent - if they are use the base intrinsic ID.
+ auto It = llvm::find_if(NEONEquivalentIntrinsicMap, [BuiltinID](auto &P) {
+ return P.first == BuiltinID;
+ });
+ if (It != end(NEONEquivalentIntrinsicMap))
+ BuiltinID = It->second;
+
// Find out if any arguments are required to be integer constant
// expressions.
unsigned ICEArguments = 0;
@@ -10069,7 +10376,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
}
}
- auto SISDMap = makeArrayRef(AArch64SISDIntrinsicMap);
+ auto SISDMap = ArrayRef(AArch64SISDIntrinsicMap);
const ARMVectorIntrinsicInfo *Builtin = findARMVectorIntrinsicInMap(
SISDMap, BuiltinID, AArch64SISDIntrinsicsProvenSorted);
@@ -10082,7 +10389,8 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
const Expr *Arg = E->getArg(E->getNumArgs()-1);
NeonTypeFlags Type(0);
- if (Optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(getContext()))
+ if (std::optional<llvm::APSInt> Result =
+ Arg->getIntegerConstantExpr(getContext()))
// Determine the type of this overloaded NEON intrinsic.
Type = NeonTypeFlags(Result->getZExtValue());
@@ -10119,7 +10427,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vcvts_f32_u32:
case NEON::BI__builtin_neon_vcvtd_f64_u64:
usgn = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vcvts_f32_s32:
case NEON::BI__builtin_neon_vcvtd_f64_s64: {
Ops.push_back(EmitScalarExpr(E->getArg(0)));
@@ -10135,7 +10443,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vcvth_f16_u32:
case NEON::BI__builtin_neon_vcvth_f16_u64:
usgn = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vcvth_f16_s16:
case NEON::BI__builtin_neon_vcvth_f16_s32:
case NEON::BI__builtin_neon_vcvth_f16_s64: {
@@ -11068,26 +11376,26 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
: Intrinsic::trunc;
return EmitNeonCall(CGM.getIntrinsic(Int, HalfTy), Ops, "vrndz");
}
- case NEON::BI__builtin_neon_vrnd32x_v:
- case NEON::BI__builtin_neon_vrnd32xq_v: {
+ case NEON::BI__builtin_neon_vrnd32x_f32:
+ case NEON::BI__builtin_neon_vrnd32xq_f32: {
Ops.push_back(EmitScalarExpr(E->getArg(0)));
Int = Intrinsic::aarch64_neon_frint32x;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnd32x");
}
- case NEON::BI__builtin_neon_vrnd32z_v:
- case NEON::BI__builtin_neon_vrnd32zq_v: {
+ case NEON::BI__builtin_neon_vrnd32z_f32:
+ case NEON::BI__builtin_neon_vrnd32zq_f32: {
Ops.push_back(EmitScalarExpr(E->getArg(0)));
Int = Intrinsic::aarch64_neon_frint32z;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnd32z");
}
- case NEON::BI__builtin_neon_vrnd64x_v:
- case NEON::BI__builtin_neon_vrnd64xq_v: {
+ case NEON::BI__builtin_neon_vrnd64x_f32:
+ case NEON::BI__builtin_neon_vrnd64xq_f32: {
Ops.push_back(EmitScalarExpr(E->getArg(0)));
Int = Intrinsic::aarch64_neon_frint64x;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnd64x");
}
- case NEON::BI__builtin_neon_vrnd64z_v:
- case NEON::BI__builtin_neon_vrnd64zq_v: {
+ case NEON::BI__builtin_neon_vrnd64z_f32:
+ case NEON::BI__builtin_neon_vrnd64zq_f32: {
Ops.push_back(EmitScalarExpr(E->getArg(0)));
Int = Intrinsic::aarch64_neon_frint64z;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vrnd64z");
@@ -11125,26 +11433,26 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vcvt_u32_v:
case NEON::BI__builtin_neon_vcvt_s64_v:
case NEON::BI__builtin_neon_vcvt_u64_v:
- case NEON::BI__builtin_neon_vcvt_s16_v:
- case NEON::BI__builtin_neon_vcvt_u16_v:
+ case NEON::BI__builtin_neon_vcvt_s16_f16:
+ case NEON::BI__builtin_neon_vcvt_u16_f16:
case NEON::BI__builtin_neon_vcvtq_s32_v:
case NEON::BI__builtin_neon_vcvtq_u32_v:
case NEON::BI__builtin_neon_vcvtq_s64_v:
case NEON::BI__builtin_neon_vcvtq_u64_v:
- case NEON::BI__builtin_neon_vcvtq_s16_v:
- case NEON::BI__builtin_neon_vcvtq_u16_v: {
+ case NEON::BI__builtin_neon_vcvtq_s16_f16:
+ case NEON::BI__builtin_neon_vcvtq_u16_f16: {
Int =
usgn ? Intrinsic::aarch64_neon_fcvtzu : Intrinsic::aarch64_neon_fcvtzs;
llvm::Type *Tys[2] = {Ty, GetFloatNeonType(this, Type)};
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtz");
}
- case NEON::BI__builtin_neon_vcvta_s16_v:
- case NEON::BI__builtin_neon_vcvta_u16_v:
+ case NEON::BI__builtin_neon_vcvta_s16_f16:
+ case NEON::BI__builtin_neon_vcvta_u16_f16:
case NEON::BI__builtin_neon_vcvta_s32_v:
- case NEON::BI__builtin_neon_vcvtaq_s16_v:
+ case NEON::BI__builtin_neon_vcvtaq_s16_f16:
case NEON::BI__builtin_neon_vcvtaq_s32_v:
case NEON::BI__builtin_neon_vcvta_u32_v:
- case NEON::BI__builtin_neon_vcvtaq_u16_v:
+ case NEON::BI__builtin_neon_vcvtaq_u16_f16:
case NEON::BI__builtin_neon_vcvtaq_u32_v:
case NEON::BI__builtin_neon_vcvta_s64_v:
case NEON::BI__builtin_neon_vcvtaq_s64_v:
@@ -11154,13 +11462,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvta");
}
- case NEON::BI__builtin_neon_vcvtm_s16_v:
+ case NEON::BI__builtin_neon_vcvtm_s16_f16:
case NEON::BI__builtin_neon_vcvtm_s32_v:
- case NEON::BI__builtin_neon_vcvtmq_s16_v:
+ case NEON::BI__builtin_neon_vcvtmq_s16_f16:
case NEON::BI__builtin_neon_vcvtmq_s32_v:
- case NEON::BI__builtin_neon_vcvtm_u16_v:
+ case NEON::BI__builtin_neon_vcvtm_u16_f16:
case NEON::BI__builtin_neon_vcvtm_u32_v:
- case NEON::BI__builtin_neon_vcvtmq_u16_v:
+ case NEON::BI__builtin_neon_vcvtmq_u16_f16:
case NEON::BI__builtin_neon_vcvtmq_u32_v:
case NEON::BI__builtin_neon_vcvtm_s64_v:
case NEON::BI__builtin_neon_vcvtmq_s64_v:
@@ -11170,13 +11478,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtm");
}
- case NEON::BI__builtin_neon_vcvtn_s16_v:
+ case NEON::BI__builtin_neon_vcvtn_s16_f16:
case NEON::BI__builtin_neon_vcvtn_s32_v:
- case NEON::BI__builtin_neon_vcvtnq_s16_v:
+ case NEON::BI__builtin_neon_vcvtnq_s16_f16:
case NEON::BI__builtin_neon_vcvtnq_s32_v:
- case NEON::BI__builtin_neon_vcvtn_u16_v:
+ case NEON::BI__builtin_neon_vcvtn_u16_f16:
case NEON::BI__builtin_neon_vcvtn_u32_v:
- case NEON::BI__builtin_neon_vcvtnq_u16_v:
+ case NEON::BI__builtin_neon_vcvtnq_u16_f16:
case NEON::BI__builtin_neon_vcvtnq_u32_v:
case NEON::BI__builtin_neon_vcvtn_s64_v:
case NEON::BI__builtin_neon_vcvtnq_s64_v:
@@ -11186,13 +11494,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) };
return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtn");
}
- case NEON::BI__builtin_neon_vcvtp_s16_v:
+ case NEON::BI__builtin_neon_vcvtp_s16_f16:
case NEON::BI__builtin_neon_vcvtp_s32_v:
- case NEON::BI__builtin_neon_vcvtpq_s16_v:
+ case NEON::BI__builtin_neon_vcvtpq_s16_f16:
case NEON::BI__builtin_neon_vcvtpq_s32_v:
- case NEON::BI__builtin_neon_vcvtp_u16_v:
+ case NEON::BI__builtin_neon_vcvtp_u16_f16:
case NEON::BI__builtin_neon_vcvtp_u32_v:
- case NEON::BI__builtin_neon_vcvtpq_u16_v:
+ case NEON::BI__builtin_neon_vcvtpq_u16_f16:
case NEON::BI__builtin_neon_vcvtpq_u32_v:
case NEON::BI__builtin_neon_vcvtp_s64_v:
case NEON::BI__builtin_neon_vcvtpq_s64_v:
@@ -11268,7 +11576,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vaddv_u8:
// FIXME: These are handled by the AArch64 scalar code.
usgn = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vaddv_s8: {
Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
Ty = Int32Ty;
@@ -11280,7 +11588,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
}
case NEON::BI__builtin_neon_vaddv_u16:
usgn = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vaddv_s16: {
Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
Ty = Int32Ty;
@@ -11292,7 +11600,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
}
case NEON::BI__builtin_neon_vaddvq_u8:
usgn = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vaddvq_s8: {
Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
Ty = Int32Ty;
@@ -11304,7 +11612,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
}
case NEON::BI__builtin_neon_vaddvq_u16:
usgn = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NEON::BI__builtin_neon_vaddvq_s16: {
Int = usgn ? Intrinsic::aarch64_neon_uaddv : Intrinsic::aarch64_neon_saddv;
Ty = Int32Ty;
@@ -11652,7 +11960,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
}
case NEON::BI__builtin_neon_vld1_dup_v:
case NEON::BI__builtin_neon_vld1q_dup_v: {
- Value *V = UndefValue::get(Ty);
+ Value *V = PoisonValue::get(Ty);
Ty = llvm::PointerType::getUnqual(VTy->getElementType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[0] = Builder.CreateAlignedLoad(VTy->getElementType(), Ops[0],
@@ -11745,7 +12053,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateZExt(Ops[3], Int64Ty);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane");
+ Ops[1] = Builder.CreateCall(F, ArrayRef(Ops).slice(1), "vld2_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
@@ -11759,7 +12067,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateZExt(Ops[4], Int64Ty);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane");
+ Ops[1] = Builder.CreateCall(F, ArrayRef(Ops).slice(1), "vld3_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
@@ -11774,7 +12082,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Ops[3] = Builder.CreateBitCast(Ops[3], Ty);
Ops[4] = Builder.CreateBitCast(Ops[4], Ty);
Ops[5] = Builder.CreateZExt(Ops[5], Int64Ty);
- Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld4_lane");
+ Ops[1] = Builder.CreateCall(F, ArrayRef(Ops).slice(1), "vld4_lane");
Ty = llvm::PointerType::getUnqual(Ops[1]->getType());
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
return Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
@@ -11934,7 +12242,7 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID,
"unexpected BPF builtin");
// A sequence number, injected into IR builtin functions, to
- // prevent CSE given the only difference of the funciton
+ // prevent CSE given the only difference of the function
// may just be the debuginfo metadata.
static uint32_t BuiltinSeqNum;
@@ -12050,11 +12358,11 @@ BuildVector(ArrayRef<llvm::Value*> Ops) {
}
// Otherwise, insertelement the values to build the vector.
- Value *Result = llvm::UndefValue::get(
+ Value *Result = llvm::PoisonValue::get(
llvm::FixedVectorType::get(Ops[0]->getType(), Ops.size()));
for (unsigned i = 0, e = Ops.size(); i != e; ++i)
- Result = Builder.CreateInsertElement(Result, Ops[i], Builder.getInt32(i));
+ Result = Builder.CreateInsertElement(Result, Ops[i], Builder.getInt64(i));
return Result;
}
@@ -12074,9 +12382,8 @@ static Value *getMaskVecValue(CodeGenFunction &CGF, Value *Mask,
int Indices[4];
for (unsigned i = 0; i != NumElts; ++i)
Indices[i] = i;
- MaskVec = CGF.Builder.CreateShuffleVector(MaskVec, MaskVec,
- makeArrayRef(Indices, NumElts),
- "extract");
+ MaskVec = CGF.Builder.CreateShuffleVector(
+ MaskVec, MaskVec, ArrayRef(Indices, NumElts), "extract");
}
return MaskVec;
}
@@ -12347,7 +12654,7 @@ static Value *EmitX86FMAExpr(CodeGenFunction &CGF, const CallExpr *E,
default: break;
case clang::X86::BI__builtin_ia32_vfmsubph512_mask3:
Subtract = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case clang::X86::BI__builtin_ia32_vfmaddph512_mask:
case clang::X86::BI__builtin_ia32_vfmaddph512_maskz:
case clang::X86::BI__builtin_ia32_vfmaddph512_mask3:
@@ -12355,7 +12662,7 @@ static Value *EmitX86FMAExpr(CodeGenFunction &CGF, const CallExpr *E,
break;
case clang::X86::BI__builtin_ia32_vfmsubaddph512_mask3:
Subtract = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case clang::X86::BI__builtin_ia32_vfmaddsubph512_mask:
case clang::X86::BI__builtin_ia32_vfmaddsubph512_maskz:
case clang::X86::BI__builtin_ia32_vfmaddsubph512_mask3:
@@ -12363,21 +12670,21 @@ static Value *EmitX86FMAExpr(CodeGenFunction &CGF, const CallExpr *E,
break;
case clang::X86::BI__builtin_ia32_vfmsubps512_mask3:
Subtract = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case clang::X86::BI__builtin_ia32_vfmaddps512_mask:
case clang::X86::BI__builtin_ia32_vfmaddps512_maskz:
case clang::X86::BI__builtin_ia32_vfmaddps512_mask3:
IID = llvm::Intrinsic::x86_avx512_vfmadd_ps_512; break;
case clang::X86::BI__builtin_ia32_vfmsubpd512_mask3:
Subtract = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case clang::X86::BI__builtin_ia32_vfmaddpd512_mask:
case clang::X86::BI__builtin_ia32_vfmaddpd512_maskz:
case clang::X86::BI__builtin_ia32_vfmaddpd512_mask3:
IID = llvm::Intrinsic::x86_avx512_vfmadd_pd_512; break;
case clang::X86::BI__builtin_ia32_vfmsubaddps512_mask3:
Subtract = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case clang::X86::BI__builtin_ia32_vfmaddsubps512_mask:
case clang::X86::BI__builtin_ia32_vfmaddsubps512_maskz:
case clang::X86::BI__builtin_ia32_vfmaddsubps512_mask3:
@@ -12385,7 +12692,7 @@ static Value *EmitX86FMAExpr(CodeGenFunction &CGF, const CallExpr *E,
break;
case clang::X86::BI__builtin_ia32_vfmsubaddpd512_mask3:
Subtract = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case clang::X86::BI__builtin_ia32_vfmaddsubpd512_mask:
case clang::X86::BI__builtin_ia32_vfmaddsubpd512_maskz:
case clang::X86::BI__builtin_ia32_vfmaddsubpd512_mask3:
@@ -12628,18 +12935,6 @@ static Value *EmitX86CvtF16ToFloatExpr(CodeGenFunction &CGF,
return Res;
}
-// Convert a BF16 to a float.
-static Value *EmitX86CvtBF16ToFloatExpr(CodeGenFunction &CGF,
- const CallExpr *E,
- ArrayRef<Value *> Ops) {
- llvm::Type *Int32Ty = CGF.Builder.getInt32Ty();
- Value *ZeroExt = CGF.Builder.CreateZExt(Ops[0], Int32Ty);
- Value *Shl = CGF.Builder.CreateShl(ZeroExt, 16);
- llvm::Type *ResultType = CGF.ConvertType(E->getType());
- Value *BitCast = CGF.Builder.CreateBitCast(Shl, ResultType);
- return BitCast;
-}
-
Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) {
llvm::Type *Int32Ty = Builder.getInt32Ty();
@@ -12668,9 +12963,11 @@ Value *CodeGenFunction::EmitX86CpuIs(StringRef CPUStr) {
.Case(ALIAS, {1u, static_cast<unsigned>(llvm::X86::ENUM)})
#define X86_CPU_TYPE(ENUM, STR) \
.Case(STR, {1u, static_cast<unsigned>(llvm::X86::ENUM)})
+#define X86_CPU_SUBTYPE_ALIAS(ENUM, ALIAS) \
+ .Case(ALIAS, {2u, static_cast<unsigned>(llvm::X86::ENUM)})
#define X86_CPU_SUBTYPE(ENUM, STR) \
.Case(STR, {2u, static_cast<unsigned>(llvm::X86::ENUM)})
-#include "llvm/Support/X86TargetParser.def"
+#include "llvm/TargetParser/X86TargetParser.def"
.Default({0, 0});
assert(Value != 0 && "Invalid CPUStr passed to CpuIs");
@@ -12749,6 +13046,16 @@ llvm::Value *CodeGenFunction::EmitX86CpuSupports(uint64_t FeaturesMask) {
return Result;
}
+Value *CodeGenFunction::EmitAArch64CpuInit() {
+ llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
+ llvm::FunctionCallee Func =
+ CGM.CreateRuntimeFunction(FTy, "init_cpu_features_resolver");
+ cast<llvm::GlobalValue>(Func.getCallee())->setDSOLocal(true);
+ cast<llvm::GlobalValue>(Func.getCallee())
+ ->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
+ return Builder.CreateCall(Func);
+}
+
Value *CodeGenFunction::EmitX86CpuInit() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
/*Variadic*/ false);
@@ -12760,6 +13067,32 @@ Value *CodeGenFunction::EmitX86CpuInit() {
return Builder.CreateCall(Func);
}
+llvm::Value *
+CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
+ uint64_t FeaturesMask = llvm::AArch64::getCpuSupportsMask(FeaturesStrs);
+ Value *Result = Builder.getTrue();
+ if (FeaturesMask != 0) {
+ // Get features from structure in runtime library
+ // struct {
+ // unsigned long long features;
+ // } __aarch64_cpu_features;
+ llvm::Type *STy = llvm::StructType::get(Int64Ty);
+ llvm::Constant *AArch64CPUFeatures =
+ CGM.CreateRuntimeVariable(STy, "__aarch64_cpu_features");
+ cast<llvm::GlobalValue>(AArch64CPUFeatures)->setDSOLocal(true);
+ llvm::Value *CpuFeatures = Builder.CreateGEP(
+ STy, AArch64CPUFeatures,
+ {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 0)});
+ Value *Features = Builder.CreateAlignedLoad(Int64Ty, CpuFeatures,
+ CharUnits::fromQuantity(8));
+ Value *Mask = Builder.getInt64(FeaturesMask);
+ Value *Bitset = Builder.CreateAnd(Features, Mask);
+ Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask);
+ Result = Builder.CreateAnd(Result, Cmp);
+ }
+ return Result;
+}
+
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
if (BuiltinID == X86::BI__builtin_cpu_is)
@@ -12771,7 +13104,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// Handle MSVC intrinsics before argument evaluation to prevent double
// evaluation.
- if (Optional<MSVCIntrin> MsvcIntId = translateX86ToMsvcIntrin(BuiltinID))
+ if (std::optional<MSVCIntrin> MsvcIntId = translateX86ToMsvcIntrin(BuiltinID))
return EmitMSVCBuiltinExpr(*MsvcIntId, E);
SmallVector<Value*, 4> Ops;
@@ -13512,8 +13845,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
for (unsigned i = 0; i != NumElts; ++i)
Indices[i] = i + Index;
- Value *Res = Builder.CreateShuffleVector(Ops[0],
- makeArrayRef(Indices, NumElts),
+ Value *Res = Builder.CreateShuffleVector(Ops[0], ArrayRef(Indices, NumElts),
"extract");
if (Ops.size() == 4)
@@ -13551,9 +13883,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
for (unsigned i = 0; i != DstNumElts; ++i)
Indices[i] = (i >= SrcNumElts) ? SrcNumElts + (i % SrcNumElts) : i;
- Value *Op1 = Builder.CreateShuffleVector(Ops[1],
- makeArrayRef(Indices, DstNumElts),
- "widen");
+ Value *Op1 = Builder.CreateShuffleVector(
+ Ops[1], ArrayRef(Indices, DstNumElts), "widen");
for (unsigned i = 0; i != DstNumElts; ++i) {
if (i >= Index && i < (Index + SrcNumElts))
@@ -13563,8 +13894,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
return Builder.CreateShuffleVector(Ops[0], Op1,
- makeArrayRef(Indices, DstNumElts),
- "insert");
+ ArrayRef(Indices, DstNumElts), "insert");
}
case X86::BI__builtin_ia32_pmovqd512_mask:
case X86::BI__builtin_ia32_pmovwb512_mask: {
@@ -13614,8 +13944,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Indices[i] = ((Imm >> (i % 8)) & 0x1) ? NumElts + i : i;
return Builder.CreateShuffleVector(Ops[0], Ops[1],
- makeArrayRef(Indices, NumElts),
- "blend");
+ ArrayRef(Indices, NumElts), "blend");
}
case X86::BI__builtin_ia32_pshuflw:
case X86::BI__builtin_ia32_pshuflw256:
@@ -13637,7 +13966,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Indices[l + i] = l + i;
}
- return Builder.CreateShuffleVector(Ops[0], makeArrayRef(Indices, NumElts),
+ return Builder.CreateShuffleVector(Ops[0], ArrayRef(Indices, NumElts),
"pshuflw");
}
case X86::BI__builtin_ia32_pshufhw:
@@ -13660,7 +13989,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
}
- return Builder.CreateShuffleVector(Ops[0], makeArrayRef(Indices, NumElts),
+ return Builder.CreateShuffleVector(Ops[0], ArrayRef(Indices, NumElts),
"pshufhw");
}
case X86::BI__builtin_ia32_pshufd:
@@ -13689,7 +14018,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
}
- return Builder.CreateShuffleVector(Ops[0], makeArrayRef(Indices, NumElts),
+ return Builder.CreateShuffleVector(Ops[0], ArrayRef(Indices, NumElts),
"permil");
}
case X86::BI__builtin_ia32_shufpd:
@@ -13719,8 +14048,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
return Builder.CreateShuffleVector(Ops[0], Ops[1],
- makeArrayRef(Indices, NumElts),
- "shufp");
+ ArrayRef(Indices, NumElts), "shufp");
}
case X86::BI__builtin_ia32_permdi256:
case X86::BI__builtin_ia32_permdf256:
@@ -13736,7 +14064,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
for (unsigned i = 0; i != 4; ++i)
Indices[l + i] = l + ((Imm >> (2 * i)) & 0x3);
- return Builder.CreateShuffleVector(Ops[0], makeArrayRef(Indices, NumElts),
+ return Builder.CreateShuffleVector(Ops[0], ArrayRef(Indices, NumElts),
"perm");
}
case X86::BI__builtin_ia32_palignr128:
@@ -13773,8 +14101,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
return Builder.CreateShuffleVector(Ops[1], Ops[0],
- makeArrayRef(Indices, NumElts),
- "palignr");
+ ArrayRef(Indices, NumElts), "palignr");
}
case X86::BI__builtin_ia32_alignd128:
case X86::BI__builtin_ia32_alignd256:
@@ -13794,8 +14121,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Indices[i] = i + ShiftVal;
return Builder.CreateShuffleVector(Ops[1], Ops[0],
- makeArrayRef(Indices, NumElts),
- "valign");
+ ArrayRef(Indices, NumElts), "valign");
}
case X86::BI__builtin_ia32_shuf_f32x4_256:
case X86::BI__builtin_ia32_shuf_f64x2_256:
@@ -13823,8 +14149,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
return Builder.CreateShuffleVector(Ops[0], Ops[1],
- makeArrayRef(Indices, NumElts),
- "shuf");
+ ArrayRef(Indices, NumElts), "shuf");
}
case X86::BI__builtin_ia32_vperm2f128_pd256:
@@ -13863,8 +14188,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
return Builder.CreateShuffleVector(OutOps[0], OutOps[1],
- makeArrayRef(Indices, NumElts),
- "vperm");
+ ArrayRef(Indices, NumElts), "vperm");
}
case X86::BI__builtin_ia32_pslldqi128_byteshift:
@@ -13892,9 +14216,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
auto *VecTy = llvm::FixedVectorType::get(Int8Ty, NumElts);
Value *Cast = Builder.CreateBitCast(Ops[0], VecTy, "cast");
Value *Zero = llvm::Constant::getNullValue(VecTy);
- Value *SV = Builder.CreateShuffleVector(Zero, Cast,
- makeArrayRef(Indices, NumElts),
- "pslldq");
+ Value *SV = Builder.CreateShuffleVector(
+ Zero, Cast, ArrayRef(Indices, NumElts), "pslldq");
return Builder.CreateBitCast(SV, Ops[0]->getType(), "cast");
}
case X86::BI__builtin_ia32_psrldqi128_byteshift:
@@ -13922,9 +14245,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
auto *VecTy = llvm::FixedVectorType::get(Int8Ty, NumElts);
Value *Cast = Builder.CreateBitCast(Ops[0], VecTy, "cast");
Value *Zero = llvm::Constant::getNullValue(VecTy);
- Value *SV = Builder.CreateShuffleVector(Cast, Zero,
- makeArrayRef(Indices, NumElts),
- "psrldq");
+ Value *SV = Builder.CreateShuffleVector(
+ Cast, Zero, ArrayRef(Indices, NumElts), "psrldq");
return Builder.CreateBitCast(SV, ResultType, "cast");
}
case X86::BI__builtin_ia32_kshiftliqi:
@@ -13944,9 +14266,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Indices[i] = NumElts + i - ShiftVal;
Value *Zero = llvm::Constant::getNullValue(In->getType());
- Value *SV = Builder.CreateShuffleVector(Zero, In,
- makeArrayRef(Indices, NumElts),
- "kshiftl");
+ Value *SV = Builder.CreateShuffleVector(
+ Zero, In, ArrayRef(Indices, NumElts), "kshiftl");
return Builder.CreateBitCast(SV, Ops[0]->getType());
}
case X86::BI__builtin_ia32_kshiftriqi:
@@ -13966,9 +14287,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Indices[i] = i + ShiftVal;
Value *Zero = llvm::Constant::getNullValue(In->getType());
- Value *SV = Builder.CreateShuffleVector(In, Zero,
- makeArrayRef(Indices, NumElts),
- "kshiftr");
+ Value *SV = Builder.CreateShuffleVector(
+ In, Zero, ArrayRef(Indices, NumElts), "kshiftr");
return Builder.CreateBitCast(SV, Ops[0]->getType());
}
case X86::BI__builtin_ia32_movnti:
@@ -14046,6 +14366,9 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_selectph_128:
case X86::BI__builtin_ia32_selectph_256:
case X86::BI__builtin_ia32_selectph_512:
+ case X86::BI__builtin_ia32_selectpbf_128:
+ case X86::BI__builtin_ia32_selectpbf_256:
+ case X86::BI__builtin_ia32_selectpbf_512:
case X86::BI__builtin_ia32_selectps_128:
case X86::BI__builtin_ia32_selectps_256:
case X86::BI__builtin_ia32_selectps_512:
@@ -14054,6 +14377,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_selectpd_512:
return EmitX86Select(*this, Ops[0], Ops[1], Ops[2]);
case X86::BI__builtin_ia32_selectsh_128:
+ case X86::BI__builtin_ia32_selectsbf_128:
case X86::BI__builtin_ia32_selectss_128:
case X86::BI__builtin_ia32_selectsd_128: {
Value *A = Builder.CreateExtractElement(Ops[1], (uint64_t)0);
@@ -14251,14 +14575,12 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// First extract half of each vector. This gives better codegen than
// doing it in a single shuffle.
- LHS = Builder.CreateShuffleVector(LHS, LHS,
- makeArrayRef(Indices, NumElts / 2));
- RHS = Builder.CreateShuffleVector(RHS, RHS,
- makeArrayRef(Indices, NumElts / 2));
+ LHS = Builder.CreateShuffleVector(LHS, LHS, ArrayRef(Indices, NumElts / 2));
+ RHS = Builder.CreateShuffleVector(RHS, RHS, ArrayRef(Indices, NumElts / 2));
// Concat the vectors.
// NOTE: Operands are swapped to match the intrinsic definition.
- Value *Res = Builder.CreateShuffleVector(RHS, LHS,
- makeArrayRef(Indices, NumElts));
+ Value *Res =
+ Builder.CreateShuffleVector(RHS, LHS, ArrayRef(Indices, NumElts));
return Builder.CreateBitCast(Res, Ops[0]->getType());
}
@@ -14448,6 +14770,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_reduce_fadd_ph128: {
Function *F =
CGM.getIntrinsic(Intrinsic::vector_reduce_fadd, Ops[1]->getType());
+ IRBuilder<>::FastMathFlagGuard FMFGuard(Builder);
Builder.getFastMathFlags().setAllowReassoc();
return Builder.CreateCall(F, {Ops[0], Ops[1]});
}
@@ -14458,6 +14781,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_reduce_fmul_ph128: {
Function *F =
CGM.getIntrinsic(Intrinsic::vector_reduce_fmul, Ops[1]->getType());
+ IRBuilder<>::FastMathFlagGuard FMFGuard(Builder);
Builder.getFastMathFlags().setAllowReassoc();
return Builder.CreateCall(F, {Ops[0], Ops[1]});
}
@@ -14468,6 +14792,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_reduce_fmax_ph128: {
Function *F =
CGM.getIntrinsic(Intrinsic::vector_reduce_fmax, Ops[0]->getType());
+ IRBuilder<>::FastMathFlagGuard FMFGuard(Builder);
Builder.getFastMathFlags().setNoNaNs();
return Builder.CreateCall(F, {Ops[0]});
}
@@ -14478,6 +14803,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_reduce_fmin_ph128: {
Function *F =
CGM.getIntrinsic(Intrinsic::vector_reduce_fmin, Ops[0]->getType());
+ IRBuilder<>::FastMathFlagGuard FMFGuard(Builder);
Builder.getFastMathFlags().setNoNaNs();
return Builder.CreateCall(F, {Ops[0]});
}
@@ -14725,7 +15051,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_cmppd256_mask:
case X86::BI__builtin_ia32_cmppd512_mask:
IsMaskFCmp = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case X86::BI__builtin_ia32_cmpps:
case X86::BI__builtin_ia32_cmpps256:
case X86::BI__builtin_ia32_cmppd:
@@ -14890,7 +15216,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return EmitX86CvtF16ToFloatExpr(*this, Ops, ConvertType(E->getType()));
}
-// AVX512 bf16 intrinsics
+ // AVX512 bf16 intrinsics
case X86::BI__builtin_ia32_cvtneps2bf16_128_mask: {
Ops[2] = getMaskVecValue(
*this, Ops[2],
@@ -14899,7 +15225,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(CGM.getIntrinsic(IID), Ops);
}
case X86::BI__builtin_ia32_cvtsbf162ss_32:
- return EmitX86CvtBF16ToFloatExpr(*this, E, Ops);
+ return Builder.CreateFPExt(Ops[0], Builder.getFloatTy());
case X86::BI__builtin_ia32_cvtneps2bf16_256_mask:
case X86::BI__builtin_ia32_cvtneps2bf16_512_mask: {
@@ -15214,7 +15540,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_vfcmaddcph512_mask:
IsConjFMA = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case X86::BI__builtin_ia32_vfmaddcph512_mask: {
Intrinsic::ID IID = IsConjFMA
? Intrinsic::x86_avx512fp16_mask_vfcmadd_cph_512
@@ -15224,7 +15550,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_vfcmaddcsh_round_mask:
IsConjFMA = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case X86::BI__builtin_ia32_vfmaddcsh_round_mask: {
Intrinsic::ID IID = IsConjFMA ? Intrinsic::x86_avx512fp16_mask_vfcmadd_csh
: Intrinsic::x86_avx512fp16_mask_vfmadd_csh;
@@ -15234,7 +15560,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_vfcmaddcsh_round_mask3:
IsConjFMA = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case X86::BI__builtin_ia32_vfmaddcsh_round_mask3: {
Intrinsic::ID IID = IsConjFMA ? Intrinsic::x86_avx512fp16_mask_vfcmadd_csh
: Intrinsic::x86_avx512fp16_mask_vfmadd_csh;
@@ -15242,6 +15568,11 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
static constexpr int Mask[] = {0, 5, 6, 7};
return Builder.CreateShuffleVector(Call, Ops[2], Mask);
}
+ case X86::BI__builtin_ia32_prefetchi:
+ return Builder.CreateCall(
+ CGM.getIntrinsic(Intrinsic::prefetch, Ops[0]->getType()),
+ {Ops[0], llvm::ConstantInt::get(Int32Ty, 0), Ops[1],
+ llvm::ConstantInt::get(Int32Ty, 0)});
}
}
@@ -15976,7 +16307,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
assert(ArgCI &&
"Third arg to xxinsertw intrinsic must be constant integer");
const int64_t MaxIndex = 12;
- int64_t Index = clamp(ArgCI->getSExtValue(), 0, MaxIndex);
+ int64_t Index = std::clamp(ArgCI->getSExtValue(), (int64_t)0, MaxIndex);
// The builtin semantics don't exactly match the xxinsertw instructions
// semantics (which ppc_vsx_xxinsertw follows). The builtin extracts the
@@ -16018,7 +16349,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
assert(ArgCI &&
"Second Arg to xxextractuw intrinsic must be a constant integer!");
const int64_t MaxIndex = 12;
- int64_t Index = clamp(ArgCI->getSExtValue(), 0, MaxIndex);
+ int64_t Index = std::clamp(ArgCI->getSExtValue(), (int64_t)0, MaxIndex);
if (getTarget().isLittleEndian()) {
// Reverse the index.
@@ -16103,10 +16434,10 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
bool isLittleEndian = getTarget().isLittleEndian();
- Value *UndefValue =
- llvm::UndefValue::get(llvm::FixedVectorType::get(Op0->getType(), 2));
+ Value *PoisonValue =
+ llvm::PoisonValue::get(llvm::FixedVectorType::get(Op0->getType(), 2));
Value *Res = Builder.CreateInsertElement(
- UndefValue, Op0, (uint64_t)(isLittleEndian ? 1 : 0));
+ PoisonValue, Op0, (uint64_t)(isLittleEndian ? 1 : 0));
Res = Builder.CreateInsertElement(Res, Op1,
(uint64_t)(isLittleEndian ? 0 : 1));
return Builder.CreateBitCast(Res, ConvertType(E->getType()));
@@ -16235,7 +16566,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
auto Pair = EmitAtomicCompareExchange(
LV, RValue::get(OldVal), RValue::get(Op2), E->getExprLoc(),
llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic, true);
- // Unlike c11's atomic_compare_exchange, accroding to
+ // Unlike c11's atomic_compare_exchange, according to
// https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=functions-compare-swap-compare-swaplp
// > In either case, the contents of the memory location specified by addr
// > are copied into the memory location specified by old_val_addr.
@@ -16353,16 +16684,9 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
case PPC::BI__builtin_ppc_test_data_class: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
- llvm::Type *ArgType = Op0->getType();
- unsigned IntrinsicID;
- if (ArgType->isDoubleTy())
- IntrinsicID = Intrinsic::ppc_test_data_class_d;
- else if (ArgType->isFloatTy())
- IntrinsicID = Intrinsic::ppc_test_data_class_f;
- else
- llvm_unreachable("Invalid Argument Type");
- return Builder.CreateCall(CGM.getIntrinsic(IntrinsicID), {Op0, Op1},
- "test_data_class");
+ return Builder.CreateCall(
+ CGM.getIntrinsic(Intrinsic::ppc_test_data_class, Op0->getType()),
+ {Op0, Op1}, "test_data_class");
}
case PPC::BI__builtin_ppc_maxfe: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
@@ -16475,8 +16799,10 @@ Value *EmitAMDGPUWorkGroupSize(CodeGenFunction &CGF, unsigned Index) {
llvm::MDNode *RNode = MDHelper.createRange(APInt(16, 1),
APInt(16, CGF.getTarget().getMaxOpenCLWorkGroupSize() + 1));
LD->setMetadata(llvm::LLVMContext::MD_range, RNode);
+ LD->setMetadata(llvm::LLVMContext::MD_noundef,
+ llvm::MDNode::get(CGF.getLLVMContext(), std::nullopt));
LD->setMetadata(llvm::LLVMContext::MD_invariant_load,
- llvm::MDNode::get(CGF.getLLVMContext(), None));
+ llvm::MDNode::get(CGF.getLLVMContext(), std::nullopt));
return LD;
}
@@ -16493,7 +16819,7 @@ Value *EmitAMDGPUGridSize(CodeGenFunction &CGF, unsigned Index) {
auto *LD = CGF.Builder.CreateLoad(
Address(Cast, CGF.Int32Ty, CharUnits::fromQuantity(4)));
LD->setMetadata(llvm::LLVMContext::MD_invariant_load,
- llvm::MDNode::get(CGF.getLLVMContext(), None));
+ llvm::MDNode::get(CGF.getLLVMContext(), std::nullopt));
return LD;
}
} // namespace
@@ -16504,39 +16830,35 @@ Value *EmitAMDGPUGridSize(CodeGenFunction &CGF, unsigned Index) {
// it into LLVM's memory ordering specifier using atomic C ABI, and writes
// to \p AO. \p Scope takes a const char * and converts it into AMDGCN
// specific SyncScopeID and writes it to \p SSID.
-bool CodeGenFunction::ProcessOrderScopeAMDGCN(Value *Order, Value *Scope,
+void CodeGenFunction::ProcessOrderScopeAMDGCN(Value *Order, Value *Scope,
llvm::AtomicOrdering &AO,
llvm::SyncScope::ID &SSID) {
- if (isa<llvm::ConstantInt>(Order)) {
- int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
-
- // Map C11/C++11 memory ordering to LLVM memory ordering
- assert(llvm::isValidAtomicOrderingCABI(ord));
- switch (static_cast<llvm::AtomicOrderingCABI>(ord)) {
- case llvm::AtomicOrderingCABI::acquire:
- case llvm::AtomicOrderingCABI::consume:
- AO = llvm::AtomicOrdering::Acquire;
- break;
- case llvm::AtomicOrderingCABI::release:
- AO = llvm::AtomicOrdering::Release;
- break;
- case llvm::AtomicOrderingCABI::acq_rel:
- AO = llvm::AtomicOrdering::AcquireRelease;
- break;
- case llvm::AtomicOrderingCABI::seq_cst:
- AO = llvm::AtomicOrdering::SequentiallyConsistent;
- break;
- case llvm::AtomicOrderingCABI::relaxed:
- AO = llvm::AtomicOrdering::Monotonic;
- break;
- }
-
- StringRef scp;
- llvm::getConstantStringInfo(Scope, scp);
- SSID = getLLVMContext().getOrInsertSyncScopeID(scp);
- return true;
+ int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+
+ // Map C11/C++11 memory ordering to LLVM memory ordering
+ assert(llvm::isValidAtomicOrderingCABI(ord));
+ switch (static_cast<llvm::AtomicOrderingCABI>(ord)) {
+ case llvm::AtomicOrderingCABI::acquire:
+ case llvm::AtomicOrderingCABI::consume:
+ AO = llvm::AtomicOrdering::Acquire;
+ break;
+ case llvm::AtomicOrderingCABI::release:
+ AO = llvm::AtomicOrdering::Release;
+ break;
+ case llvm::AtomicOrderingCABI::acq_rel:
+ AO = llvm::AtomicOrdering::AcquireRelease;
+ break;
+ case llvm::AtomicOrderingCABI::seq_cst:
+ AO = llvm::AtomicOrdering::SequentiallyConsistent;
+ break;
+ case llvm::AtomicOrderingCABI::relaxed:
+ AO = llvm::AtomicOrdering::Monotonic;
+ break;
}
- return false;
+
+ StringRef scp;
+ llvm::getConstantStringInfo(Scope, scp);
+ SSID = getLLVMContext().getOrInsertSyncScopeID(scp);
}
Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
@@ -16593,7 +16915,7 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
Args.push_back(EmitScalarExpr(E->getArg(I)));
assert(Args.size() == 5 || Args.size() == 6);
if (Args.size() == 5)
- Args.insert(Args.begin(), llvm::UndefValue::get(Args[0]->getType()));
+ Args.insert(Args.begin(), llvm::PoisonValue::get(Args[0]->getType()));
Function *F =
CGM.getIntrinsic(Intrinsic::amdgcn_update_dpp, Args[0]->getType());
return Builder.CreateCall(F, Args);
@@ -16661,6 +16983,13 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
return emitTernaryBuiltin(*this, E, Intrinsic::amdgcn_ubfe);
case AMDGPU::BI__builtin_amdgcn_sbfe:
return emitTernaryBuiltin(*this, E, Intrinsic::amdgcn_sbfe);
+ case AMDGPU::BI__builtin_amdgcn_ballot_w32:
+ case AMDGPU::BI__builtin_amdgcn_ballot_w64: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ llvm::Value *Src = EmitScalarExpr(E->getArg(0));
+ Function *F = CGM.getIntrinsic(Intrinsic::amdgcn_ballot, { ResultType });
+ return Builder.CreateCall(F, { Src });
+ }
case AMDGPU::BI__builtin_amdgcn_uicmp:
case AMDGPU::BI__builtin_amdgcn_uicmpl:
case AMDGPU::BI__builtin_amdgcn_sicmp:
@@ -16862,6 +17191,21 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
RayInverseDir, TextureDescr});
}
+ case AMDGPU::BI__builtin_amdgcn_ds_bvh_stack_rtn: {
+ SmallVector<Value *, 4> Args;
+ for (int i = 0, e = E->getNumArgs(); i != e; ++i)
+ Args.push_back(EmitScalarExpr(E->getArg(i)));
+
+ Function *F = CGM.getIntrinsic(Intrinsic::amdgcn_ds_bvh_stack_rtn);
+ Value *Call = Builder.CreateCall(F, Args);
+ Value *Rtn = Builder.CreateExtractValue(Call, 0);
+ Value *A = Builder.CreateExtractValue(Call, 1);
+ llvm::Type *RetTy = ConvertType(E->getType());
+ Value *I0 = Builder.CreateInsertElement(PoisonValue::get(RetTy), Rtn,
+ (uint64_t)0);
+ return Builder.CreateInsertElement(I0, A, 1);
+ }
+
case AMDGPU::BI__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w32:
case AMDGPU::BI__builtin_amdgcn_wmma_bf16_16x16x16_bf16_w64:
case AMDGPU::BI__builtin_amdgcn_wmma_f16_16x16x16_f16_w32:
@@ -16966,12 +17310,10 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
Function *F = CGM.getIntrinsic(Intrinsic::fshr, Src0->getType());
return Builder.CreateCall(F, { Src0, Src1, Src2 });
}
-
case AMDGPU::BI__builtin_amdgcn_fence: {
- if (ProcessOrderScopeAMDGCN(EmitScalarExpr(E->getArg(0)),
- EmitScalarExpr(E->getArg(1)), AO, SSID))
- return Builder.CreateFence(AO, SSID);
- LLVM_FALLTHROUGH;
+ ProcessOrderScopeAMDGCN(EmitScalarExpr(E->getArg(0)),
+ EmitScalarExpr(E->getArg(1)), AO, SSID);
+ return Builder.CreateFence(AO, SSID);
}
case AMDGPU::BI__builtin_amdgcn_atomic_inc32:
case AMDGPU::BI__builtin_amdgcn_atomic_inc64:
@@ -16997,22 +17339,29 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
llvm::Function *F =
CGM.getIntrinsic(BuiltinAtomicOp, {ResultType, Ptr->getType()});
- if (ProcessOrderScopeAMDGCN(EmitScalarExpr(E->getArg(2)),
- EmitScalarExpr(E->getArg(3)), AO, SSID)) {
+ ProcessOrderScopeAMDGCN(EmitScalarExpr(E->getArg(2)),
+ EmitScalarExpr(E->getArg(3)), AO, SSID);
- // llvm.amdgcn.atomic.inc and llvm.amdgcn.atomic.dec expects ordering and
- // scope as unsigned values
- Value *MemOrder = Builder.getInt32(static_cast<int>(AO));
- Value *MemScope = Builder.getInt32(static_cast<int>(SSID));
+ // llvm.amdgcn.atomic.inc and llvm.amdgcn.atomic.dec expects ordering and
+ // scope as unsigned values
+ Value *MemOrder = Builder.getInt32(static_cast<int>(AO));
+ Value *MemScope = Builder.getInt32(static_cast<int>(SSID));
- QualType PtrTy = E->getArg(0)->IgnoreImpCasts()->getType();
- bool Volatile =
- PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
- Value *IsVolatile = Builder.getInt1(static_cast<bool>(Volatile));
+ QualType PtrTy = E->getArg(0)->IgnoreImpCasts()->getType();
+ bool Volatile =
+ PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified();
+ Value *IsVolatile = Builder.getInt1(static_cast<bool>(Volatile));
- return Builder.CreateCall(F, {Ptr, Val, MemOrder, MemScope, IsVolatile});
- }
- LLVM_FALLTHROUGH;
+ return Builder.CreateCall(F, {Ptr, Val, MemOrder, MemScope, IsVolatile});
+ }
+ case AMDGPU::BI__builtin_amdgcn_s_sendmsg_rtn:
+ case AMDGPU::BI__builtin_amdgcn_s_sendmsg_rtnl: {
+ llvm::Value *Arg = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ResultType = ConvertType(E->getType());
+ // s_sendmsg_rtn is mangled using return type only.
+ Function *F =
+ CGM.getIntrinsic(Intrinsic::amdgcn_s_sendmsg_rtn, {ResultType});
+ return Builder.CreateCall(F, {Arg});
}
default:
return nullptr;
@@ -18035,7 +18384,7 @@ CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
Address Dst = EmitPointerWithAlignment(E->getArg(0));
Value *Src = EmitScalarExpr(E->getArg(1));
Value *Ldm = EmitScalarExpr(E->getArg(2));
- Optional<llvm::APSInt> isColMajorArg =
+ std::optional<llvm::APSInt> isColMajorArg =
E->getArg(3)->getIntegerConstantExpr(getContext());
if (!isColMajorArg)
return nullptr;
@@ -18082,7 +18431,7 @@ CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
Value *Dst = EmitScalarExpr(E->getArg(0));
Address Src = EmitPointerWithAlignment(E->getArg(1));
Value *Ldm = EmitScalarExpr(E->getArg(2));
- Optional<llvm::APSInt> isColMajorArg =
+ std::optional<llvm::APSInt> isColMajorArg =
E->getArg(3)->getIntegerConstantExpr(getContext());
if (!isColMajorArg)
return nullptr;
@@ -18141,7 +18490,7 @@ CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
Address SrcA = EmitPointerWithAlignment(E->getArg(1));
Address SrcB = EmitPointerWithAlignment(E->getArg(2));
Address SrcC = EmitPointerWithAlignment(E->getArg(3));
- Optional<llvm::APSInt> LayoutArg =
+ std::optional<llvm::APSInt> LayoutArg =
E->getArg(4)->getIntegerConstantExpr(getContext());
if (!LayoutArg)
return nullptr;
@@ -18152,7 +18501,7 @@ CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E) {
if (BuiltinID == NVPTX::BI__bmma_m8n8k128_mma_xor_popc_b1 ||
BuiltinID == NVPTX::BI__bmma_m8n8k128_mma_and_popc_b1)
SatfArg = 0; // .b1 does not have satf argument.
- else if (Optional<llvm::APSInt> OptSatfArg =
+ else if (std::optional<llvm::APSInt> OptSatfArg =
E->getArg(5)->getIntegerConstantExpr(getContext()))
SatfArg = *OptSatfArg;
else
@@ -18595,7 +18944,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
IntNo = Intrinsic::wasm_extadd_pairwise_unsigned;
break;
default:
- llvm_unreachable("unexptected builtin ID");
+ llvm_unreachable("unexpected builtin ID");
}
Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
@@ -18715,7 +19064,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Ops[OpIdx++] = EmitScalarExpr(E->getArg(0));
Ops[OpIdx++] = EmitScalarExpr(E->getArg(1));
while (OpIdx < 18) {
- Optional<llvm::APSInt> LaneConst =
+ std::optional<llvm::APSInt> LaneConst =
E->getArg(OpIdx)->getIntegerConstantExpr(getContext());
assert(LaneConst && "Constant arg isn't actually constant?");
Ops[OpIdx++] = llvm::ConstantInt::get(getLLVMContext(), *LaneConst);
@@ -18723,22 +19072,22 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_shuffle);
return Builder.CreateCall(Callee, Ops);
}
- case WebAssembly::BI__builtin_wasm_fma_f32x4:
- case WebAssembly::BI__builtin_wasm_fms_f32x4:
- case WebAssembly::BI__builtin_wasm_fma_f64x2:
- case WebAssembly::BI__builtin_wasm_fms_f64x2: {
+ case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4:
+ case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4:
+ case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2:
+ case WebAssembly::BI__builtin_wasm_relaxed_nmadd_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_fma_f32x4:
- case WebAssembly::BI__builtin_wasm_fma_f64x2:
- IntNo = Intrinsic::wasm_fma;
+ case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4:
+ case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2:
+ IntNo = Intrinsic::wasm_relaxed_madd;
break;
- case WebAssembly::BI__builtin_wasm_fms_f32x4:
- case WebAssembly::BI__builtin_wasm_fms_f64x2:
- IntNo = Intrinsic::wasm_fms;
+ case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4:
+ case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2:
+ IntNo = Intrinsic::wasm_relaxed_nmadd;
break;
default:
llvm_unreachable("unexpected builtin ID");
@@ -18746,15 +19095,15 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Function *Callee = CGM.getIntrinsic(IntNo, A->getType());
return Builder.CreateCall(Callee, {A, B, C});
}
- case WebAssembly::BI__builtin_wasm_laneselect_i8x16:
- case WebAssembly::BI__builtin_wasm_laneselect_i16x8:
- case WebAssembly::BI__builtin_wasm_laneselect_i32x4:
- case WebAssembly::BI__builtin_wasm_laneselect_i64x2: {
+ case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i8x16:
+ case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i16x8:
+ case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i32x4:
+ case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i64x2: {
Value *A = EmitScalarExpr(E->getArg(0));
Value *B = EmitScalarExpr(E->getArg(1));
Value *C = EmitScalarExpr(E->getArg(2));
Function *Callee =
- CGM.getIntrinsic(Intrinsic::wasm_laneselect, A->getType());
+ CGM.getIntrinsic(Intrinsic::wasm_relaxed_laneselect, A->getType());
return Builder.CreateCall(Callee, {A, B, C});
}
case WebAssembly::BI__builtin_wasm_relaxed_swizzle_i8x16: {
@@ -18816,18 +19165,27 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_q15mulr_signed);
return Builder.CreateCall(Callee, {LHS, RHS});
}
- case WebAssembly::BI__builtin_wasm_dot_i8x16_i7x16_s_i16x8: {
+ case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8: {
Value *LHS = EmitScalarExpr(E->getArg(0));
Value *RHS = EmitScalarExpr(E->getArg(1));
- Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_dot_i8x16_i7x16_signed);
+ Function *Callee =
+ CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_signed);
return Builder.CreateCall(Callee, {LHS, RHS});
}
- case WebAssembly::BI__builtin_wasm_dot_i8x16_i7x16_add_s_i32x4: {
+ case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4: {
Value *LHS = EmitScalarExpr(E->getArg(0));
Value *RHS = EmitScalarExpr(E->getArg(1));
Value *Acc = EmitScalarExpr(E->getArg(2));
Function *Callee =
- CGM.getIntrinsic(Intrinsic::wasm_dot_i8x16_i7x16_add_signed);
+ CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_add_signed);
+ return Builder.CreateCall(Callee, {LHS, RHS, Acc});
+ }
+ case WebAssembly::BI__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4: {
+ Value *LHS = EmitScalarExpr(E->getArg(0));
+ Value *RHS = EmitScalarExpr(E->getArg(1));
+ Value *Acc = EmitScalarExpr(E->getArg(2));
+ Function *Callee =
+ CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_bf16x8_add_f32);
return Builder.CreateCall(Callee, {LHS, RHS, Acc});
}
default:
@@ -18842,7 +19200,7 @@ getIntrinsicForHexagonNonClangBuiltin(unsigned BuiltinID) {
Intrinsic::ID IntrinsicID;
unsigned VecLen;
};
- Info Infos[] = {
+ static Info Infos[] = {
#define CUSTOM_BUILTIN_MAPPING(x,s) \
{ Hexagon::BI__builtin_HEXAGON_##x, Intrinsic::hexagon_##x, s },
CUSTOM_BUILTIN_MAPPING(L2_loadrub_pci, 0)
@@ -18884,8 +19242,7 @@ getIntrinsicForHexagonNonClangBuiltin(unsigned BuiltinID) {
static const bool SortOnce = (llvm::sort(Infos, CmpInfo), true);
(void)SortOnce;
- const Info *F = std::lower_bound(std::begin(Infos), std::end(Infos),
- Info{BuiltinID, 0, 0}, CmpInfo);
+ const Info *F = llvm::lower_bound(Infos, Info{BuiltinID, 0, 0}, CmpInfo);
if (F == std::end(Infos) || F->BuiltinID != BuiltinID)
return {Intrinsic::not_intrinsic, 0};
@@ -19004,6 +19361,25 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
PredAddr.getAlignment());
return Builder.CreateExtractValue(Result, 0);
}
+ // These are identical to the builtins above, except they don't consume
+ // input carry, only generate carry-out. Since they still produce two
+ // outputs, generate the store of the predicate, but no load.
+ case Hexagon::BI__builtin_HEXAGON_V6_vaddcarryo:
+ case Hexagon::BI__builtin_HEXAGON_V6_vaddcarryo_128B:
+ case Hexagon::BI__builtin_HEXAGON_V6_vsubcarryo:
+ case Hexagon::BI__builtin_HEXAGON_V6_vsubcarryo_128B: {
+ // Get the type from the 0-th argument.
+ llvm::Type *VecType = ConvertType(E->getArg(0)->getType());
+ Address PredAddr = Builder.CreateElementBitCast(
+ EmitPointerWithAlignment(E->getArg(2)), VecType);
+ llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID),
+ {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1))});
+
+ llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1);
+ Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.getPointer(),
+ PredAddr.getAlignment());
+ return Builder.CreateExtractValue(Result, 0);
+ }
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstoreq:
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorenq:
@@ -19104,7 +19480,12 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
Intrinsic::ID ID = Intrinsic::not_intrinsic;
unsigned NF = 1;
- constexpr unsigned TAIL_UNDISTURBED = 0;
+ // The 0th bit simulates the `vta` of RVV
+ // The 1st bit simulates the `vma` of RVV
+ constexpr unsigned RVV_VTA = 0x1;
+ constexpr unsigned RVV_VMA = 0x2;
+ int PolicyAttrs = 0;
+ bool IsMasked = false;
// Required for overloaded intrinsics.
llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes;
@@ -19119,38 +19500,8 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
case RISCV::BI__builtin_riscv_clmul:
case RISCV::BI__builtin_riscv_clmulh:
case RISCV::BI__builtin_riscv_clmulr:
- case RISCV::BI__builtin_riscv_bcompress_32:
- case RISCV::BI__builtin_riscv_bcompress_64:
- case RISCV::BI__builtin_riscv_bdecompress_32:
- case RISCV::BI__builtin_riscv_bdecompress_64:
- case RISCV::BI__builtin_riscv_bfp_32:
- case RISCV::BI__builtin_riscv_bfp_64:
- case RISCV::BI__builtin_riscv_grev_32:
- case RISCV::BI__builtin_riscv_grev_64:
- case RISCV::BI__builtin_riscv_gorc_32:
- case RISCV::BI__builtin_riscv_gorc_64:
- case RISCV::BI__builtin_riscv_shfl_32:
- case RISCV::BI__builtin_riscv_shfl_64:
- case RISCV::BI__builtin_riscv_unshfl_32:
- case RISCV::BI__builtin_riscv_unshfl_64:
case RISCV::BI__builtin_riscv_xperm4:
case RISCV::BI__builtin_riscv_xperm8:
- case RISCV::BI__builtin_riscv_xperm_n:
- case RISCV::BI__builtin_riscv_xperm_b:
- case RISCV::BI__builtin_riscv_xperm_h:
- case RISCV::BI__builtin_riscv_xperm_w:
- case RISCV::BI__builtin_riscv_crc32_b:
- case RISCV::BI__builtin_riscv_crc32_h:
- case RISCV::BI__builtin_riscv_crc32_w:
- case RISCV::BI__builtin_riscv_crc32_d:
- case RISCV::BI__builtin_riscv_crc32c_b:
- case RISCV::BI__builtin_riscv_crc32c_h:
- case RISCV::BI__builtin_riscv_crc32c_w:
- case RISCV::BI__builtin_riscv_crc32c_d:
- case RISCV::BI__builtin_riscv_fsl_32:
- case RISCV::BI__builtin_riscv_fsr_32:
- case RISCV::BI__builtin_riscv_fsl_64:
- case RISCV::BI__builtin_riscv_fsr_64:
case RISCV::BI__builtin_riscv_brev8:
case RISCV::BI__builtin_riscv_zip_32:
case RISCV::BI__builtin_riscv_unzip_32: {
@@ -19183,88 +19534,6 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
ID = Intrinsic::riscv_clmulr;
break;
- // Zbe
- case RISCV::BI__builtin_riscv_bcompress_32:
- case RISCV::BI__builtin_riscv_bcompress_64:
- ID = Intrinsic::riscv_bcompress;
- break;
- case RISCV::BI__builtin_riscv_bdecompress_32:
- case RISCV::BI__builtin_riscv_bdecompress_64:
- ID = Intrinsic::riscv_bdecompress;
- break;
-
- // Zbf
- case RISCV::BI__builtin_riscv_bfp_32:
- case RISCV::BI__builtin_riscv_bfp_64:
- ID = Intrinsic::riscv_bfp;
- break;
-
- // Zbp
- case RISCV::BI__builtin_riscv_grev_32:
- case RISCV::BI__builtin_riscv_grev_64:
- ID = Intrinsic::riscv_grev;
- break;
- case RISCV::BI__builtin_riscv_gorc_32:
- case RISCV::BI__builtin_riscv_gorc_64:
- ID = Intrinsic::riscv_gorc;
- break;
- case RISCV::BI__builtin_riscv_shfl_32:
- case RISCV::BI__builtin_riscv_shfl_64:
- ID = Intrinsic::riscv_shfl;
- break;
- case RISCV::BI__builtin_riscv_unshfl_32:
- case RISCV::BI__builtin_riscv_unshfl_64:
- ID = Intrinsic::riscv_unshfl;
- break;
- case RISCV::BI__builtin_riscv_xperm_n:
- ID = Intrinsic::riscv_xperm_n;
- break;
- case RISCV::BI__builtin_riscv_xperm_b:
- ID = Intrinsic::riscv_xperm_b;
- break;
- case RISCV::BI__builtin_riscv_xperm_h:
- ID = Intrinsic::riscv_xperm_h;
- break;
- case RISCV::BI__builtin_riscv_xperm_w:
- ID = Intrinsic::riscv_xperm_w;
- break;
-
- // Zbr
- case RISCV::BI__builtin_riscv_crc32_b:
- ID = Intrinsic::riscv_crc32_b;
- break;
- case RISCV::BI__builtin_riscv_crc32_h:
- ID = Intrinsic::riscv_crc32_h;
- break;
- case RISCV::BI__builtin_riscv_crc32_w:
- ID = Intrinsic::riscv_crc32_w;
- break;
- case RISCV::BI__builtin_riscv_crc32_d:
- ID = Intrinsic::riscv_crc32_d;
- break;
- case RISCV::BI__builtin_riscv_crc32c_b:
- ID = Intrinsic::riscv_crc32c_b;
- break;
- case RISCV::BI__builtin_riscv_crc32c_h:
- ID = Intrinsic::riscv_crc32c_h;
- break;
- case RISCV::BI__builtin_riscv_crc32c_w:
- ID = Intrinsic::riscv_crc32c_w;
- break;
- case RISCV::BI__builtin_riscv_crc32c_d:
- ID = Intrinsic::riscv_crc32c_d;
- break;
-
- // Zbt
- case RISCV::BI__builtin_riscv_fsl_32:
- case RISCV::BI__builtin_riscv_fsl_64:
- ID = Intrinsic::riscv_fsl;
- break;
- case RISCV::BI__builtin_riscv_fsr_32:
- case RISCV::BI__builtin_riscv_fsr_64:
- ID = Intrinsic::riscv_fsr;
- break;
-
// Zbkx
case RISCV::BI__builtin_riscv_xperm8:
ID = Intrinsic::riscv_xperm8;
@@ -19407,3 +19676,129 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
return Builder.CreateCall(F, Ops, "");
}
+
+Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ SmallVector<Value *, 4> Ops;
+
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; i++)
+ Ops.push_back(EmitScalarExpr(E->getArg(i)));
+
+ Intrinsic::ID ID = Intrinsic::not_intrinsic;
+
+ switch (BuiltinID) {
+ default:
+ llvm_unreachable("unexpected builtin ID.");
+ case LoongArch::BI__builtin_loongarch_cacop_d:
+ ID = Intrinsic::loongarch_cacop_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_cacop_w:
+ ID = Intrinsic::loongarch_cacop_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_dbar:
+ ID = Intrinsic::loongarch_dbar;
+ break;
+ case LoongArch::BI__builtin_loongarch_break:
+ ID = Intrinsic::loongarch_break;
+ break;
+ case LoongArch::BI__builtin_loongarch_ibar:
+ ID = Intrinsic::loongarch_ibar;
+ break;
+ case LoongArch::BI__builtin_loongarch_movfcsr2gr:
+ ID = Intrinsic::loongarch_movfcsr2gr;
+ break;
+ case LoongArch::BI__builtin_loongarch_movgr2fcsr:
+ ID = Intrinsic::loongarch_movgr2fcsr;
+ break;
+ case LoongArch::BI__builtin_loongarch_syscall:
+ ID = Intrinsic::loongarch_syscall;
+ break;
+ case LoongArch::BI__builtin_loongarch_crc_w_b_w:
+ ID = Intrinsic::loongarch_crc_w_b_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_crc_w_h_w:
+ ID = Intrinsic::loongarch_crc_w_h_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_crc_w_w_w:
+ ID = Intrinsic::loongarch_crc_w_w_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_crc_w_d_w:
+ ID = Intrinsic::loongarch_crc_w_d_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_crcc_w_b_w:
+ ID = Intrinsic::loongarch_crcc_w_b_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_crcc_w_h_w:
+ ID = Intrinsic::loongarch_crcc_w_h_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_crcc_w_w_w:
+ ID = Intrinsic::loongarch_crcc_w_w_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_crcc_w_d_w:
+ ID = Intrinsic::loongarch_crcc_w_d_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrrd_w:
+ ID = Intrinsic::loongarch_csrrd_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrwr_w:
+ ID = Intrinsic::loongarch_csrwr_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrxchg_w:
+ ID = Intrinsic::loongarch_csrxchg_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrrd_d:
+ ID = Intrinsic::loongarch_csrrd_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrwr_d:
+ ID = Intrinsic::loongarch_csrwr_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_csrxchg_d:
+ ID = Intrinsic::loongarch_csrxchg_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_iocsrrd_b:
+ ID = Intrinsic::loongarch_iocsrrd_b;
+ break;
+ case LoongArch::BI__builtin_loongarch_iocsrrd_h:
+ ID = Intrinsic::loongarch_iocsrrd_h;
+ break;
+ case LoongArch::BI__builtin_loongarch_iocsrrd_w:
+ ID = Intrinsic::loongarch_iocsrrd_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_iocsrrd_d:
+ ID = Intrinsic::loongarch_iocsrrd_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_iocsrwr_b:
+ ID = Intrinsic::loongarch_iocsrwr_b;
+ break;
+ case LoongArch::BI__builtin_loongarch_iocsrwr_h:
+ ID = Intrinsic::loongarch_iocsrwr_h;
+ break;
+ case LoongArch::BI__builtin_loongarch_iocsrwr_w:
+ ID = Intrinsic::loongarch_iocsrwr_w;
+ break;
+ case LoongArch::BI__builtin_loongarch_iocsrwr_d:
+ ID = Intrinsic::loongarch_iocsrwr_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_cpucfg:
+ ID = Intrinsic::loongarch_cpucfg;
+ break;
+ case LoongArch::BI__builtin_loongarch_asrtle_d:
+ ID = Intrinsic::loongarch_asrtle_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_asrtgt_d:
+ ID = Intrinsic::loongarch_asrtgt_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_lddir_d:
+ ID = Intrinsic::loongarch_lddir_d;
+ break;
+ case LoongArch::BI__builtin_loongarch_ldpte_d:
+ ID = Intrinsic::loongarch_ldpte_d;
+ break;
+ // TODO: Support more Intrinsics.
+ }
+
+ assert(ID != Intrinsic::not_intrinsic);
+
+ llvm::Function *F = CGM.getIntrinsic(ID);
+ return Builder.CreateCall(F, Ops);
+}
diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp
index a8bb0dd65d1a..bb887df3e4e0 100644
--- a/clang/lib/CodeGen/CGCUDANV.cpp
+++ b/clang/lib/CodeGen/CGCUDANV.cpp
@@ -49,10 +49,10 @@ private:
const Decl *D;
};
llvm::SmallVector<KernelInfo, 16> EmittedKernels;
- // Map a device stub function to a symbol for identifying kernel in host code.
+ // Map a kernel mangled name to a symbol for identifying kernel in host code
// For CUDA, the symbol for identifying the kernel is the same as the device
// stub function. For HIP, they are different.
- llvm::DenseMap<llvm::Function *, llvm::GlobalValue *> KernelHandles;
+ llvm::DenseMap<StringRef, llvm::GlobalValue *> KernelHandles;
// Map a kernel handle to the kernel stub.
llvm::DenseMap<llvm::GlobalValue *, llvm::Function *> KernelStubs;
struct VarInfo {
@@ -69,6 +69,8 @@ private:
bool RelocatableDeviceCode;
/// Mangle context for device.
std::unique_ptr<MangleContext> DeviceMC;
+ /// Some zeros used for GEPs.
+ llvm::Constant *Zeros[2];
llvm::FunctionCallee getSetupArgumentFn() const;
llvm::FunctionCallee getLaunchFn() const;
@@ -86,14 +88,25 @@ private:
/// the start of the string. The result of this function can be used anywhere
/// where the C code specifies const char*.
llvm::Constant *makeConstantString(const std::string &Str,
- const std::string &Name = "",
- const std::string &SectionName = "",
- unsigned Alignment = 0) {
- llvm::Constant *Zeros[] = {llvm::ConstantInt::get(SizeTy, 0),
- llvm::ConstantInt::get(SizeTy, 0)};
+ const std::string &Name = "") {
auto ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str());
- llvm::GlobalVariable *GV =
- cast<llvm::GlobalVariable>(ConstStr.getPointer());
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr.getElementType(),
+ ConstStr.getPointer(), Zeros);
+ }
+
+ /// Helper function which generates an initialized constant array from Str,
+ /// and optionally sets section name and alignment. AddNull specifies whether
+ /// the array should nave NUL termination.
+ llvm::Constant *makeConstantArray(StringRef Str,
+ StringRef Name = "",
+ StringRef SectionName = "",
+ unsigned Alignment = 0,
+ bool AddNull = false) {
+ llvm::Constant *Value =
+ llvm::ConstantDataArray::getString(Context, Str, AddNull);
+ auto *GV = new llvm::GlobalVariable(
+ TheModule, Value->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Value, Name);
if (!SectionName.empty()) {
GV->setSection(SectionName);
// Mark the address as used which make sure that this section isn't
@@ -102,9 +115,7 @@ private:
}
if (Alignment)
GV->setAlignment(llvm::Align(Alignment));
-
- return llvm::ConstantExpr::getGetElementPtr(ConstStr.getElementType(),
- ConstStr.getPointer(), Zeros);
+ return llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros);
}
/// Helper function that generates an empty dummy function returning void.
@@ -220,6 +231,8 @@ CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM)
IntTy = CGM.IntTy;
SizeTy = CGM.SizeTy;
VoidTy = CGM.VoidTy;
+ Zeros[0] = llvm::ConstantInt::get(SizeTy, 0);
+ Zeros[1] = Zeros[0];
CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy));
VoidPtrTy = cast<llvm::PointerType>(Types.ConvertType(Ctx.VoidPtrTy));
@@ -297,7 +310,8 @@ std::string CGNVCUDARuntime::getDeviceSideName(const NamedDecl *ND) {
void CGNVCUDARuntime::emitDeviceStub(CodeGenFunction &CGF,
FunctionArgList &Args) {
EmittedKernels.push_back({CGF.CurFn, CGF.CurFuncDecl});
- if (auto *GV = dyn_cast<llvm::GlobalVariable>(KernelHandles[CGF.CurFn])) {
+ if (auto *GV =
+ dyn_cast<llvm::GlobalVariable>(KernelHandles[CGF.CurFn->getName()])) {
GV->setLinkage(CGF.CurFn->getLinkage());
GV->setInitializer(CGF.CurFn);
}
@@ -387,8 +401,8 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
ShmemSize.getPointer(), Stream.getPointer()});
// Emit the call to cudaLaunch
- llvm::Value *Kernel =
- CGF.Builder.CreatePointerCast(KernelHandles[CGF.CurFn], VoidPtrTy);
+ llvm::Value *Kernel = CGF.Builder.CreatePointerCast(
+ KernelHandles[CGF.CurFn->getName()], VoidPtrTy);
CallArgList LaunchKernelArgs;
LaunchKernelArgs.add(RValue::get(Kernel),
cudaLaunchKernelFD->getParamDecl(0)->getType());
@@ -443,8 +457,8 @@ void CGNVCUDARuntime::emitDeviceStubBodyLegacy(CodeGenFunction &CGF,
// Emit the call to cudaLaunch
llvm::FunctionCallee cudaLaunchFn = getLaunchFn();
- llvm::Value *Arg =
- CGF.Builder.CreatePointerCast(KernelHandles[CGF.CurFn], CharPtrTy);
+ llvm::Value *Arg = CGF.Builder.CreatePointerCast(
+ KernelHandles[CGF.CurFn->getName()], CharPtrTy);
CGF.EmitRuntimeCallOrInvoke(cudaLaunchFn, Arg);
CGF.EmitBranch(EndBlock);
@@ -538,7 +552,7 @@ llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() {
llvm::Constant *NullPtr = llvm::ConstantPointerNull::get(VoidPtrTy);
llvm::Value *Args[] = {
&GpuBinaryHandlePtr,
- Builder.CreateBitCast(KernelHandles[I.Kernel], VoidPtrTy),
+ Builder.CreateBitCast(KernelHandles[I.Kernel->getName()], VoidPtrTy),
KernelName,
KernelName,
llvm::ConstantInt::get(IntTy, -1),
@@ -744,9 +758,8 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
// If fatbin is available from early finalization, create a string
// literal containing the fat binary loaded from the given file.
const unsigned HIPCodeObjectAlign = 4096;
- FatBinStr =
- makeConstantString(std::string(CudaGpuBinary->getBuffer()), "",
- FatbinConstantName, HIPCodeObjectAlign);
+ FatBinStr = makeConstantArray(std::string(CudaGpuBinary->getBuffer()), "",
+ FatbinConstantName, HIPCodeObjectAlign);
} else {
// If fatbin is not available, create an external symbol
// __hip_fatbin in section .hip_fatbin. The external symbol is supposed
@@ -780,8 +793,8 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
// For CUDA, create a string literal containing the fat binary loaded from
// the given file.
- FatBinStr = makeConstantString(std::string(CudaGpuBinary->getBuffer()), "",
- FatbinConstantName, 8);
+ FatBinStr = makeConstantArray(std::string(CudaGpuBinary->getBuffer()), "",
+ FatbinConstantName, 8);
FatMagic = CudaFatMagic;
}
@@ -888,8 +901,8 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
SmallString<64> ModuleID;
llvm::raw_svector_ostream OS(ModuleID);
OS << ModuleIDPrefix << llvm::format("%" PRIx64, FatbinWrapper->getGUID());
- llvm::Constant *ModuleIDConstant = makeConstantString(
- std::string(ModuleID.str()), "", ModuleIDSectionName, 32);
+ llvm::Constant *ModuleIDConstant = makeConstantArray(
+ std::string(ModuleID.str()), "", ModuleIDSectionName, 32, /*AddNull=*/true);
// Create an alias for the FatbinWrapper that nvcc will look for.
llvm::GlobalAlias::create(llvm::GlobalValue::ExternalLinkage,
@@ -1118,7 +1131,7 @@ void CGNVCUDARuntime::createOffloadingEntries() {
StringRef Section = CGM.getLangOpts().HIP ? "hip_offloading_entries"
: "cuda_offloading_entries";
for (KernelInfo &I : EmittedKernels)
- OMPBuilder.emitOffloadingEntry(KernelHandles[I.Kernel],
+ OMPBuilder.emitOffloadingEntry(KernelHandles[I.Kernel->getName()],
getDeviceSideName(cast<NamedDecl>(I.D)), 0,
DeviceVarFlags::OffloadGlobalEntry, Section);
@@ -1181,12 +1194,12 @@ llvm::Function *CGNVCUDARuntime::finalizeModule() {
llvm::GlobalValue *CGNVCUDARuntime::getKernelHandle(llvm::Function *F,
GlobalDecl GD) {
- auto Loc = KernelHandles.find(F);
+ auto Loc = KernelHandles.find(F->getName());
if (Loc != KernelHandles.end())
return Loc->second;
if (!CGM.getLangOpts().HIP) {
- KernelHandles[F] = F;
+ KernelHandles[F->getName()] = F;
KernelStubs[F] = F;
return F;
}
@@ -1200,7 +1213,7 @@ llvm::GlobalValue *CGNVCUDARuntime::getKernelHandle(llvm::Function *F,
Var->setDSOLocal(F->isDSOLocal());
Var->setVisibility(F->getVisibility());
CGM.maybeSetTrivialComdat(*GD.getDecl(), *Var);
- KernelHandles[F] = Var;
+ KernelHandles[F->getName()] = Var;
KernelStubs[Var] = F;
return Var;
}
diff --git a/clang/lib/CodeGen/CGCUDARuntime.h b/clang/lib/CodeGen/CGCUDARuntime.h
index 73c7ca7bc15f..9a9c6d26cc63 100644
--- a/clang/lib/CodeGen/CGCUDARuntime.h
+++ b/clang/lib/CodeGen/CGCUDARuntime.h
@@ -55,7 +55,7 @@ public:
/// The kind flag for an offloading entry.
enum OffloadEntryKindFlag : uint32_t {
/// Mark the entry as a global entry. This indicates the presense of a
- /// kernel if the size size field is zero and a variable otherwise.
+ /// kernel if the size field is zero and a variable otherwise.
OffloadGlobalEntry = 0x0,
/// Mark the entry as a managed global variable.
OffloadGlobalManagedEntry = 0x1,
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index 0768e6581acb..a600768b2074 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -105,6 +105,10 @@ protected:
/// final class will have been taken care of by the caller.
virtual bool isThisCompleteObject(GlobalDecl GD) const = 0;
+ virtual bool constructorsAndDestructorsReturnThis() const {
+ return CGM.getCodeGenOpts().CtorDtorReturnThis;
+ }
+
public:
virtual ~CGCXXABI();
@@ -120,7 +124,13 @@ public:
///
/// There currently is no way to indicate if a destructor returns 'this'
/// when called virtually, and code generation does not support the case.
- virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
+ virtual bool HasThisReturn(GlobalDecl GD) const {
+ if (isa<CXXConstructorDecl>(GD.getDecl()) ||
+ (isa<CXXDestructorDecl>(GD.getDecl()) &&
+ GD.getDtorType() != Dtor_Deleting))
+ return constructorsAndDestructorsReturnThis();
+ return false;
+ }
virtual bool hasMostDerivedReturn(GlobalDecl GD) const { return false; }
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index dfa78bf59c65..dfa552161d7c 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -40,6 +40,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
#include "llvm/Transforms/Utils/Local.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -112,7 +113,7 @@ CodeGenTypes::arrangeFreeFunctionType(CanQual<FunctionNoProtoType> FTNP) {
// variadic type.
return arrangeLLVMFunctionInfo(FTNP->getReturnType().getUnqualifiedType(),
/*instanceMethod=*/false,
- /*chainCall=*/false, None,
+ /*chainCall=*/false, std::nullopt,
FTNP->getExtInfo(), {}, RequiredArgs(0));
}
@@ -459,7 +460,8 @@ CodeGenTypes::arrangeFunctionDeclaration(const FunctionDecl *FD) {
if (CanQual<FunctionNoProtoType> noProto = FTy.getAs<FunctionNoProtoType>()) {
return arrangeLLVMFunctionInfo(
noProto->getReturnType(), /*instanceMethod=*/false,
- /*chainCall=*/false, None, noProto->getExtInfo(), {},RequiredArgs::All);
+ /*chainCall=*/false, std::nullopt, noProto->getExtInfo(), {},
+ RequiredArgs::All);
}
return arrangeFreeFunctionType(FTy.castAs<FunctionProtoType>());
@@ -484,9 +486,11 @@ const CGFunctionInfo &
CodeGenTypes::arrangeObjCMessageSendSignature(const ObjCMethodDecl *MD,
QualType receiverType) {
SmallVector<CanQualType, 16> argTys;
- SmallVector<FunctionProtoType::ExtParameterInfo, 4> extParamInfos(2);
+ SmallVector<FunctionProtoType::ExtParameterInfo, 4> extParamInfos(
+ MD->isDirectMethod() ? 1 : 2);
argTys.push_back(Context.getCanonicalParamType(receiverType));
- argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
+ if (!MD->isDirectMethod())
+ argTys.push_back(Context.getCanonicalParamType(Context.getObjCSelType()));
// FIXME: Kill copy?
for (const auto *I : MD->parameters()) {
argTys.push_back(Context.getCanonicalParamType(I->getType()));
@@ -708,7 +712,7 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
const CGFunctionInfo &CodeGenTypes::arrangeNullaryFunction() {
return arrangeLLVMFunctionInfo(
getContext().VoidTy, /*instanceMethod=*/false, /*chainCall=*/false,
- None, FunctionType::ExtInfo(), {}, RequiredArgs::All);
+ std::nullopt, FunctionType::ExtInfo(), {}, RequiredArgs::All);
}
const CGFunctionInfo &
@@ -1144,7 +1148,7 @@ static Address CreateTempAllocaForCoercion(CodeGenFunction &CGF, llvm::Type *Ty,
CharUnits MinAlign,
const Twine &Name = "tmp") {
// Don't use an alignment that's worse than what LLVM would prefer.
- auto PrefAlign = CGF.CGM.getDataLayout().getPrefTypeAlignment(Ty);
+ auto PrefAlign = CGF.CGM.getDataLayout().getPrefTypeAlign(Ty);
CharUnits Align = std::max(MinAlign, CharUnits::fromQuantity(PrefAlign));
return CGF.CreateTempAlloca(Ty, Align, Name + ".coerce");
@@ -1257,7 +1261,7 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) {
Src = EnterStructPointerForCoercedAccess(Src, SrcSTy,
- DstSize.getFixedSize(), CGF);
+ DstSize.getFixedValue(), CGF);
SrcTy = Src.getElementType();
}
@@ -1273,7 +1277,7 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
// If load is legal, just bitcast the src pointer.
if (!SrcSize.isScalable() && !DstSize.isScalable() &&
- SrcSize.getFixedSize() >= DstSize.getFixedSize()) {
+ SrcSize.getFixedValue() >= DstSize.getFixedValue()) {
// Generally SrcSize is never greater than DstSize, since this means we are
// losing bits. However, this can happen in cases where the structure has
// additional padding, for example due to a user specified alignment.
@@ -1319,7 +1323,7 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
CGF.Builder.CreateMemCpy(
Tmp.getPointer(), Tmp.getAlignment().getAsAlign(), Src.getPointer(),
Src.getAlignment().getAsAlign(),
- llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize.getKnownMinSize()));
+ llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize.getKnownMinValue()));
return CGF.Builder.CreateLoad(Tmp);
}
@@ -1362,7 +1366,7 @@ static void CreateCoercedStore(llvm::Value *Src,
if (llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) {
Dst = EnterStructPointerForCoercedAccess(Dst, DstSTy,
- SrcSize.getFixedSize(), CGF);
+ SrcSize.getFixedValue(), CGF);
DstTy = Dst.getElementType();
}
@@ -1389,7 +1393,7 @@ static void CreateCoercedStore(llvm::Value *Src,
// If store is legal, just bitcast the src pointer.
if (isa<llvm::ScalableVectorType>(SrcTy) ||
isa<llvm::ScalableVectorType>(DstTy) ||
- SrcSize.getFixedSize() <= DstSize.getFixedSize()) {
+ SrcSize.getFixedValue() <= DstSize.getFixedValue()) {
Dst = CGF.Builder.CreateElementBitCast(Dst, SrcTy);
CGF.EmitAggregateStore(Src, Dst, DstIsVolatile);
} else {
@@ -1407,7 +1411,7 @@ static void CreateCoercedStore(llvm::Value *Src,
CGF.Builder.CreateMemCpy(
Dst.getPointer(), Dst.getAlignment().getAsAlign(), Tmp.getPointer(),
Tmp.getAlignment().getAsAlign(),
- llvm::ConstantInt::get(CGF.IntPtrTy, DstSize.getFixedSize()));
+ llvm::ConstantInt::get(CGF.IntPtrTy, DstSize.getFixedValue()));
}
}
@@ -1633,7 +1637,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
// sret things on win32 aren't void, they return the sret pointer.
QualType ret = FI.getReturnType();
llvm::Type *ty = ConvertType(ret);
- unsigned addressSpace = Context.getTargetAddressSpace(ret);
+ unsigned addressSpace = CGM.getTypes().getTargetAddressSpace(ret);
resultType = llvm::PointerType::get(ty, addressSpace);
} else {
resultType = llvm::Type::getVoidTy(getLLVMContext());
@@ -1657,7 +1661,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
if (IRFunctionArgs.hasSRetArg()) {
QualType Ret = FI.getReturnType();
llvm::Type *Ty = ConvertType(Ret);
- unsigned AddressSpace = Context.getTargetAddressSpace(Ret);
+ unsigned AddressSpace = CGM.getTypes().getTargetAddressSpace(Ret);
ArgTypes[IRFunctionArgs.getSRetArgNo()] =
llvm::PointerType::get(Ty, AddressSpace);
}
@@ -1723,7 +1727,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
case ABIArgInfo::CoerceAndExpand: {
auto ArgTypesIter = ArgTypes.begin() + FirstIRArg;
- for (auto EltTy : ArgInfo.getCoerceAndExpandTypeSequence()) {
+ for (auto *EltTy : ArgInfo.getCoerceAndExpandTypeSequence()) {
*ArgTypesIter++ = EltTy;
}
assert(ArgTypesIter == ArgTypes.begin() + FirstIRArg + NumIRArgs);
@@ -1781,7 +1785,7 @@ static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs,
}
bool CodeGenModule::MayDropFunctionReturn(const ASTContext &Context,
- QualType ReturnType) {
+ QualType ReturnType) const {
// We can't just discard the return value for a record type with a
// complex destructor or a non-trivially copyable type.
if (const RecordType *RT =
@@ -1792,6 +1796,38 @@ bool CodeGenModule::MayDropFunctionReturn(const ASTContext &Context,
return ReturnType.isTriviallyCopyableType(Context);
}
+static bool HasStrictReturn(const CodeGenModule &Module, QualType RetTy,
+ const Decl *TargetDecl) {
+ // As-is msan can not tolerate noundef mismatch between caller and
+ // implementation. Mismatch is possible for e.g. indirect calls from C-caller
+ // into C++. Such mismatches lead to confusing false reports. To avoid
+ // expensive workaround on msan we enforce initialization event in uncommon
+ // cases where it's allowed.
+ if (Module.getLangOpts().Sanitize.has(SanitizerKind::Memory))
+ return true;
+ // C++ explicitly makes returning undefined values UB. C's rule only applies
+ // to used values, so we never mark them noundef for now.
+ if (!Module.getLangOpts().CPlusPlus)
+ return false;
+ if (TargetDecl) {
+ if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(TargetDecl)) {
+ if (FDecl->isExternC())
+ return false;
+ } else if (const VarDecl *VDecl = dyn_cast<VarDecl>(TargetDecl)) {
+ // Function pointer.
+ if (VDecl->isExternC())
+ return false;
+ }
+ }
+
+ // We don't want to be too aggressive with the return checking, unless
+ // it's explicit in the code opts or we're using an appropriate sanitizer.
+ // Try to respect what the programmer intended.
+ return Module.getCodeGenOpts().StrictReturn ||
+ !Module.MayDropFunctionReturn(Module.getContext(), RetTy) ||
+ Module.getLangOpts().Sanitize.has(SanitizerKind::Return);
+}
+
void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
bool HasOptnone,
bool AttrOnCallSite,
@@ -1820,19 +1856,16 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
if (!CodeGenOpts.TrapFuncName.empty())
FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName);
} else {
- StringRef FpKind;
switch (CodeGenOpts.getFramePointer()) {
case CodeGenOptions::FramePointerKind::None:
- FpKind = "none";
+ // This is the default behavior.
break;
case CodeGenOptions::FramePointerKind::NonLeaf:
- FpKind = "non-leaf";
- break;
case CodeGenOptions::FramePointerKind::All:
- FpKind = "all";
- break;
+ FuncAttrs.addAttribute("frame-pointer",
+ CodeGenOptions::getFramePointerKindName(
+ CodeGenOpts.getFramePointer()));
}
- FuncAttrs.addAttribute("frame-pointer", FpKind);
if (CodeGenOpts.LessPreciseFPMAD)
FuncAttrs.addAttribute("less-precise-fpmad", "true");
@@ -1860,7 +1893,12 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
FuncAttrs.addAttribute("no-nans-fp-math", "true");
if (LangOpts.ApproxFunc)
FuncAttrs.addAttribute("approx-func-fp-math", "true");
- if (LangOpts.UnsafeFPMath)
+ if (LangOpts.AllowFPReassoc && LangOpts.AllowRecip &&
+ LangOpts.NoSignedZero && LangOpts.ApproxFunc &&
+ (LangOpts.getDefaultFPContractMode() ==
+ LangOptions::FPModeKind::FPM_Fast ||
+ LangOpts.getDefaultFPContractMode() ==
+ LangOptions::FPModeKind::FPM_FastHonorPragmas))
FuncAttrs.addAttribute("unsafe-fp-math", "true");
if (CodeGenOpts.SoftFloat)
FuncAttrs.addAttribute("use-soft-float", "true");
@@ -1931,11 +1969,11 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
}
- // TODO: NoUnwind attribute should be added for other GPU modes OpenCL, HIP,
+ // TODO: NoUnwind attribute should be added for other GPU modes HIP,
// SYCL, OpenMP offload. AFAIK, none of them support exceptions in device
// code.
- if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
- // Exceptions aren't supported in CUDA device code.
+ if ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice) ||
+ getLangOpts().OpenCL) {
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}
@@ -2046,6 +2084,27 @@ static bool DetermineNoUndef(QualType QTy, CodeGenTypes &Types,
return false;
}
+/// Check if the argument of a function has maybe_undef attribute.
+static bool IsArgumentMaybeUndef(const Decl *TargetDecl,
+ unsigned NumRequiredArgs, unsigned ArgNo) {
+ const auto *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl);
+ if (!FD)
+ return false;
+
+ // Assume variadic arguments do not have maybe_undef attribute.
+ if (ArgNo >= NumRequiredArgs)
+ return false;
+
+ // Check if argument has maybe_undef attribute.
+ if (ArgNo < FD->getNumParams()) {
+ const ParmVarDecl *Param = FD->getParamDecl(ArgNo);
+ if (Param && Param->hasAttr<MaybeUndefAttr>())
+ return true;
+ }
+
+ return false;
+}
+
/// Construct the IR attribute list of a function or call.
///
/// When adding an attribute, please consider where it should be handled:
@@ -2094,6 +2153,15 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
// The NoBuiltinAttr attached to the target FunctionDecl.
const NoBuiltinAttr *NBA = nullptr;
+ // Some ABIs may result in additional accesses to arguments that may
+ // otherwise not be present.
+ auto AddPotentialArgAccess = [&]() {
+ llvm::Attribute A = FuncAttrs.getAttribute(llvm::Attribute::Memory);
+ if (A.isValid())
+ FuncAttrs.addMemoryAttr(A.getMemoryEffects() |
+ llvm::MemoryEffects::argMemOnly());
+ };
+
// Collect function IR attributes based on declaration-specific
// information.
// FIXME: handle sseregparm someday...
@@ -2140,18 +2208,18 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
// 'const', 'pure' and 'noalias' attributed functions are also nounwind.
if (TargetDecl->hasAttr<ConstAttr>()) {
- FuncAttrs.addAttribute(llvm::Attribute::ReadNone);
+ FuncAttrs.addMemoryAttr(llvm::MemoryEffects::none());
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
// gcc specifies that 'const' functions have greater restrictions than
// 'pure' functions, so they also cannot have infinite loops.
FuncAttrs.addAttribute(llvm::Attribute::WillReturn);
} else if (TargetDecl->hasAttr<PureAttr>()) {
- FuncAttrs.addAttribute(llvm::Attribute::ReadOnly);
+ FuncAttrs.addMemoryAttr(llvm::MemoryEffects::readOnly());
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
// gcc specifies that 'pure' functions cannot have infinite loops.
FuncAttrs.addAttribute(llvm::Attribute::WillReturn);
} else if (TargetDecl->hasAttr<NoAliasAttr>()) {
- FuncAttrs.addAttribute(llvm::Attribute::ArgMemOnly);
+ FuncAttrs.addMemoryAttr(llvm::MemoryEffects::argMemOnly());
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}
if (TargetDecl->hasAttr<RestrictAttr>())
@@ -2168,7 +2236,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
HasOptnone = TargetDecl->hasAttr<OptimizeNoneAttr>();
if (auto *AllocSize = TargetDecl->getAttr<AllocSizeAttr>()) {
- Optional<unsigned> NumElemsParam;
+ std::optional<unsigned> NumElemsParam;
if (AllocSize->getNumElemsParam().isValid())
NumElemsParam = AllocSize->getNumElemsParam().getLLVMIndex();
FuncAttrs.addAllocSizeAttr(AllocSize->getElemSizeParam().getLLVMIndex(),
@@ -2237,9 +2305,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
// Add "sample-profile-suffix-elision-policy" attribute for internal linkage
// functions with -funique-internal-linkage-names.
if (TargetDecl && CodeGenOpts.UniqueInternalLinkageNames) {
- if (isa<FunctionDecl>(TargetDecl)) {
- if (this->getFunctionLinkage(CalleeInfo.getCalleeDecl()) ==
- llvm::GlobalValue::InternalLinkage)
+ if (const auto *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
+ if (!FD->isExternallyVisible())
FuncAttrs.addAttribute("sample-profile-suffix-elision-policy",
"selected");
}
@@ -2287,27 +2354,9 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
const ABIArgInfo &RetAI = FI.getReturnInfo();
const llvm::DataLayout &DL = getDataLayout();
- // C++ explicitly makes returning undefined values UB. C's rule only applies
- // to used values, so we never mark them noundef for now.
- bool HasStrictReturn = getLangOpts().CPlusPlus;
- if (TargetDecl && HasStrictReturn) {
- if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(TargetDecl))
- HasStrictReturn &= !FDecl->isExternC();
- else if (const VarDecl *VDecl = dyn_cast<VarDecl>(TargetDecl))
- // Function pointer
- HasStrictReturn &= !VDecl->isExternC();
- }
-
- // We don't want to be too aggressive with the return checking, unless
- // it's explicit in the code opts or we're using an appropriate sanitizer.
- // Try to respect what the programmer intended.
- HasStrictReturn &= getCodeGenOpts().StrictReturn ||
- !MayDropFunctionReturn(getContext(), RetTy) ||
- getLangOpts().Sanitize.has(SanitizerKind::Memory) ||
- getLangOpts().Sanitize.has(SanitizerKind::Return);
-
// Determine if the return type could be partially undef
- if (CodeGenOpts.EnableNoundefAttrs && HasStrictReturn) {
+ if (CodeGenOpts.EnableNoundefAttrs &&
+ HasStrictReturn(*this, RetTy, TargetDecl)) {
if (!RetTy->isVoidType() && RetAI.getKind() != ABIArgInfo::Indirect &&
DetermineNoUndef(RetTy, getTypes(), DL, RetAI))
RetAttrs.addAttribute(llvm::Attribute::NoUndef);
@@ -2319,7 +2368,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
RetAttrs.addAttribute(llvm::Attribute::SExt);
else
RetAttrs.addAttribute(llvm::Attribute::ZExt);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ABIArgInfo::Direct:
if (RetAI.getInReg())
RetAttrs.addAttribute(llvm::Attribute::InReg);
@@ -2330,8 +2379,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect: {
// inalloca and sret disable readnone and readonly
- FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
- .removeAttribute(llvm::Attribute::ReadNone);
+ AddPotentialArgAccess();
break;
}
@@ -2350,7 +2398,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
RetAttrs.addDereferenceableAttr(
getMinimumObjectSize(PTy).getQuantity());
- if (getContext().getTargetAddressSpace(PTy) == 0 &&
+ if (getTypes().getTargetAddressSpace(PTy) == 0 &&
!CodeGenOpts.NullPointerIsValid)
RetAttrs.addAttribute(llvm::Attribute::NonNull);
if (PTy->isObjectType()) {
@@ -2399,7 +2447,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
FI.arg_begin()->type.castAs<PointerType>()->getPointeeType();
if (!CodeGenOpts.NullPointerIsValid &&
- getContext().getTargetAddressSpace(FI.arg_begin()->type) == 0) {
+ getTypes().getTargetAddressSpace(FI.arg_begin()->type) == 0) {
Attrs.addAttribute(llvm::Attribute::NonNull);
Attrs.addDereferenceableAttr(getMinimumObjectSize(ThisTy).getQuantity());
} else {
@@ -2455,7 +2503,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
Attrs.addAttribute(llvm::Attribute::SExt);
else
Attrs.addAttribute(llvm::Attribute::ZExt);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ABIArgInfo::Direct:
if (ArgNo == 0 && FI.isChainCall())
Attrs.addAttribute(llvm::Attribute::Nest);
@@ -2501,9 +2549,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
Attrs.addAlignmentAttr(Align.getQuantity());
// byval disables readnone and readonly.
- FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
- .removeAttribute(llvm::Attribute::ReadNone);
-
+ AddPotentialArgAccess();
break;
}
case ABIArgInfo::IndirectAliased: {
@@ -2519,8 +2565,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
case ABIArgInfo::InAlloca:
// inalloca disables readnone and readonly.
- FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
- .removeAttribute(llvm::Attribute::ReadNone);
+ AddPotentialArgAccess();
continue;
}
@@ -2529,7 +2574,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
Attrs.addDereferenceableAttr(
getMinimumObjectSize(PTy).getQuantity());
- if (getContext().getTargetAddressSpace(PTy) == 0 &&
+ if (getTypes().getTargetAddressSpace(PTy) == 0 &&
!CodeGenOpts.NullPointerIsValid)
Attrs.addAttribute(llvm::Attribute::NonNull);
if (PTy->isObjectType()) {
@@ -2851,7 +2896,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Align Alignment =
CGM.getNaturalTypeAlignment(ETy).getAsAlign();
AI->addAttrs(llvm::AttrBuilder(getLLVMContext()).addAlignmentAttr(Alignment));
- if (!getContext().getTargetAddressSpace(ETy) &&
+ if (!getTypes().getTargetAddressSpace(ETy) &&
!CGM.getCodeGenOpts().NullPointerIsValid)
AI->addAttr(llvm::Attribute::NonNull);
}
@@ -2860,7 +2905,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Set `align` attribute if any.
const auto *AVAttr = PVD->getAttr<AlignValueAttr>();
if (!AVAttr)
- if (const auto *TOTy = dyn_cast<TypedefType>(OTy))
+ if (const auto *TOTy = OTy->getAs<TypedefType>())
AVAttr = TOTy->getDecl()->getAttr<AlignValueAttr>();
if (AVAttr && !SanOpts.has(SanitizerKind::Alignment)) {
// If alignment-assumption sanitizer is enabled, we do *not* add
@@ -3509,7 +3554,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
switch (RetAI.getKind()) {
case ABIArgInfo::InAlloca:
- // Aggregrates get evaluated directly into the destination. Sometimes we
+ // Aggregates get evaluated directly into the destination. Sometimes we
// need to return the sret value in a register, though.
assert(hasAggregateEvaluationKind(RetTy));
if (RetAI.getInAllocaSRet()) {
@@ -3537,7 +3582,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
break;
}
case TEK_Aggregate:
- // Do nothing; aggregrates get evaluated directly into the destination.
+ // Do nothing; aggregates get evaluated directly into the destination.
break;
case TEK_Scalar: {
LValueBaseInfo BaseInfo;
@@ -4078,7 +4123,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
bool CanCheckNullability = false;
if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD) {
- auto Nullability = PVD->getType()->getNullability(getContext());
+ auto Nullability = PVD->getType()->getNullability();
CanCheckNullability = Nullability &&
*Nullability == NullabilityKind::NonNull &&
PVD->getTypeSourceInfo();
@@ -4106,7 +4151,7 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType,
EmitCheckSourceLocation(ArgLoc), EmitCheckSourceLocation(AttrLoc),
llvm::ConstantInt::get(Int32Ty, ArgNo + 1),
};
- EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None);
+ EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, std::nullopt);
}
// Check if the call is going to use the inalloca convention. This needs to
@@ -4426,7 +4471,7 @@ QualType CodeGenFunction::getVarArgType(const Expr *Arg) {
if (Arg->getType()->isIntegerType() &&
getContext().getTypeSize(Arg->getType()) <
- getContext().getTargetInfo().getPointerWidth(0) &&
+ getContext().getTargetInfo().getPointerWidth(LangAS::Default) &&
Arg->isNullPointerConstant(getContext(),
Expr::NPC_ValueDependentIsNotNull)) {
return getContext().getIntPtrType();
@@ -4449,7 +4494,7 @@ CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) {
llvm::CallInst *
CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee,
const llvm::Twine &name) {
- return EmitNounwindRuntimeCall(callee, None, name);
+ return EmitNounwindRuntimeCall(callee, std::nullopt, name);
}
/// Emits a call to the given nounwind runtime function.
@@ -4466,7 +4511,7 @@ CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee,
/// runtime function.
llvm::CallInst *CodeGenFunction::EmitRuntimeCall(llvm::FunctionCallee callee,
const llvm::Twine &name) {
- return EmitRuntimeCall(callee, None, name);
+ return EmitRuntimeCall(callee, std::nullopt, name);
}
// Calls which may throw must have operand bundles indicating which funclet
@@ -4530,7 +4575,7 @@ void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(
llvm::CallBase *
CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::FunctionCallee callee,
const Twine &name) {
- return EmitRuntimeCallOrInvoke(callee, None, name);
+ return EmitRuntimeCallOrInvoke(callee, std::nullopt, name);
}
/// Emits a call or invoke instruction to the given runtime function.
@@ -4580,7 +4625,7 @@ namespace {
/// Specify given \p NewAlign as the alignment of return value attribute. If
/// such attribute already exists, re-set it to the maximal one of two options.
-LLVM_NODISCARD llvm::AttributeList
+[[nodiscard]] llvm::AttributeList
maybeRaiseRetAlignmentAttribute(llvm::LLVMContext &Ctx,
const llvm::AttributeList &Attrs,
llvm::Align NewAlign) {
@@ -4611,7 +4656,7 @@ protected:
public:
/// If we can, materialize the alignment as an attribute on return value.
- LLVM_NODISCARD llvm::AttributeList
+ [[nodiscard]] llvm::AttributeList
TryEmitAsCallSiteAttribute(const llvm::AttributeList &Attrs) {
if (!AA || OffsetCI || CGF.SanOpts.has(SanitizerKind::Alignment))
return Attrs;
@@ -4680,7 +4725,7 @@ public:
static unsigned getMaxVectorWidth(const llvm::Type *Ty) {
if (auto *VT = dyn_cast<llvm::VectorType>(Ty))
- return VT->getPrimitiveSizeInBits().getKnownMinSize();
+ return VT->getPrimitiveSizeInBits().getKnownMinValue();
if (auto *AT = dyn_cast<llvm::ArrayType>(Ty))
return getMaxVectorWidth(AT->getElementType());
@@ -4821,6 +4866,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned FirstIRArg, NumIRArgs;
std::tie(FirstIRArg, NumIRArgs) = IRFunctionArgs.getIRArgs(ArgNo);
+ bool ArgHasMaybeUndefAttr =
+ IsArgumentMaybeUndef(TargetDecl, CallInfo.getNumRequiredArgs(), ArgNo);
+
switch (ArgInfo.getKind()) {
case ABIArgInfo::InAlloca: {
assert(NumIRArgs == 0);
@@ -4879,7 +4927,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Make a temporary alloca to pass the argument.
Address Addr = CreateMemTempWithoutCast(
I->Ty, ArgInfo.getIndirectAlign(), "indirect-arg-temp");
- IRCallArgs[FirstIRArg] = Addr.getPointer();
+
+ llvm::Value *Val = Addr.getPointer();
+ if (ArgHasMaybeUndefAttr)
+ Val = Builder.CreateFreeze(Addr.getPointer());
+ IRCallArgs[FirstIRArg] = Val;
I->copyInto(*this, Addr);
} else {
@@ -4937,7 +4989,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Create an aligned temporary, and copy to it.
Address AI = CreateMemTempWithoutCast(
I->Ty, ArgInfo.getIndirectAlign(), "byval-temp");
- IRCallArgs[FirstIRArg] = AI.getPointer();
+ llvm::Value *Val = AI.getPointer();
+ if (ArgHasMaybeUndefAttr)
+ Val = Builder.CreateFreeze(AI.getPointer());
+ IRCallArgs[FirstIRArg] = Val;
// Emit lifetime markers for the temporary alloca.
llvm::TypeSize ByvalTempElementSize =
@@ -4956,9 +5011,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
auto *T = llvm::PointerType::getWithSamePointeeType(
cast<llvm::PointerType>(V->getType()),
CGM.getDataLayout().getAllocaAddrSpace());
- IRCallArgs[FirstIRArg] = getTargetHooks().performAddrSpaceCast(
+
+ llvm::Value *Val = getTargetHooks().performAddrSpaceCast(
*this, V, LangAS::Default, CGM.getASTAllocaAddressSpace(), T,
true);
+ if (ArgHasMaybeUndefAttr)
+ Val = Builder.CreateFreeze(Val);
+ IRCallArgs[FirstIRArg] = Val;
}
}
break;
@@ -5012,6 +5071,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
V->getType() != IRFuncTy->getParamType(FirstIRArg))
V = Builder.CreateBitCast(V, IRFuncTy->getParamType(FirstIRArg));
+ if (ArgHasMaybeUndefAttr)
+ V = Builder.CreateFreeze(V);
IRCallArgs[FirstIRArg] = V;
break;
}
@@ -5056,6 +5117,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
Address EltPtr = Builder.CreateStructGEP(Src, i);
llvm::Value *LI = Builder.CreateLoad(EltPtr);
+ if (ArgHasMaybeUndefAttr)
+ LI = Builder.CreateFreeze(LI);
IRCallArgs[FirstIRArg + i] = LI;
}
} else {
@@ -5072,6 +5135,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (ATy != nullptr && isa<RecordType>(I->Ty.getCanonicalType()))
Load = EmitCMSEClearRecord(Load, ATy, I->Ty);
}
+
+ if (ArgHasMaybeUndefAttr)
+ Load = Builder.CreateFreeze(Load);
IRCallArgs[FirstIRArg] = Load;
}
@@ -5095,15 +5161,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Type *scalarType = RV.getScalarVal()->getType();
auto scalarSize = CGM.getDataLayout().getTypeAllocSize(scalarType);
- auto scalarAlign = CGM.getDataLayout().getPrefTypeAlignment(scalarType);
+ auto scalarAlign = CGM.getDataLayout().getPrefTypeAlign(scalarType);
// Materialize to a temporary.
- addr =
- CreateTempAlloca(RV.getScalarVal()->getType(),
- CharUnits::fromQuantity(std::max(
- layout->getAlignment().value(), scalarAlign)),
- "tmp",
- /*ArraySize=*/nullptr, &AllocaAddr);
+ addr = CreateTempAlloca(
+ RV.getScalarVal()->getType(),
+ CharUnits::fromQuantity(std::max(layout->getAlignment(), scalarAlign)),
+ "tmp",
+ /*ArraySize=*/nullptr, &AllocaAddr);
tempSize = EmitLifetimeStart(scalarSize, AllocaAddr.getPointer());
Builder.CreateStore(RV.getScalarVal(), addr);
@@ -5117,6 +5182,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
Address eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = Builder.CreateLoad(eltAddr);
+ if (ArgHasMaybeUndefAttr)
+ elt = Builder.CreateFreeze(elt);
IRCallArgs[IRArgPos++] = elt;
}
assert(IRArgPos == FirstIRArg + NumIRArgs);
@@ -5324,6 +5391,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
SmallVector<llvm::OperandBundleDef, 1> BundleList =
getBundlesForFunclet(CalleePtr);
+ if (SanOpts.has(SanitizerKind::KCFI) &&
+ !isa_and_nonnull<FunctionDecl>(TargetDecl))
+ EmitKCFIOperandBundle(ConcreteCallee, BundleList);
+
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
if (FD->hasAttr<StrictFPAttr>())
// All calls within a strictfp function are marked strictfp
@@ -5506,7 +5577,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Builder.CreateStore(elt, eltAddr);
}
// FALLTHROUGH
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case ABIArgInfo::InAlloca:
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index c6696c4df775..0795ea598411 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -29,6 +29,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -1505,7 +1506,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
}
// Fallthrough: act like we're in the base variant.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Dtor_Base:
assert(Body);
@@ -1649,23 +1650,58 @@ namespace {
}
};
- static void EmitSanitizerDtorCallback(CodeGenFunction &CGF, llvm::Value *Ptr,
- CharUnits::QuantityType PoisonSize) {
+ class DeclAsInlineDebugLocation {
+ CGDebugInfo *DI;
+ llvm::MDNode *InlinedAt;
+ std::optional<ApplyDebugLocation> Location;
+
+ public:
+ DeclAsInlineDebugLocation(CodeGenFunction &CGF, const NamedDecl &Decl)
+ : DI(CGF.getDebugInfo()) {
+ if (!DI)
+ return;
+ InlinedAt = DI->getInlinedAt();
+ DI->setInlinedAt(CGF.Builder.getCurrentDebugLocation());
+ Location.emplace(CGF, Decl.getLocation());
+ }
+
+ ~DeclAsInlineDebugLocation() {
+ if (!DI)
+ return;
+ Location.reset();
+ DI->setInlinedAt(InlinedAt);
+ }
+ };
+
+ static void EmitSanitizerDtorCallback(
+ CodeGenFunction &CGF, StringRef Name, llvm::Value *Ptr,
+ std::optional<CharUnits::QuantityType> PoisonSize = {}) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
// Pass in void pointer and size of region as arguments to runtime
// function
- llvm::Value *Args[] = {CGF.Builder.CreateBitCast(Ptr, CGF.VoidPtrTy),
- llvm::ConstantInt::get(CGF.SizeTy, PoisonSize)};
+ SmallVector<llvm::Value *, 2> Args = {
+ CGF.Builder.CreateBitCast(Ptr, CGF.VoidPtrTy)};
+ SmallVector<llvm::Type *, 2> ArgTypes = {CGF.VoidPtrTy};
- llvm::Type *ArgTypes[] = {CGF.VoidPtrTy, CGF.SizeTy};
+ if (PoisonSize.has_value()) {
+ Args.emplace_back(llvm::ConstantInt::get(CGF.SizeTy, *PoisonSize));
+ ArgTypes.emplace_back(CGF.SizeTy);
+ }
llvm::FunctionType *FnType =
llvm::FunctionType::get(CGF.VoidTy, ArgTypes, false);
- llvm::FunctionCallee Fn =
- CGF.CGM.CreateRuntimeFunction(FnType, "__sanitizer_dtor_callback");
+ llvm::FunctionCallee Fn = CGF.CGM.CreateRuntimeFunction(FnType, Name);
+
CGF.EmitNounwindRuntimeCall(Fn, Args);
}
+ static void
+ EmitSanitizerDtorFieldsCallback(CodeGenFunction &CGF, llvm::Value *Ptr,
+ CharUnits::QuantityType PoisonSize) {
+ EmitSanitizerDtorCallback(CGF, "__sanitizer_dtor_callback_fields", Ptr,
+ PoisonSize);
+ }
+
/// Poison base class with a trivial destructor.
struct SanitizeDtorTrivialBase final : EHScopeStack::Cleanup {
const CXXRecordDecl *BaseClass;
@@ -1687,7 +1723,11 @@ namespace {
if (!BaseSize.isPositive())
return;
- EmitSanitizerDtorCallback(CGF, Addr.getPointer(), BaseSize.getQuantity());
+ // Use the base class declaration location as inline DebugLocation. All
+ // fields of the class are destroyed.
+ DeclAsInlineDebugLocation InlineHere(CGF, *BaseClass);
+ EmitSanitizerDtorFieldsCallback(CGF, Addr.getPointer(),
+ BaseSize.getQuantity());
// Prevent the current stack frame from disappearing from the stack trace.
CGF.CurFn->addFnAttr("disable-tail-calls", "true");
@@ -1735,7 +1775,10 @@ namespace {
if (!PoisonSize.isPositive())
return;
- EmitSanitizerDtorCallback(CGF, OffsetPtr, PoisonSize.getQuantity());
+ // Use the top field declaration location as inline DebugLocation.
+ DeclAsInlineDebugLocation InlineHere(
+ CGF, **std::next(Dtor->getParent()->field_begin(), StartIndex));
+ EmitSanitizerDtorFieldsCallback(CGF, OffsetPtr, PoisonSize.getQuantity());
// Prevent the current stack frame from disappearing from the stack trace.
CGF.CurFn->addFnAttr("disable-tail-calls", "true");
@@ -1752,15 +1795,13 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) override {
assert(Dtor->getParent()->isDynamicClass());
(void)Dtor;
- ASTContext &Context = CGF.getContext();
// Poison vtable and vtable ptr if they exist for this class.
llvm::Value *VTablePtr = CGF.LoadCXXThis();
- CharUnits::QuantityType PoisonSize =
- Context.toCharUnitsFromBits(CGF.PointerWidthInBits).getQuantity();
// Pass in void pointer and size of region as arguments to runtime
// function
- EmitSanitizerDtorCallback(CGF, VTablePtr, PoisonSize);
+ EmitSanitizerDtorCallback(CGF, "__sanitizer_dtor_callback_vptr",
+ VTablePtr);
}
};
@@ -1768,12 +1809,12 @@ namespace {
ASTContext &Context;
EHScopeStack &EHStack;
const CXXDestructorDecl *DD;
- llvm::Optional<unsigned> StartIndex;
+ std::optional<unsigned> StartIndex;
public:
SanitizeDtorCleanupBuilder(ASTContext &Context, EHScopeStack &EHStack,
const CXXDestructorDecl *DD)
- : Context(Context), EHStack(EHStack), DD(DD), StartIndex(llvm::None) {}
+ : Context(Context), EHStack(EHStack), DD(DD), StartIndex(std::nullopt) {}
void PushCleanupForField(const FieldDecl *Field) {
if (Field->isZeroSize(Context))
return;
@@ -1782,15 +1823,15 @@ namespace {
if (!StartIndex)
StartIndex = FieldIndex;
} else if (StartIndex) {
- EHStack.pushCleanup<SanitizeDtorFieldRange>(
- NormalAndEHCleanup, DD, StartIndex.value(), FieldIndex);
- StartIndex = None;
+ EHStack.pushCleanup<SanitizeDtorFieldRange>(NormalAndEHCleanup, DD,
+ *StartIndex, FieldIndex);
+ StartIndex = std::nullopt;
}
}
void End() {
if (StartIndex)
EHStack.pushCleanup<SanitizeDtorFieldRange>(NormalAndEHCleanup, DD,
- StartIndex.value(), -1);
+ *StartIndex, -1);
}
};
} // end anonymous namespace
@@ -2543,7 +2584,7 @@ void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) {
llvm::FunctionType::get(CGM.Int32Ty, /*isVarArg=*/true)
->getPointerTo(ProgAS)
->getPointerTo(GlobalsAS);
- // vtable field is is derived from `this` pointer, therefore they should be in
+ // vtable field is derived from `this` pointer, therefore they should be in
// the same addr space. Note that this might not be LLVM address space 0.
VTableField = Builder.CreateElementBitCast(VTableField, VTablePtrTy);
VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy);
@@ -2955,7 +2996,7 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
CallArgs.add(RValue::get(ThisPtr.getPointer()), ThisType);
// Add the rest of the parameters.
- for (auto param : BD->parameters())
+ for (auto *param : BD->parameters())
EmitDelegateCallArg(CallArgs, param, param->getBeginLoc());
assert(!Lambda->isGenericLambda() &&
@@ -2969,12 +3010,13 @@ void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
// Start building arguments for forwarding call
CallArgList CallArgs;
- QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda));
- llvm::Value *ThisPtr = llvm::UndefValue::get(getTypes().ConvertType(ThisType));
- CallArgs.add(RValue::get(ThisPtr), ThisType);
+ QualType LambdaType = getContext().getRecordType(Lambda);
+ QualType ThisType = getContext().getPointerType(LambdaType);
+ Address ThisPtr = CreateMemTemp(LambdaType, "unused.capture");
+ CallArgs.add(RValue::get(ThisPtr.getPointer()), ThisType);
// Add the rest of the parameters.
- for (auto Param : MD->parameters())
+ for (auto *Param : MD->parameters())
EmitDelegateCallArg(CallArgs, Param, Param->getBeginLoc());
const CXXMethodDecl *CallOp = Lambda->getLambdaCallOperator();
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index 5035ed34358d..43758ac27e43 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -556,7 +556,7 @@ static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF,
Entry->replaceAllUsesWith(Pred);
// Merge the blocks.
- Pred->getInstList().splice(Pred->end(), Entry->getInstList());
+ Pred->splice(Pred->end(), Entry);
// Kill the entry block.
Entry->eraseFromParent();
@@ -942,7 +942,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// Append the prepared cleanup prologue from above.
llvm::BasicBlock *NormalExit = Builder.GetInsertBlock();
for (unsigned I = 0, E = InstsToAppend.size(); I != E; ++I)
- NormalExit->getInstList().push_back(InstsToAppend[I]);
+ InstsToAppend[I]->insertInto(NormalExit, NormalExit->end());
// Optimistically hope that any fixups will continue falling through.
for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups();
@@ -1016,8 +1016,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// throwing cleanups. For funclet EH personalities, the cleanupendpad models
// program termination when cleanups throw.
bool PushedTerminate = false;
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
+ SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad);
llvm::CleanupPadInst *CPI = nullptr;
const EHPersonality &Personality = EHPersonality::get(*this);
@@ -1336,7 +1335,8 @@ static void EmitSehScope(CodeGenFunction &CGF,
CGF.getBundlesForFunclet(SehCppScope.getCallee());
if (CGF.CurrentFuncletPad)
BundleList.emplace_back("funclet", CGF.CurrentFuncletPad);
- CGF.Builder.CreateInvoke(SehCppScope, Cont, InvokeDest, None, BundleList);
+ CGF.Builder.CreateInvoke(SehCppScope, Cont, InvokeDest, std::nullopt,
+ BundleList);
CGF.EmitBlock(Cont);
}
diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp
index 594c7d49df3c..775a4341558a 100644
--- a/clang/lib/CodeGen/CGCoroutine.cpp
+++ b/clang/lib/CodeGen/CGCoroutine.cpp
@@ -539,7 +539,7 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) {
EHStack.pushCleanup<CallCoroDelete>(NormalAndEHCleanup, S.getDeallocate());
// Create mapping between parameters and copy-params for coroutine function.
- auto ParamMoves = S.getParamMoves();
+ llvm::ArrayRef<const Stmt *> ParamMoves = S.getParamMoves();
assert(
(ParamMoves.size() == 0 || (ParamMoves.size() == FnArgs.size())) &&
"ParamMoves and FnArgs should be the same size for coroutine function");
@@ -673,9 +673,23 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
}
CGM.Error(E->getBeginLoc(), "this builtin expect that __builtin_coro_begin "
"has been used earlier in this function");
- auto NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
+ auto *NullPtr = llvm::ConstantPointerNull::get(Builder.getInt8PtrTy());
return RValue::get(NullPtr);
}
+ case llvm::Intrinsic::coro_size: {
+ auto &Context = getContext();
+ CanQualType SizeTy = Context.getSizeType();
+ llvm::IntegerType *T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
+ llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::coro_size, T);
+ return RValue::get(Builder.CreateCall(F));
+ }
+ case llvm::Intrinsic::coro_align: {
+ auto &Context = getContext();
+ CanQualType SizeTy = Context.getSizeType();
+ llvm::IntegerType *T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
+ llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::coro_align, T);
+ return RValue::get(Builder.CreateCall(F));
+ }
// The following three intrinsics take a token parameter referring to a token
// returned by earlier call to @llvm.coro.id. Since we cannot represent it in
// builtins, we patch it up here.
@@ -689,7 +703,7 @@ RValue CodeGenFunction::EmitCoroutineIntrinsic(const CallExpr *E,
CGM.Error(E->getBeginLoc(), "this builtin expect that __builtin_coro_id has"
" been used earlier in this function");
// Fallthrough to the next case to add TokenNone as the first argument.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
// @llvm.coro.suspend takes a token parameter. Add token 'none' as the first
// argument.
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 94c48316add7..3bde43cc1db3 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -26,6 +26,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
@@ -47,7 +48,10 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/SHA1.h"
+#include "llvm/Support/SHA256.h"
#include "llvm/Support/TimeProfiler.h"
+#include <optional>
using namespace clang;
using namespace clang::CodeGen;
@@ -342,35 +346,44 @@ StringRef CGDebugInfo::getClassName(const RecordDecl *RD) {
return StringRef();
}
-Optional<llvm::DIFile::ChecksumKind>
-CGDebugInfo::computeChecksum(FileID FID, SmallString<32> &Checksum) const {
+std::optional<llvm::DIFile::ChecksumKind>
+CGDebugInfo::computeChecksum(FileID FID, SmallString<64> &Checksum) const {
Checksum.clear();
if (!CGM.getCodeGenOpts().EmitCodeView &&
CGM.getCodeGenOpts().DwarfVersion < 5)
- return None;
+ return std::nullopt;
SourceManager &SM = CGM.getContext().getSourceManager();
- Optional<llvm::MemoryBufferRef> MemBuffer = SM.getBufferOrNone(FID);
+ std::optional<llvm::MemoryBufferRef> MemBuffer = SM.getBufferOrNone(FID);
if (!MemBuffer)
- return None;
+ return std::nullopt;
- llvm::toHex(
- llvm::MD5::hash(llvm::arrayRefFromStringRef(MemBuffer->getBuffer())),
- /*LowerCase*/ true, Checksum);
- return llvm::DIFile::CSK_MD5;
+ auto Data = llvm::arrayRefFromStringRef(MemBuffer->getBuffer());
+ switch (CGM.getCodeGenOpts().getDebugSrcHash()) {
+ case clang::CodeGenOptions::DSH_MD5:
+ llvm::toHex(llvm::MD5::hash(Data), /*LowerCase=*/true, Checksum);
+ return llvm::DIFile::CSK_MD5;
+ case clang::CodeGenOptions::DSH_SHA1:
+ llvm::toHex(llvm::SHA1::hash(Data), /*LowerCase=*/true, Checksum);
+ return llvm::DIFile::CSK_SHA1;
+ case clang::CodeGenOptions::DSH_SHA256:
+ llvm::toHex(llvm::SHA256::hash(Data), /*LowerCase=*/true, Checksum);
+ return llvm::DIFile::CSK_SHA256;
+ }
+ llvm_unreachable("Unhandled DebugSrcHashKind enum");
}
-Optional<StringRef> CGDebugInfo::getSource(const SourceManager &SM,
- FileID FID) {
+std::optional<StringRef> CGDebugInfo::getSource(const SourceManager &SM,
+ FileID FID) {
if (!CGM.getCodeGenOpts().EmbedSource)
- return None;
+ return std::nullopt;
bool SourceInvalid = false;
StringRef Source = SM.getBufferData(FID, &SourceInvalid);
if (SourceInvalid)
- return None;
+ return std::nullopt;
return Source;
}
@@ -405,19 +418,20 @@ llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) {
return cast<llvm::DIFile>(V);
}
- SmallString<32> Checksum;
+ SmallString<64> Checksum;
- Optional<llvm::DIFile::ChecksumKind> CSKind = computeChecksum(FID, Checksum);
- Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo;
+ std::optional<llvm::DIFile::ChecksumKind> CSKind =
+ computeChecksum(FID, Checksum);
+ std::optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo;
if (CSKind)
CSInfo.emplace(*CSKind, Checksum);
return createFile(FileName, CSInfo, getSource(SM, SM.getFileID(Loc)));
}
-llvm::DIFile *
-CGDebugInfo::createFile(StringRef FileName,
- Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo,
- Optional<StringRef> Source) {
+llvm::DIFile *CGDebugInfo::createFile(
+ StringRef FileName,
+ std::optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo,
+ std::optional<StringRef> Source) {
StringRef Dir;
StringRef File;
std::string RemappedFile = remapDIPath(FileName);
@@ -499,9 +513,9 @@ StringRef CGDebugInfo::getCurrentDirname() {
}
void CGDebugInfo::CreateCompileUnit() {
- SmallString<32> Checksum;
- Optional<llvm::DIFile::ChecksumKind> CSKind;
- Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo;
+ SmallString<64> Checksum;
+ std::optional<llvm::DIFile::ChecksumKind> CSKind;
+ std::optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo;
// Should we be asking the SourceManager for the main file name, instead of
// accepting it as an argument? This just causes the main file name to
@@ -512,7 +526,8 @@ void CGDebugInfo::CreateCompileUnit() {
// Get absolute path name.
SourceManager &SM = CGM.getContext().getSourceManager();
- std::string MainFileName = CGM.getCodeGenOpts().MainFileName;
+ auto &CGO = CGM.getCodeGenOpts();
+ std::string MainFileName = CGO.MainFileName;
if (MainFileName.empty())
MainFileName = "<stdin>";
@@ -521,7 +536,7 @@ void CGDebugInfo::CreateCompileUnit() {
// a relative path, so we look into the actual file entry for the main
// file to determine the real absolute path for the file.
std::string MainFileDir;
- if (Optional<FileEntryRef> MainFile =
+ if (OptionalFileEntryRef MainFile =
SM.getFileEntryRefForID(SM.getMainFileID())) {
MainFileDir = std::string(MainFile->getDir().getName());
if (!llvm::sys::path::is_absolute(MainFileName)) {
@@ -548,11 +563,11 @@ void CGDebugInfo::CreateCompileUnit() {
if (LO.CPlusPlus) {
if (LO.ObjC)
LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
- else if (LO.CPlusPlus14 && (!CGM.getCodeGenOpts().DebugStrictDwarf ||
- CGM.getCodeGenOpts().DwarfVersion >= 5))
+ else if (CGO.DebugStrictDwarf && CGO.DwarfVersion < 5)
+ LangTag = llvm::dwarf::DW_LANG_C_plus_plus;
+ else if (LO.CPlusPlus14)
LangTag = llvm::dwarf::DW_LANG_C_plus_plus_14;
- else if (LO.CPlusPlus11 && (!CGM.getCodeGenOpts().DebugStrictDwarf ||
- CGM.getCodeGenOpts().DwarfVersion >= 5))
+ else if (LO.CPlusPlus11)
LangTag = llvm::dwarf::DW_LANG_C_plus_plus_11;
else
LangTag = llvm::dwarf::DW_LANG_C_plus_plus;
@@ -563,6 +578,8 @@ void CGDebugInfo::CreateCompileUnit() {
LangTag = llvm::dwarf::DW_LANG_OpenCL;
} else if (LO.RenderScript) {
LangTag = llvm::dwarf::DW_LANG_GOOGLE_RenderScript;
+ } else if (LO.C11 && !(CGO.DebugStrictDwarf && CGO.DwarfVersion < 5)) {
+ LangTag = llvm::dwarf::DW_LANG_C11;
} else if (LO.C99) {
LangTag = llvm::dwarf::DW_LANG_C99;
} else {
@@ -883,10 +900,6 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
return DBuilder.createBasicType(BTName, Size, Encoding);
}
-llvm::DIType *CGDebugInfo::CreateType(const AutoType *Ty) {
- return DBuilder.createUnspecifiedType("auto");
-}
-
llvm::DIType *CGDebugInfo::CreateType(const BitIntType *Ty) {
StringRef Name = Ty->isUnsigned() ? "unsigned _BitInt" : "_BitInt";
@@ -1137,13 +1150,12 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag,
QualType PointeeTy,
llvm::DIFile *Unit) {
// Bit size, align and offset of the type.
- // Size is always the size of a pointer. We can't use getTypeSize here
- // because that does not return the correct value for references.
- unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getTarget().getPointerWidth(AddressSpace);
+ // Size is always the size of a pointer.
+ uint64_t Size = CGM.getContext().getTypeSize(Ty);
auto Align = getTypeAlignIfRequired(Ty, CGM.getContext());
- Optional<unsigned> DWARFAddressSpace =
- CGM.getTarget().getDWARFAddressSpace(AddressSpace);
+ std::optional<unsigned> DWARFAddressSpace =
+ CGM.getTarget().getDWARFAddressSpace(
+ CGM.getTypes().getTargetAddressSpace(PointeeTy));
SmallVector<llvm::Metadata *, 4> Annots;
auto *BTFAttrTy = dyn_cast<BTFTagAttributedType>(PointeeTy);
@@ -1266,18 +1278,31 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
assert(Ty->isTypeAlias());
llvm::DIType *Src = getOrCreateType(Ty->getAliasedType(), Unit);
- auto *AliasDecl =
- cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl())
- ->getTemplatedDecl();
+ const TemplateDecl *TD = Ty->getTemplateName().getAsTemplateDecl();
+ if (isa<BuiltinTemplateDecl>(TD))
+ return Src;
+ const auto *AliasDecl = cast<TypeAliasTemplateDecl>(TD)->getTemplatedDecl();
if (AliasDecl->hasAttr<NoDebugAttr>())
return Src;
SmallString<128> NS;
llvm::raw_svector_ostream OS(NS);
- Ty->getTemplateName().print(OS, getPrintingPolicy(),
- TemplateName::Qualified::None);
- printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy());
+
+ auto PP = getPrintingPolicy();
+ Ty->getTemplateName().print(OS, PP, TemplateName::Qualified::None);
+
+ // Disable PrintCanonicalTypes here because we want
+ // the DW_AT_name to benefit from the TypePrinter's ability
+ // to skip defaulted template arguments.
+ //
+ // FIXME: Once -gsimple-template-names is enabled by default
+ // and we attach template parameters to alias template DIEs
+ // we don't need to worry about customizing the PrintingPolicy
+ // here anymore.
+ PP.PrintCanonicalTypes = false;
+ printTemplateArgumentList(OS, Ty->template_arguments(), PP,
+ TD->getTemplateParameters());
SourceLocation Loc = AliasDecl->getLocation();
return DBuilder.createTypedef(Src, OS.str(), getOrCreateFile(Loc),
@@ -1285,6 +1310,33 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty,
getDeclContextDescriptor(AliasDecl));
}
+/// Convert an AccessSpecifier into the corresponding DINode flag.
+/// As an optimization, return 0 if the access specifier equals the
+/// default for the containing type.
+static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access,
+ const RecordDecl *RD) {
+ AccessSpecifier Default = clang::AS_none;
+ if (RD && RD->isClass())
+ Default = clang::AS_private;
+ else if (RD && (RD->isStruct() || RD->isUnion()))
+ Default = clang::AS_public;
+
+ if (Access == Default)
+ return llvm::DINode::FlagZero;
+
+ switch (Access) {
+ case clang::AS_private:
+ return llvm::DINode::FlagPrivate;
+ case clang::AS_protected:
+ return llvm::DINode::FlagProtected;
+ case clang::AS_public:
+ return llvm::DINode::FlagPublic;
+ case clang::AS_none:
+ return llvm::DINode::FlagZero;
+ }
+ llvm_unreachable("unexpected access enumerator");
+}
+
llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty,
llvm::DIFile *Unit) {
llvm::DIType *Underlying =
@@ -1300,10 +1352,16 @@ llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty,
uint32_t Align = getDeclAlignIfRequired(Ty->getDecl(), CGM.getContext());
// Typedefs are derived from some other type.
llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(Ty->getDecl());
+
+ llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
+ const DeclContext *DC = Ty->getDecl()->getDeclContext();
+ if (isa<RecordDecl>(DC))
+ Flags = getAccessFlag(Ty->getDecl()->getAccess(), cast<RecordDecl>(DC));
+
return DBuilder.createTypedef(Underlying, Ty->getDecl()->getName(),
getOrCreateFile(Loc), getLineNumber(Loc),
getDeclContextDescriptor(Ty->getDecl()), Align,
- Annotations);
+ Flags, Annotations);
}
static unsigned getDwarfCC(CallingConv CC) {
@@ -1397,33 +1455,6 @@ llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty,
return F;
}
-/// Convert an AccessSpecifier into the corresponding DINode flag.
-/// As an optimization, return 0 if the access specifier equals the
-/// default for the containing type.
-static llvm::DINode::DIFlags getAccessFlag(AccessSpecifier Access,
- const RecordDecl *RD) {
- AccessSpecifier Default = clang::AS_none;
- if (RD && RD->isClass())
- Default = clang::AS_private;
- else if (RD && (RD->isStruct() || RD->isUnion()))
- Default = clang::AS_public;
-
- if (Access == Default)
- return llvm::DINode::FlagZero;
-
- switch (Access) {
- case clang::AS_private:
- return llvm::DINode::FlagPrivate;
- case clang::AS_protected:
- return llvm::DINode::FlagProtected;
- case clang::AS_public:
- return llvm::DINode::FlagPublic;
- case clang::AS_none:
- return llvm::DINode::FlagZero;
- }
- llvm_unreachable("unexpected access enumerator");
-}
-
llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl,
llvm::DIScope *RecordTy,
const RecordDecl *RD) {
@@ -1497,7 +1528,7 @@ void CGDebugInfo::CollectRecordLambdaFields(
if (C.capturesVariable()) {
SourceLocation Loc = C.getLocation();
assert(!Field->isBitField() && "lambdas don't have bitfield members!");
- VarDecl *V = C.getCapturedVar();
+ ValueDecl *V = C.getCapturedVar();
StringRef VName = V->getName();
llvm::DIFile *VUnit = getOrCreateFile(Loc);
auto Align = getDeclAlignIfRequired(V, CGM.getContext());
@@ -1637,28 +1668,31 @@ void CGDebugInfo::CollectRecordFields(
} else if (CGM.getCodeGenOpts().EmitCodeView) {
// Debug info for nested types is included in the member list only for
// CodeView.
- if (const auto *nestedType = dyn_cast<TypeDecl>(I))
+ if (const auto *nestedType = dyn_cast<TypeDecl>(I)) {
+ // MSVC doesn't generate nested type for anonymous struct/union.
+ if (isa<RecordDecl>(I) &&
+ cast<RecordDecl>(I)->isAnonymousStructOrUnion())
+ continue;
if (!nestedType->isImplicit() &&
nestedType->getDeclContext() == record)
CollectRecordNestedType(nestedType, elements);
+ }
}
}
}
llvm::DISubroutineType *
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
- llvm::DIFile *Unit, bool decl) {
- const auto *Func = Method->getType()->castAs<FunctionProtoType>();
+ llvm::DIFile *Unit) {
+ const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
if (Method->isStatic())
return cast_or_null<llvm::DISubroutineType>(
getOrCreateType(QualType(Func, 0), Unit));
- return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit, decl);
+ return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit);
}
-llvm::DISubroutineType *
-CGDebugInfo::getOrCreateInstanceMethodType(QualType ThisPtr,
- const FunctionProtoType *Func,
- llvm::DIFile *Unit, bool decl) {
+llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType(
+ QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile *Unit) {
FunctionProtoType::ExtProtoInfo EPI = Func->getExtProtoInfo();
Qualifiers &Qc = EPI.TypeQuals;
Qc.removeConst();
@@ -1681,31 +1715,19 @@ CGDebugInfo::getOrCreateInstanceMethodType(QualType ThisPtr,
assert(Args.size() && "Invalid number of arguments!");
SmallVector<llvm::Metadata *, 16> Elts;
+
// First element is always return type. For 'void' functions it is NULL.
- QualType temp = Func->getReturnType();
- if (temp->getTypeClass() == Type::Auto && decl) {
- const AutoType *AT = cast<AutoType>(temp);
-
- // It may be tricky in some cases to link the specification back the lambda
- // call operator and so we skip emitting "auto" for lambdas. This is
- // consistent with gcc as well.
- if (AT->isDeduced() && ThisPtr->getPointeeCXXRecordDecl()->isLambda())
- Elts.push_back(getOrCreateType(AT->getDeducedType(), Unit));
- else
- Elts.push_back(CreateType(AT));
- } else
- Elts.push_back(Args[0]);
+ Elts.push_back(Args[0]);
// "this" pointer is always first argument.
const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl();
if (isa<ClassTemplateSpecializationDecl>(RD)) {
// Create pointer type directly in this case.
const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
- QualType PointeeTy = ThisPtrTy->getPointeeType();
- unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getTarget().getPointerWidth(AS);
+ uint64_t Size = CGM.getContext().getTypeSize(ThisPtrTy);
auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext());
- llvm::DIType *PointeeType = getOrCreateType(PointeeTy, Unit);
+ llvm::DIType *PointeeType =
+ getOrCreateType(ThisPtrTy->getPointeeType(), Unit);
llvm::DIType *ThisPtrType =
DBuilder.createPointerType(PointeeType, Size, Align);
TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType);
@@ -1747,7 +1769,7 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
StringRef MethodName = getFunctionName(Method);
- llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit, true);
+ llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit);
// Since a single ctor/dtor corresponds to multiple functions, it doesn't
// make sense to give a single ctor/dtor a linkage name.
@@ -1775,7 +1797,7 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
llvm::DISubprogram::DISPFlags SPFlags = llvm::DISubprogram::SPFlagZero;
int ThisAdjustment = 0;
- if (Method->isVirtual()) {
+ if (VTableContextBase::hasVtableSlot(Method)) {
if (Method->isPure())
SPFlags |= llvm::DISubprogram::SPFlagPureVirtual;
else
@@ -1979,7 +2001,7 @@ void CGDebugInfo::CollectCXXBasesAux(
}
llvm::DINodeArray
-CGDebugInfo::CollectTemplateParams(Optional<TemplateArgs> OArgs,
+CGDebugInfo::CollectTemplateParams(std::optional<TemplateArgs> OArgs,
llvm::DIFile *Unit) {
if (!OArgs)
return llvm::DINodeArray();
@@ -1989,35 +2011,23 @@ CGDebugInfo::CollectTemplateParams(Optional<TemplateArgs> OArgs,
const TemplateArgument &TA = Args.Args[i];
StringRef Name;
bool defaultParameter = false;
- if (Args.TList)
+ if (Args.TList) {
Name = Args.TList->getParam(i)->getName();
+
+ NamedDecl const *ND = Args.TList->getParam(i);
+ defaultParameter = clang::isSubstitutedDefaultArgument(
+ CGM.getContext(), TA, ND, Args.Args, Args.TList->getDepth());
+ }
+
switch (TA.getKind()) {
case TemplateArgument::Type: {
llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit);
-
- if (Args.TList)
- if (auto *templateType =
- dyn_cast_or_null<TemplateTypeParmDecl>(Args.TList->getParam(i)))
- if (templateType->hasDefaultArgument())
- defaultParameter =
- templateType->getDefaultArgument() == TA.getAsType();
-
TemplateParams.push_back(DBuilder.createTemplateTypeParameter(
TheCU, Name, TTy, defaultParameter));
} break;
case TemplateArgument::Integral: {
llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit);
- if (Args.TList && CGM.getCodeGenOpts().DwarfVersion >= 5)
- if (auto *templateType = dyn_cast_or_null<NonTypeTemplateParmDecl>(
- Args.TList->getParam(i)))
- if (templateType->hasDefaultArgument() &&
- !templateType->getDefaultArgument()->isValueDependent())
- defaultParameter = llvm::APSInt::isSameValue(
- templateType->getDefaultArgument()->EvaluateKnownConstInt(
- CGM.getContext()),
- TA.getAsIntegral());
-
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
TheCU, Name, TTy, defaultParameter,
llvm::ConstantInt::get(CGM.getLLVMContext(), TA.getAsIntegral())));
@@ -2093,7 +2103,7 @@ CGDebugInfo::CollectTemplateParams(Optional<TemplateArgs> OArgs,
TA.getAsTemplate().getAsTemplateDecl()->printQualifiedName(
OS, getPrintingPolicy());
TemplateParams.push_back(DBuilder.createTemplateTemplateParameter(
- TheCU, Name, nullptr, OS.str()));
+ TheCU, Name, nullptr, OS.str(), defaultParameter));
break;
}
case TemplateArgument::Pack:
@@ -2122,7 +2132,7 @@ CGDebugInfo::CollectTemplateParams(Optional<TemplateArgs> OArgs,
return DBuilder.getOrCreateArray(TemplateParams);
}
-Optional<CGDebugInfo::TemplateArgs>
+std::optional<CGDebugInfo::TemplateArgs>
CGDebugInfo::GetTemplateArgs(const FunctionDecl *FD) const {
if (FD->getTemplatedKind() ==
FunctionDecl::TK_FunctionTemplateSpecialization) {
@@ -2131,22 +2141,22 @@ CGDebugInfo::GetTemplateArgs(const FunctionDecl *FD) const {
->getTemplateParameters();
return {{TList, FD->getTemplateSpecializationArgs()->asArray()}};
}
- return None;
+ return std::nullopt;
}
-Optional<CGDebugInfo::TemplateArgs>
+std::optional<CGDebugInfo::TemplateArgs>
CGDebugInfo::GetTemplateArgs(const VarDecl *VD) const {
// Always get the full list of parameters, not just the ones from the
// specialization. A partial specialization may have fewer parameters than
// there are arguments.
auto *TS = dyn_cast<VarTemplateSpecializationDecl>(VD);
if (!TS)
- return None;
+ return std::nullopt;
VarTemplateDecl *T = TS->getSpecializedTemplate();
const TemplateParameterList *TList = T->getTemplateParameters();
auto TA = TS->getTemplateArgs().asArray();
return {{TList, TA}};
}
-Optional<CGDebugInfo::TemplateArgs>
+std::optional<CGDebugInfo::TemplateArgs>
CGDebugInfo::GetTemplateArgs(const RecordDecl *RD) const {
if (auto *TSpecial = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
// Always get the full list of parameters, not just the ones from the
@@ -2157,7 +2167,7 @@ CGDebugInfo::GetTemplateArgs(const RecordDecl *RD) const {
const TemplateArgumentList &TAList = TSpecial->getTemplateArgs();
return {{TPList, TAList.asArray()}};
}
- return None;
+ return std::nullopt;
}
llvm::DINodeArray
@@ -2202,7 +2212,7 @@ llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) {
llvm::DIType *SubTy = DBuilder.createSubroutineType(SElements);
unsigned Size = Context.getTypeSize(Context.VoidPtrTy);
unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace();
- Optional<unsigned> DWARFAddressSpace =
+ std::optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace);
llvm::DIType *vtbl_ptr_type = DBuilder.createPointerType(
@@ -2299,7 +2309,7 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit,
VFTLayout.vtable_components().size() - CGM.getLangOpts().RTTIData;
unsigned VTableWidth = PtrWidth * VSlotCount;
unsigned VtblPtrAddressSpace = CGM.getTarget().getVtblPtrAddressSpace();
- Optional<unsigned> DWARFAddressSpace =
+ std::optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(VtblPtrAddressSpace);
// Create a very wide void* type and insert it directly in the element list.
@@ -2356,7 +2366,7 @@ void CGDebugInfo::addHeapAllocSiteMetadata(llvm::CallBase *CI,
return;
llvm::MDNode *node;
if (AllocatedTy->isVoidType())
- node = llvm::MDNode::get(CGM.getLLVMContext(), None);
+ node = llvm::MDNode::get(CGM.getLLVMContext(), std::nullopt);
else
node = getOrCreateType(AllocatedTy, getOrCreateFile(Loc));
@@ -2766,8 +2776,12 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod,
llvm::DIBuilder DIB(CGM.getModule());
SmallString<0> PCM;
- if (!llvm::sys::path::is_absolute(Mod.getASTFile()))
- PCM = Mod.getPath();
+ if (!llvm::sys::path::is_absolute(Mod.getASTFile())) {
+ if (CGM.getHeaderSearchOpts().ModuleFileHomeIsCwd)
+ PCM = getCurrentDirname();
+ else
+ PCM = Mod.getPath();
+ }
llvm::sys::path::append(PCM, Mod.getASTFile());
DIB.createCompileUnit(
TheCU->getSourceLanguage(),
@@ -2928,6 +2942,9 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty,
else if (Field->getAccessControl() == ObjCIvarDecl::Public)
Flags = llvm::DINode::FlagPublic;
+ if (Field->isBitField())
+ Flags |= llvm::DINode::FlagBitField;
+
llvm::MDNode *PropertyNode = nullptr;
if (ObjCImplementationDecl *ImpD = ID->getImplementation()) {
if (ObjCPropertyImplDecl *PImpD =
@@ -3160,7 +3177,7 @@ llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty,
return DBuilder.createMemberPointerType(
getOrCreateInstanceMethodType(
CXXMethodDecl::getThisType(FPT, Ty->getMostRecentCXXRecordDecl()),
- FPT, U, false),
+ FPT, U),
ClassType, Size, /*Align=*/0, Flags);
}
@@ -3285,7 +3302,7 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
break;
case Type::TypeOf:
- T = cast<TypeOfType>(T)->getUnderlyingType();
+ T = cast<TypeOfType>(T)->getUnmodifiedType();
break;
case Type::Decltype:
T = cast<DecltypeType>(T)->getUnderlyingType();
@@ -3351,7 +3368,7 @@ void CGDebugInfo::completeTemplateDefinition(
}
void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) {
- if (DebugKind <= codegenoptions::DebugLineTablesOnly)
+ if (DebugKind <= codegenoptions::DebugLineTablesOnly || D.isDynamicClass())
return;
completeClassData(&D);
@@ -3613,7 +3630,7 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
// them distinct if they are ODR-uniqued.
if (Identifier.empty())
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case llvm::dwarf::DW_TAG_structure_type:
case llvm::dwarf::DW_TAG_union_type:
@@ -3910,7 +3927,7 @@ llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) {
return SP;
}
- for (auto NextFD : FD->redecls()) {
+ for (auto *NextFD : FD->redecls()) {
auto MI = SPCache.find(NextFD->getCanonicalDecl());
if (MI != SPCache.end()) {
auto *SP = dyn_cast_or_null<llvm::DISubprogram>(MI->second);
@@ -3968,10 +3985,11 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
!CGM.getCodeGenOpts().EmitCodeView))
// Create fake but valid subroutine type. Otherwise -verify would fail, and
// subprogram DIE will miss DW_AT_decl_file and DW_AT_decl_line fields.
- return DBuilder.createSubroutineType(DBuilder.getOrCreateTypeArray(None));
+ return DBuilder.createSubroutineType(
+ DBuilder.getOrCreateTypeArray(std::nullopt));
if (const auto *Method = dyn_cast<CXXMethodDecl>(D))
- return getOrCreateMethodType(Method, F, false);
+ return getOrCreateMethodType(Method, F);
const auto *FTy = FnType->getAs<FunctionType>();
CallingConv CC = FTy ? FTy->getCallConv() : CallingConv::CC_C;
@@ -4097,8 +4115,12 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc,
if (Name.startswith("\01"))
Name = Name.substr(1);
+ assert((!D || !isa<VarDecl>(D) ||
+ GD.getDynamicInitKind() != DynamicInitKind::NoStub) &&
+ "Unexpected DynamicInitKind !");
+
if (!HasDecl || D->isImplicit() || D->hasAttr<ArtificialAttr>() ||
- (isa<VarDecl>(D) && GD.getDynamicInitKind() != DynamicInitKind::NoStub)) {
+ isa<VarDecl>(D) || isa<CapturedDecl>(D)) {
Flags |= llvm::DINode::FlagArtificial;
// Artificial functions should not silently reuse CurLoc.
CurLoc = SourceLocation();
@@ -4196,10 +4218,28 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
SPFlags |= llvm::DISubprogram::SPFlagOptimized;
llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D);
- llvm::DISubprogram *SP = DBuilder.createFunction(
- FDContext, Name, LinkageName, Unit, LineNo,
- getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
- TParamsArray.get(), getFunctionDeclaration(D), nullptr, Annotations);
+ llvm::DISubroutineType *STy = getOrCreateFunctionType(D, FnType, Unit);
+ llvm::DISubprogram *SP =
+ DBuilder.createFunction(FDContext, Name, LinkageName, Unit, LineNo, STy,
+ ScopeLine, Flags, SPFlags, TParamsArray.get(),
+ getFunctionDeclaration(D), nullptr, Annotations);
+
+ // Preserve btf_decl_tag attributes for parameters of extern functions
+ // for BPF target. The parameters created in this loop are attached as
+ // DISubprogram's retainedNodes in the subsequent finalizeSubprogram call.
+ if (IsDeclForCallSite && CGM.getTarget().getTriple().isBPF()) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ llvm::DITypeRefArray ParamTypes = STy->getTypeArray();
+ unsigned ArgNo = 1;
+ for (ParmVarDecl *PD : FD->parameters()) {
+ llvm::DINodeArray ParamAnnotations = CollectBTFDeclTagAnnotations(PD);
+ DBuilder.createParameterVariable(
+ SP, PD->getName(), ArgNo, Unit, LineNo, ParamTypes[ArgNo], true,
+ llvm::DINode::FlagZero, ParamAnnotations);
+ ++ArgNo;
+ }
+ }
+ }
if (IsDeclForCallSite)
Fn->setSubprogram(SP);
@@ -4218,17 +4258,11 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
if (Func->getSubprogram())
return;
- // Do not emit a declaration subprogram for a builtin, a function with nodebug
- // attribute, or if call site info isn't required. Also, elide declarations
- // for functions with reserved names, as call site-related features aren't
- // interesting in this case (& also, the compiler may emit calls to these
- // functions without debug locations, which makes the verifier complain).
- if (CalleeDecl->getBuiltinID() != 0 || CalleeDecl->hasAttr<NoDebugAttr>() ||
+ // Do not emit a declaration subprogram for a function with nodebug
+ // attribute, or if call site info isn't required.
+ if (CalleeDecl->hasAttr<NoDebugAttr>() ||
getCallSiteRelatedAttrs() == llvm::DINode::FlagZero)
return;
- if (CalleeDecl->isReserved(CGM.getLangOpts()) !=
- ReservedIdentifierStatus::NotReserved)
- return;
// If there is no DISubprogram attached to the function being called,
// create the one describing the function in order to have complete
@@ -4282,7 +4316,7 @@ void CGDebugInfo::CreateLexicalBlock(SourceLocation Loc) {
void CGDebugInfo::AppendAddressSpaceXDeref(
unsigned AddressSpace, SmallVectorImpl<uint64_t> &Expr) const {
- Optional<unsigned> DWARFAddressSpace =
+ std::optional<unsigned> DWARFAddressSpace =
CGM.getTarget().getDWARFAddressSpace(AddressSpace);
if (!DWARFAddressSpace)
return;
@@ -4379,7 +4413,7 @@ CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
CharUnits Align = CGM.getContext().getDeclAlign(VD);
if (Align > CGM.getContext().toCharUnitsFromBits(
- CGM.getTarget().getPointerAlign(0))) {
+ CGM.getTarget().getPointerAlign(LangAS::Default))) {
CharUnits FieldOffsetInBytes =
CGM.getContext().toCharUnitsFromBits(FieldOffset);
CharUnits AlignedOffsetInBytes = FieldOffsetInBytes.alignTo(Align);
@@ -4413,7 +4447,7 @@ CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
llvm::Value *Storage,
- llvm::Optional<unsigned> ArgNo,
+ std::optional<unsigned> ArgNo,
CGBuilderTy &Builder,
const bool UsePointerValue) {
assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
@@ -4453,7 +4487,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
auto Align = getDeclAlignIfRequired(VD, CGM.getContext());
- unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType());
+ unsigned AddressSpace = CGM.getTypes().getTargetAddressSpace(VD->getType());
AppendAddressSpaceXDeref(AddressSpace, Expr);
// If this is implicit parameter of CXXThis or ObjCSelf kind, then give it an
@@ -4479,7 +4513,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
// offset of __forwarding field
offset = CGM.getContext().toCharUnitsFromBits(
- CGM.getTarget().getPointerWidth(0));
+ CGM.getTarget().getPointerWidth(LangAS::Default));
Expr.push_back(offset.getQuantity());
Expr.push_back(llvm::dwarf::DW_OP_deref);
Expr.push_back(llvm::dwarf::DW_OP_plus_uconst);
@@ -4593,7 +4627,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD,
llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const BindingDecl *BD,
llvm::Value *Storage,
- llvm::Optional<unsigned> ArgNo,
+ std::optional<unsigned> ArgNo,
CGBuilderTy &Builder,
const bool UsePointerValue) {
assert(CGM.getCodeGenOpts().hasReducedDebugInfo());
@@ -4614,7 +4648,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const BindingDecl *BD,
return nullptr;
auto Align = getDeclAlignIfRequired(BD, CGM.getContext());
- unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(BD->getType());
+ unsigned AddressSpace = CGM.getTypes().getTargetAddressSpace(BD->getType());
SmallVector<uint64_t, 3> Expr;
AppendAddressSpaceXDeref(AddressSpace, Expr);
@@ -4684,11 +4718,11 @@ CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage,
if (auto *DD = dyn_cast<DecompositionDecl>(VD))
for (auto *B : DD->bindings()) {
- EmitDeclare(B, Storage, llvm::None, Builder,
+ EmitDeclare(B, Storage, std::nullopt, Builder,
VD->getType()->isReferenceType());
}
- return EmitDeclare(VD, Storage, llvm::None, Builder, UsePointerValue);
+ return EmitDeclare(VD, Storage, std::nullopt, Builder, UsePointerValue);
}
void CGDebugInfo::EmitLabel(const LabelDecl *D, CGBuilderTy &Builder) {
@@ -5139,7 +5173,7 @@ std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const {
if (!CGM.getCodeGenOpts().hasReducedDebugInfo())
TemplateNamesKind = codegenoptions::DebugTemplateNamesKind::Full;
- Optional<TemplateArgs> Args;
+ std::optional<TemplateArgs> Args;
bool IsOperatorOverload = false; // isa<CXXConversionDecl>(ND);
if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
@@ -5293,8 +5327,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
auto Align = getDeclAlignIfRequired(D, CGM.getContext());
SmallVector<uint64_t, 4> Expr;
- unsigned AddressSpace =
- CGM.getContext().getTargetAddressSpace(D->getType());
+ unsigned AddressSpace = CGM.getTypes().getTargetAddressSpace(D->getType());
if (CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) {
if (D->hasAttr<CUDASharedAttr>())
AddressSpace =
@@ -5380,10 +5413,18 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
llvm::DIExpression *InitExpr = nullptr;
if (CGM.getContext().getTypeSize(VD->getType()) <= 64) {
// FIXME: Add a representation for integer constants wider than 64 bits.
- if (Init.isInt())
- InitExpr =
- DBuilder.createConstantValueExpression(Init.getInt().getExtValue());
- else if (Init.isFloat())
+ if (Init.isInt()) {
+ const llvm::APSInt &InitInt = Init.getInt();
+ std::optional<uint64_t> InitIntOpt;
+ if (InitInt.isUnsigned())
+ InitIntOpt = InitInt.tryZExtValue();
+ else if (auto tmp = InitInt.trySExtValue(); tmp.has_value())
+ // Transform a signed optional to unsigned optional. When cpp 23 comes,
+ // use std::optional::transform
+ InitIntOpt = (uint64_t)tmp.value();
+ if (InitIntOpt)
+ InitExpr = DBuilder.createConstantValueExpression(InitIntOpt.value());
+ } else if (Init.isFloat())
InitExpr = DBuilder.createConstantValueExpression(
Init.getFloat().bitcastToAPInt().getZExtValue());
}
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 38e3fa5b2fa9..95484a060cd8 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -25,11 +25,11 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Allocator.h"
+#include <optional>
namespace llvm {
class MDNode;
@@ -177,7 +177,6 @@ class CGDebugInfo {
/// ivars and property accessors.
llvm::DIType *CreateType(const BuiltinType *Ty);
llvm::DIType *CreateType(const ComplexType *Ty);
- llvm::DIType *CreateType(const AutoType *Ty);
llvm::DIType *CreateType(const BitIntType *Ty);
llvm::DIType *CreateQualifiedType(QualType Ty, llvm::DIFile *Fg);
llvm::DIType *CreateQualifiedType(const FunctionProtoType *Ty,
@@ -231,10 +230,10 @@ class CGDebugInfo {
/// not updated to include implicit \c this pointer. Use this routine
/// to get a method type which includes \c this pointer.
llvm::DISubroutineType *getOrCreateMethodType(const CXXMethodDecl *Method,
- llvm::DIFile *F, bool decl);
+ llvm::DIFile *F);
llvm::DISubroutineType *
getOrCreateInstanceMethodType(QualType ThisPtr, const FunctionProtoType *Func,
- llvm::DIFile *Unit, bool decl);
+ llvm::DIFile *Unit);
llvm::DISubroutineType *
getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile *F);
/// \return debug info descriptor for vtable.
@@ -280,7 +279,7 @@ class CGDebugInfo {
llvm::ArrayRef<TemplateArgument> Args;
};
/// A helper function to collect template parameters.
- llvm::DINodeArray CollectTemplateParams(Optional<TemplateArgs> Args,
+ llvm::DINodeArray CollectTemplateParams(std::optional<TemplateArgs> Args,
llvm::DIFile *Unit);
/// A helper function to collect debug info for function template
/// parameters.
@@ -292,9 +291,9 @@ class CGDebugInfo {
llvm::DINodeArray CollectVarTemplateParams(const VarDecl *VD,
llvm::DIFile *Unit);
- Optional<TemplateArgs> GetTemplateArgs(const VarDecl *) const;
- Optional<TemplateArgs> GetTemplateArgs(const RecordDecl *) const;
- Optional<TemplateArgs> GetTemplateArgs(const FunctionDecl *) const;
+ std::optional<TemplateArgs> GetTemplateArgs(const VarDecl *) const;
+ std::optional<TemplateArgs> GetTemplateArgs(const RecordDecl *) const;
+ std::optional<TemplateArgs> GetTemplateArgs(const FunctionDecl *) const;
/// A helper function to collect debug info for template
/// parameters.
@@ -587,7 +586,7 @@ private:
/// Returns a pointer to the DILocalVariable associated with the
/// llvm.dbg.declare, or nullptr otherwise.
llvm::DILocalVariable *EmitDeclare(const VarDecl *decl, llvm::Value *AI,
- llvm::Optional<unsigned> ArgNo,
+ std::optional<unsigned> ArgNo,
CGBuilderTy &Builder,
const bool UsePointerValue = false);
@@ -595,7 +594,7 @@ private:
/// Returns a pointer to the DILocalVariable associated with the
/// llvm.dbg.declare, or nullptr otherwise.
llvm::DILocalVariable *EmitDeclare(const BindingDecl *decl, llvm::Value *AI,
- llvm::Optional<unsigned> ArgNo,
+ std::optional<unsigned> ArgNo,
CGBuilderTy &Builder,
const bool UsePointerValue = false);
@@ -631,11 +630,11 @@ private:
void CreateCompileUnit();
/// Compute the file checksum debug info for input file ID.
- Optional<llvm::DIFile::ChecksumKind>
- computeChecksum(FileID FID, SmallString<32> &Checksum) const;
+ std::optional<llvm::DIFile::ChecksumKind>
+ computeChecksum(FileID FID, SmallString<64> &Checksum) const;
/// Get the source of the given file ID.
- Optional<StringRef> getSource(const SourceManager &SM, FileID FID);
+ std::optional<StringRef> getSource(const SourceManager &SM, FileID FID);
/// Convenience function to get the file debug info descriptor for the input
/// location.
@@ -644,8 +643,8 @@ private:
/// Create a file debug info descriptor for a source file.
llvm::DIFile *
createFile(StringRef FileName,
- Optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo,
- Optional<StringRef> Source);
+ std::optional<llvm::DIFile::ChecksumInfo<StringRef>> CSInfo,
+ std::optional<StringRef> Source);
/// Get the type from the cache or create a new type if necessary.
llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg);
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index f04af0d2cdf8..ceaddc4e694a 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -37,6 +37,7 @@
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -90,6 +91,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Export:
case Decl::ObjCPropertyImpl:
case Decl::FileScopeAsm:
+ case Decl::TopLevelStmt:
case Decl::Friend:
case Decl::FriendTemplate:
case Decl::Block:
@@ -100,6 +102,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::ObjCTypeParam:
case Decl::Binding:
case Decl::UnresolvedUsingIfExists:
+ case Decl::HLSLBuffer:
llvm_unreachable("Declaration should not be in declstmts!");
case Decl::Record: // struct/union/class X;
case Decl::CXXRecord: // struct/union/class X; [C++]
@@ -126,6 +129,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::OMPRequires:
case Decl::Empty:
case Decl::Concept:
+ case Decl::ImplicitConceptSpecialization:
case Decl::LifetimeExtendedTemporary:
case Decl::RequiresExprBody:
// None of these decls require codegen support.
@@ -755,7 +759,7 @@ void CodeGenFunction::EmitNullabilityCheck(LValue LHS, llvm::Value *RHS,
if (!SanOpts.has(SanitizerKind::NullabilityAssign))
return;
- auto Nullability = LHS.getType()->getNullability(getContext());
+ auto Nullability = LHS.getType()->getNullability();
if (!Nullability || *Nullability != NullabilityKind::NonNull)
return;
@@ -839,7 +843,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
// If D is pseudo-strong, treat it like __unsafe_unretained here. This means
// that we omit the retain, and causes non-autoreleased return values to be
// immediately released.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case Qualifiers::OCL_ExplicitNone:
@@ -2612,7 +2616,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
// function satisfy their nullability preconditions. This makes it necessary
// to emit null checks for args in the function body itself.
if (requiresReturnValueNullabilityCheck()) {
- auto Nullability = Ty->getNullability(getContext());
+ auto Nullability = Ty->getNullability();
if (Nullability && *Nullability == NullabilityKind::NonNull) {
SanitizerScope SanScope(this);
RetValNullabilityPrecondition =
@@ -2695,7 +2699,7 @@ void CodeGenModule::EmitOMPAllocateDecl(const OMPAllocateDecl *D) {
}
}
-llvm::Optional<CharUnits>
+std::optional<CharUnits>
CodeGenModule::getOMPAllocateAlignment(const VarDecl *VD) {
if (const auto *AA = VD->getAttr<OMPAllocateDeclAttr>()) {
if (Expr *Alignment = AA->getAlignment()) {
@@ -2711,5 +2715,5 @@ CodeGenModule::getOMPAllocateAlignment(const VarDecl *VD) {
std::max<unsigned>(UserAlign, NaturalAlign.getQuantity()));
}
}
- return llvm::None;
+ return std::nullopt;
}
diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index 949112c63cc9..dcd811ea257b 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "CGCXXABI.h"
+#include "CGHLSLRuntime.h"
#include "CGObjCRuntime.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenFunction.h"
@@ -194,7 +195,7 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
// For example, in the above CUDA code, the static local variable s has a
// "shared" address space qualifier, but the constructor of StructWithCtor
// expects "this" in the "generic" address space.
- unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(T);
+ unsigned ExpectedAddrSpace = getTypes().getTargetAddressSpace(T);
unsigned ActualAddrSpace = GV->getAddressSpace();
llvm::Constant *DeclPtr = GV;
if (ActualAddrSpace != ExpectedAddrSpace) {
@@ -552,7 +553,18 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
CXXThreadLocalInits.push_back(Fn);
CXXThreadLocalInitVars.push_back(D);
} else if (PerformInit && ISA) {
- EmitPointerToInitFunc(D, Addr, Fn, ISA);
+ // Contract with backend that "init_seg(compiler)" corresponds to priority
+ // 200 and "init_seg(lib)" corresponds to priority 400.
+ int Priority = -1;
+ if (ISA->getSection() == ".CRT$XCC")
+ Priority = 200;
+ else if (ISA->getSection() == ".CRT$XCL")
+ Priority = 400;
+
+ if (Priority != -1)
+ AddGlobalCtor(Fn, Priority, ~0U, COMDATKey);
+ else
+ EmitPointerToInitFunc(D, Addr, Fn, ISA);
} else if (auto *IPA = D->getAttr<InitPriorityAttr>()) {
OrderGlobalInitsOrStermFinalizers Key(IPA->getPriority(),
PrioritizedCXXGlobalInits.size());
@@ -576,8 +588,16 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
// SelectAny globals will be comdat-folded. Put the initializer into a
// COMDAT group associated with the global, so the initializers get folded
// too.
-
- AddGlobalCtor(Fn, 65535, COMDATKey);
+ I = DelayedCXXInitPosition.find(D);
+ // CXXGlobalInits.size() is the lex order number for the next deferred
+ // VarDecl. Use it when the current VarDecl is non-deferred. Although this
+ // lex order number is shared between current VarDecl and some following
+ // VarDecls, their order of insertion into `llvm.global_ctors` is the same
+ // as the lexing order and the following stable sort would preserve such
+ // order.
+ unsigned LexOrder =
+ I == DelayedCXXInitPosition.end() ? CXXGlobalInits.size() : I->second;
+ AddGlobalCtor(Fn, 65535, LexOrder, COMDATKey);
if (COMDATKey && (getTriple().isOSBinFormatELF() ||
getTarget().getCXXABI().isMicrosoft())) {
// When COMDAT is used on ELF or in the MS C++ ABI, the key must be in
@@ -620,7 +640,12 @@ void CodeGenModule::EmitCXXThreadLocalInitFunc() {
/* Build the initializer for a C++20 module:
This is arranged to be run only once regardless of how many times the module
- might be included transitively. This arranged by using a control variable.
+ might be included transitively. This arranged by using a guard variable.
+
+ If there are no initalizers at all (and also no imported modules) we reduce
+ this to an empty function (since the Itanium ABI requires that this function
+ be available to a caller, which might be produced by a different
+ implementation).
First we call any initializers for imported modules.
We then call initializers for the Global Module Fragment (if present)
@@ -632,13 +657,10 @@ void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) {
while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
CXXGlobalInits.pop_back();
- // We create the function, even if it is empty, since an importer of this
- // module will refer to it unconditionally (for the current implementation
- // there is no way for the importer to know that an importee does not need
- // an initializer to be run).
-
+ // As noted above, we create the function, even if it is empty.
// Module initializers for imported modules are emitted first.
- // Collect the modules that we import
+
+ // Collect all the modules that we import
SmallVector<Module *> AllImports;
// Ones that we export
for (auto I : Primary->Exports)
@@ -649,8 +671,8 @@ void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) {
SmallVector<llvm::Function *, 8> ModuleInits;
for (Module *M : AllImports) {
- // No Itanium initializer in module map modules.
- if (M->isModuleMapModule())
+ // No Itanium initializer in header like modules.
+ if (M->isHeaderLikeModule())
continue; // TODO: warn of mixed use of module map modules and C++20?
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
SmallString<256> FnName;
@@ -665,7 +687,6 @@ void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) {
FTy, llvm::Function::ExternalLinkage, FnName.str(), &getModule());
ModuleInits.push_back(Fn);
}
- AllImports.clear();
// Add any initializers with specified priority; this uses the same approach
// as EmitCXXGlobalInitFunc().
@@ -683,13 +704,11 @@ void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) {
for (; I < PrioE; ++I)
ModuleInits.push_back(I->second);
}
- PrioritizedCXXGlobalInits.clear();
}
// Now append the ones without specified priority.
- for (auto F : CXXGlobalInits)
+ for (auto *F : CXXGlobalInits)
ModuleInits.push_back(F);
- CXXGlobalInits.clear();
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction();
@@ -699,7 +718,6 @@ void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) {
// each init is run just once (even though a module might be imported
// multiple times via nested use).
llvm::Function *Fn;
- llvm::GlobalVariable *Guard = nullptr;
{
SmallString<256> InitFnName;
llvm::raw_svector_ostream Out(InitFnName);
@@ -709,18 +727,26 @@ void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) {
FTy, llvm::Twine(InitFnName), FI, SourceLocation(), false,
llvm::GlobalVariable::ExternalLinkage);
- Guard = new llvm::GlobalVariable(getModule(), Int8Ty, /*isConstant=*/false,
- llvm::GlobalVariable::InternalLinkage,
- llvm::ConstantInt::get(Int8Ty, 0),
- InitFnName.str() + "__in_chrg");
+ // If we have a completely empty initializer then we do not want to create
+ // the guard variable.
+ ConstantAddress GuardAddr = ConstantAddress::invalid();
+ if (!AllImports.empty() || !PrioritizedCXXGlobalInits.empty() ||
+ !CXXGlobalInits.empty()) {
+ // Create the guard var.
+ llvm::GlobalVariable *Guard = new llvm::GlobalVariable(
+ getModule(), Int8Ty, /*isConstant=*/false,
+ llvm::GlobalVariable::InternalLinkage,
+ llvm::ConstantInt::get(Int8Ty, 0), InitFnName.str() + "__in_chrg");
+ CharUnits GuardAlign = CharUnits::One();
+ Guard->setAlignment(GuardAlign.getAsAlign());
+ GuardAddr = ConstantAddress(Guard, Int8Ty, GuardAlign);
+ }
+ CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, ModuleInits,
+ GuardAddr);
}
- CharUnits GuardAlign = CharUnits::One();
- Guard->setAlignment(GuardAlign.getAsAlign());
- CodeGenFunction(*this).GenerateCXXGlobalInitFunc(
- Fn, ModuleInits, ConstantAddress(Guard, Int8Ty, GuardAlign));
- // We allow for the case that a module object is added to a linked binary
- // without a specific call to the the initializer. This also ensure that
+ // We allow for the case that a module object is added to a linked binary
+ // without a specific call to the the initializer. This also ensures that
// implementation partition initializers are called when the partition
// is not imported as an interface.
AddGlobalCtor(Fn);
@@ -739,6 +765,10 @@ void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) {
Fn->addFnAttr("device-init");
}
+ // We are done with the inits.
+ AllImports.clear();
+ PrioritizedCXXGlobalInits.clear();
+ CXXGlobalInits.clear();
ModuleInits.clear();
}
@@ -778,8 +808,8 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
SmallVector<llvm::Function *, 8> ModuleInits;
if (CXX20ModuleInits)
for (Module *M : ImportedModules) {
- // No Itanium initializer in module map modules.
- if (M->isModuleMapModule())
+ // No Itanium initializer in header like modules.
+ if (M->isHeaderLikeModule())
continue;
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
SmallString<256> FnName;
@@ -824,7 +854,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
// Prepend the module inits to the highest priority set.
if (!ModuleInits.empty()) {
- for (auto F : ModuleInits)
+ for (auto *F : ModuleInits)
LocalCXXGlobalInits.push_back(F);
ModuleInits.clear();
}
@@ -842,7 +872,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
CXXGlobalInits.empty())
return;
- for (auto F : CXXGlobalInits)
+ for (auto *F : CXXGlobalInits)
ModuleInits.push_back(F);
CXXGlobalInits.clear();
@@ -977,6 +1007,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
EmitCXXGlobalVarDeclInit(*D, Addr, PerformInit);
}
+ if (getLangOpts().HLSL)
+ CGM.getHLSLRuntime().annotateHLSLResource(D, Addr);
+
FinishFunction();
}
diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 76c6beb090a9..6fa7871588f7 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -158,7 +158,7 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
case ObjCRuntime::GNUstep:
if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
return EHPersonality::GNUstep_ObjC;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ObjCRuntime::GCC:
case ObjCRuntime::ObjFW:
if (L.hasSjLjExceptions())
@@ -249,7 +249,7 @@ const EHPersonality &EHPersonality::get(CodeGenFunction &CGF) {
// For outlined finallys and filters, use the SEH personality in case they
// contain more SEH. This mostly only affects finallys. Filters could
// hypothetically use gnu statement expressions to sneak in nested SEH.
- FD = FD ? FD : CGF.CurSEHParent;
+ FD = FD ? FD : CGF.CurSEHParent.getDecl();
return get(CGF.CGM, dyn_cast_or_null<FunctionDecl>(FD));
}
@@ -1223,8 +1223,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
// Wasm uses Windows-style EH instructions, but merges all catch clauses into
// one big catchpad. So we save the old funclet pad here before we traverse
// each catch handler.
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
+ SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad);
llvm::BasicBlock *WasmCatchStartBlock = nullptr;
if (EHPersonality::get(*this).isWasmPersonality()) {
auto *CatchSwitch =
@@ -1257,8 +1256,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
RunCleanupsScope CatchScope(*this);
// Initialize the catch variable and set up the cleanups.
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
+ SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad);
CGM.getCXXABI().emitBeginCatch(*this, C);
// Emit the PGO counter increment.
@@ -1582,8 +1580,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateFunclet() {
// Create the cleanuppad using the current parent pad as its token. Use 'none'
// if this is a top-level terminate scope, which is the common case.
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
- CurrentFuncletPad);
+ SaveAndRestore RestoreCurrentFuncletPad(CurrentFuncletPad);
llvm::Value *ParentPad = CurrentFuncletPad;
if (!ParentPad)
ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());
@@ -1628,7 +1625,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
llvm::Value *Sel = getSelectorFromSlot();
llvm::Type *LPadType = llvm::StructType::get(Exn->getType(), Sel->getType());
- llvm::Value *LPadVal = llvm::UndefValue::get(LPadType);
+ llvm::Value *LPadVal = llvm::PoisonValue::get(LPadType);
LPadVal = Builder.CreateInsertValue(LPadVal, Exn, 0, "lpad.val");
LPadVal = Builder.CreateInsertValue(LPadVal, Sel, 1, "lpad.val");
@@ -2005,7 +2002,7 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
SmallString<128> Name;
{
llvm::raw_svector_ostream OS(Name);
- const NamedDecl *ParentSEHFn = ParentCGF.CurSEHParent;
+ GlobalDecl ParentSEHFn = ParentCGF.CurSEHParent;
assert(ParentSEHFn && "No CurSEHParent!");
MangleContext &Mangler = CGM.getCXXABI().getMangleContext();
if (IsFilter)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index bf3dd812b9e8..c26dd1b23321 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -42,6 +42,7 @@
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
+#include <optional>
#include <string>
using namespace clang;
@@ -123,7 +124,7 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
Address CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty,
const Twine &Name) {
CharUnits Align =
- CharUnits::fromQuantity(CGM.getDataLayout().getPrefTypeAlignment(Ty));
+ CharUnits::fromQuantity(CGM.getDataLayout().getPrefTypeAlign(Ty));
return CreateTempAlloca(Ty, Align, Name);
}
@@ -875,52 +876,6 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
}
}
-/// Determine whether this expression refers to a flexible array member in a
-/// struct. We disable array bounds checks for such members.
-static bool isFlexibleArrayMemberExpr(const Expr *E,
- unsigned StrictFlexArraysLevel) {
- // For compatibility with existing code, we treat arrays of length 0 or
- // 1 as flexible array members.
- // FIXME: This is inconsistent with the warning code in SemaChecking. Unify
- // the two mechanisms.
- const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe();
- if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- // FIXME: Sema doesn't treat [1] as a flexible array member if the bound
- // was produced by macro expansion.
- if (StrictFlexArraysLevel >= 2 && CAT->getSize().ugt(0))
- return false;
- // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing
- // arrays to be treated as flexible-array-members, we still emit ubsan
- // checks as if they are not.
- if (CAT->getSize().ugt(1))
- return false;
- } else if (!isa<IncompleteArrayType>(AT))
- return false;
-
- E = E->IgnoreParens();
-
- // A flexible array member must be the last member in the class.
- if (const auto *ME = dyn_cast<MemberExpr>(E)) {
- // FIXME: If the base type of the member expr is not FD->getParent(),
- // this should not be treated as a flexible array member access.
- if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- // FIXME: Sema doesn't treat a T[1] union member as a flexible array
- // member, only a T[0] or T[] member gets that treatment.
- // Under StrictFlexArraysLevel, obey c99+ that disallows FAM in union, see
- // C11 6.7.2.1 §18
- if (FD->getParent()->isUnion())
- return StrictFlexArraysLevel < 2;
- RecordDecl::field_iterator FI(
- DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
- return ++FI == FD->getParent()->field_end();
- }
- } else if (const auto *IRE = dyn_cast<ObjCIvarRefExpr>(E)) {
- return IRE->getDecl()->getNextIvar() == nullptr;
- }
-
- return false;
-}
-
llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E,
QualType EltTy) {
ASTContext &C = getContext();
@@ -965,7 +920,8 @@ llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E,
static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
const Expr *Base,
QualType &IndexedType,
- unsigned StrictFlexArraysLevel) {
+ LangOptions::StrictFlexArraysLevelKind
+ StrictFlexArraysLevel) {
// For the vector indexing extension, the bound is the number of elements.
if (const VectorType *VT = Base->getType()->getAs<VectorType>()) {
IndexedType = Base->getType();
@@ -976,7 +932,8 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
if (const auto *CE = dyn_cast<CastExpr>(Base)) {
if (CE->getCastKind() == CK_ArrayToPointerDecay &&
- !isFlexibleArrayMemberExpr(CE->getSubExpr(), StrictFlexArraysLevel)) {
+ !CE->getSubExpr()->isFlexibleArrayMemberLike(CGF.getContext(),
+ StrictFlexArraysLevel)) {
IndexedType = CE->getSubExpr()->getType();
const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe();
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
@@ -1003,7 +960,8 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
"should not be called unless adding bounds checks");
SanitizerScope SanScope(this);
- const unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays;
+ const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
+ getLangOpts().getStrictFlexArraysLevel();
QualType IndexedType;
llvm::Value *Bound =
@@ -1426,6 +1384,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitOMPArraySectionExpr(cast<OMPArraySectionExpr>(E));
case Expr::ExtVectorElementExprClass:
return EmitExtVectorElementExpr(cast<ExtVectorElementExpr>(E));
+ case Expr::CXXThisExprClass:
+ return MakeAddrLValue(LoadCXXThisAddress(), E->getType());
case Expr::MemberExprClass:
return EmitMemberExpr(cast<MemberExpr>(E));
case Expr::CompoundLiteralExprClass:
@@ -1661,21 +1621,7 @@ static bool getRangeForType(CodeGenFunction &CGF, QualType Ty,
End = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
} else {
const EnumDecl *ED = ET->getDecl();
- llvm::Type *LTy = CGF.ConvertTypeForMem(ED->getIntegerType());
- unsigned Bitwidth = LTy->getScalarSizeInBits();
- unsigned NumNegativeBits = ED->getNumNegativeBits();
- unsigned NumPositiveBits = ED->getNumPositiveBits();
-
- if (NumNegativeBits) {
- unsigned NumBits = std::max(NumNegativeBits, NumPositiveBits + 1);
- assert(NumBits <= Bitwidth);
- End = llvm::APInt(Bitwidth, 1) << (NumBits - 1);
- Min = -End;
- } else {
- assert(NumPositiveBits <= Bitwidth);
- End = llvm::APInt(Bitwidth, 1) << NumPositiveBits;
- Min = llvm::APInt::getZero(Bitwidth);
- }
+ ED->getValueRange(End, Min);
}
return true;
}
@@ -1743,6 +1689,10 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
LValueBaseInfo BaseInfo,
TBAAAccessInfo TBAAInfo,
bool isNontemporal) {
+ if (auto *GV = dyn_cast<llvm::GlobalValue>(Addr.getPointer()))
+ if (GV->isThreadLocal())
+ Addr = Addr.withPointer(Builder.CreateThreadLocalAddress(GV));
+
if (const auto *ClangVecTy = Ty->getAs<VectorType>()) {
// Boolean vectors use `iN` as storage type.
if (ClangVecTy->isExtVectorBoolType()) {
@@ -1802,8 +1752,11 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
// In order to prevent the optimizer from throwing away the check, don't
// attach range metadata to the load.
} else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
- if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
+ if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty)) {
Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
+ Load->setMetadata(llvm::LLVMContext::MD_noundef,
+ llvm::MDNode::get(getLLVMContext(), std::nullopt));
+ }
return EmitFromMemory(Load, Ty);
}
@@ -1884,6 +1837,10 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
LValueBaseInfo BaseInfo,
TBAAAccessInfo TBAAInfo,
bool isInit, bool isNontemporal) {
+ if (auto *GV = dyn_cast<llvm::GlobalValue>(Addr.getPointer()))
+ if (GV->isThreadLocal())
+ Addr = Addr.withPointer(Builder.CreateThreadLocalAddress(GV));
+
llvm::Type *SrcTy = Value->getType();
if (const auto *ClangVecTy = Ty->getAs<VectorType>()) {
auto *VecTy = dyn_cast<llvm::FixedVectorType>(SrcTy);
@@ -2537,16 +2494,18 @@ static LValue EmitThreadPrivateVarDeclLValue(
static Address emitDeclTargetVarDeclLValue(CodeGenFunction &CGF,
const VarDecl *VD, QualType T) {
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- // Return an invalid address if variable is MT_To and unified
- // memory is not enabled. For all other cases: MT_Link and
- // MT_To with unified memory, return a valid address.
- if (!Res || (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ // Return an invalid address if variable is MT_To (or MT_Enter starting with
+ // OpenMP 5.2) and unified memory is not enabled. For all other cases: MT_Link
+ // and MT_To (or MT_Enter) with unified memory, return a valid address.
+ if (!Res || ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
!CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory()))
return Address::invalid();
assert(((*Res == OMPDeclareTargetDeclAttr::MT_Link) ||
- (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory())) &&
"Expected link clause OR to clause with unified memory enabled.");
QualType PtrTy = CGF.getContext().getPointerType(VD->getType());
@@ -2614,6 +2573,10 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
}
llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
+
+ if (VD->getTLSKind() != VarDecl::TLS_None)
+ V = CGF.Builder.CreateThreadLocalAddress(V);
+
llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType());
V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
@@ -2785,7 +2748,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
getContext().getDeclAlign(VD));
llvm::Type *VarTy = getTypes().ConvertTypeForMem(VD->getType());
auto *PTy = llvm::PointerType::get(
- VarTy, getContext().getTargetAddressSpace(VD->getType()));
+ VarTy, getTypes().getTargetAddressSpace(VD->getType()));
Addr = Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, PTy, VarTy);
} else {
// Should we be using the alignment of the constant pointer we emitted?
@@ -2883,6 +2846,10 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
llvm_unreachable("DeclRefExpr for Decl not entered in LocalDeclMap?");
}
+ // Handle threadlocal function locals.
+ if (VD->getTLSKind() != VarDecl::TLS_None)
+ addr =
+ addr.withPointer(Builder.CreateThreadLocalAddress(addr.getPointer()));
// Check for OpenMP threadprivate variables.
if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd &&
@@ -2940,8 +2907,13 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
// FIXME: While we're emitting a binding from an enclosing scope, all other
// DeclRefExprs we see should be implicitly treated as if they also refer to
// an enclosing scope.
- if (const auto *BD = dyn_cast<BindingDecl>(ND))
+ if (const auto *BD = dyn_cast<BindingDecl>(ND)) {
+ if (E->refersToEnclosingVariableOrCapture()) {
+ auto *FD = LambdaCaptureFields.lookup(BD);
+ return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
+ }
return EmitLValue(BD->getBinding());
+ }
// We can form DeclRefExprs naming GUID declarations when reconstituting
// non-type template parameters into expressions.
@@ -3090,10 +3062,9 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
// Format the type name as if for a diagnostic, including quotes and
// optionally an 'aka'.
SmallString<32> Buffer;
- CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
- (intptr_t)T.getAsOpaquePtr(),
- StringRef(), StringRef(), None, Buffer,
- None);
+ CGM.getDiags().ConvertArgToString(
+ DiagnosticsEngine::ak_qualtype, (intptr_t)T.getAsOpaquePtr(), StringRef(),
+ StringRef(), std::nullopt, Buffer, std::nullopt);
llvm::Constant *Components[] = {
Builder.getInt16(TypeKind), Builder.getInt16(TypeInfo),
@@ -3122,7 +3093,7 @@ llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
// Floating-point types which fit into intptr_t are bitcast to integers
// and then passed directly (after zero-extension, if necessary).
if (V->getType()->isFloatingPointTy()) {
- unsigned Bits = V->getType()->getPrimitiveSizeInBits().getFixedSize();
+ unsigned Bits = V->getType()->getPrimitiveSizeInBits().getFixedValue();
if (Bits <= TargetTy->getIntegerBitWidth())
V = Builder.CreateBitCast(V, llvm::Type::getIntNTy(getLLVMContext(),
Bits));
@@ -3186,7 +3157,8 @@ llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
auto FilenameGV =
CGM.GetAddrOfConstantCString(std::string(FilenameString), ".src");
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(
- cast<llvm::GlobalVariable>(FilenameGV.getPointer()));
+ cast<llvm::GlobalVariable>(
+ FilenameGV.getPointer()->stripPointerCasts()));
Filename = FilenameGV.getPointer();
Line = PLoc.getLine();
Column = PLoc.getColumn();
@@ -3244,7 +3216,7 @@ static void emitCheckHandlerCall(CodeGenFunction &CGF,
CheckRecoverableKind RecoverKind, bool IsFatal,
llvm::BasicBlock *ContBB) {
assert(IsFatal || RecoverKind != CheckRecoverableKind::Unrecoverable);
- Optional<ApplyDebugLocation> DL;
+ std::optional<ApplyDebugLocation> DL;
if (!CGF.Builder.getCurrentDebugLocation()) {
// Ensure that the call has at least an artificial debug location.
DL.emplace(CGF, SourceLocation());
@@ -3292,7 +3264,7 @@ void CodeGenFunction::EmitCheck(
assert(IsSanitizerScope);
assert(Checked.size() > 0);
assert(CheckHandler >= 0 &&
- size_t(CheckHandler) < llvm::array_lengthof(SanitizerHandlers));
+ size_t(CheckHandler) < std::size(SanitizerHandlers));
const StringRef CheckName = SanitizerHandlers[CheckHandler].Name;
llvm::Value *FatalCond = nullptr;
@@ -3354,13 +3326,15 @@ void CodeGenFunction::EmitCheck(
// Emit handler arguments and create handler function type.
if (!StaticArgs.empty()) {
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
- auto *InfoPtr =
- new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
- llvm::GlobalVariable::PrivateLinkage, Info);
+ auto *InfoPtr = new llvm::GlobalVariable(
+ CGM.getModule(), Info->getType(), false,
+ llvm::GlobalVariable::PrivateLinkage, Info, "", nullptr,
+ llvm::GlobalVariable::NotThreadLocal,
+ CGM.getDataLayout().getDefaultGlobalsAddressSpace());
InfoPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(InfoPtr);
- Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy));
- ArgTypes.push_back(Int8PtrTy);
+ Args.push_back(EmitCastToVoidPtr(InfoPtr));
+ ArgTypes.push_back(Args.back()->getType());
}
for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) {
@@ -3561,7 +3535,7 @@ void CodeGenFunction::EmitUnreachable(SourceLocation Loc) {
EmitCheck(std::make_pair(static_cast<llvm::Value *>(Builder.getFalse()),
SanitizerKind::Unreachable),
SanitizerHandler::BuiltinUnreachable,
- EmitCheckSourceLocation(Loc), None);
+ EmitCheckSourceLocation(Loc), std::nullopt);
}
Builder.CreateUnreachable();
}
@@ -3576,7 +3550,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
TrapBBs.resize(CheckHandlerID + 1);
llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];
- if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB) {
+ if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB ||
+ (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>())) {
TrapBB = createBasicBlock("trap");
Builder.CreateCondBr(Checked, Cont, TrapBB);
EmitBlock(TrapBB);
@@ -3755,7 +3730,7 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
const llvm::Twine &name = "arrayidx") {
// All the indices except that last must be zero.
#ifndef NDEBUG
- for (auto idx : indices.drop_back())
+ for (auto *idx : indices.drop_back())
assert(isa<llvm::ConstantInt>(idx) &&
cast<llvm::ConstantInt>(idx)->isZero());
#endif
@@ -4038,14 +4013,15 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
llvm::APSInt ConstLength;
if (Length) {
// Idx = LowerBound + Length - 1;
- if (Optional<llvm::APSInt> CL = Length->getIntegerConstantExpr(C)) {
+ if (std::optional<llvm::APSInt> CL = Length->getIntegerConstantExpr(C)) {
ConstLength = CL->zextOrTrunc(PointerWidthInBits);
Length = nullptr;
}
auto *LowerBound = E->getLowerBound();
llvm::APSInt ConstLowerBound(PointerWidthInBits, /*isUnsigned=*/false);
if (LowerBound) {
- if (Optional<llvm::APSInt> LB = LowerBound->getIntegerConstantExpr(C)) {
+ if (std::optional<llvm::APSInt> LB =
+ LowerBound->getIntegerConstantExpr(C)) {
ConstLowerBound = LB->zextOrTrunc(PointerWidthInBits);
LowerBound = nullptr;
}
@@ -4085,7 +4061,7 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
: BaseTy;
if (auto *VAT = C.getAsVariableArrayType(ArrayTy)) {
Length = VAT->getSizeExpr();
- if (Optional<llvm::APSInt> L = Length->getIntegerConstantExpr(C)) {
+ if (std::optional<llvm::APSInt> L = Length->getIntegerConstantExpr(C)) {
ConstLength = *L;
Length = nullptr;
}
@@ -4292,7 +4268,7 @@ unsigned CodeGenFunction::getDebugInfoFIndex(const RecordDecl *Rec,
unsigned FieldIndex) {
unsigned I = 0, Skipped = 0;
- for (auto F : Rec->getDefinition()->fields()) {
+ for (auto *F : Rec->getDefinition()->fields()) {
if (I == FieldIndex)
break;
if (F->isUnnamedBitfield())
@@ -4596,11 +4572,11 @@ LValue CodeGenFunction::EmitInitListLValue(const InitListExpr *E) {
/// Emit the operand of a glvalue conditional operator. This is either a glvalue
/// or a (possibly-parenthesized) throw-expression. If this is a throw, no
/// LValue is returned and the current block has been terminated.
-static Optional<LValue> EmitLValueOrThrowExpression(CodeGenFunction &CGF,
- const Expr *Operand) {
+static std::optional<LValue> EmitLValueOrThrowExpression(CodeGenFunction &CGF,
+ const Expr *Operand) {
if (auto *ThrowExpr = dyn_cast<CXXThrowExpr>(Operand->IgnoreParens())) {
CGF.EmitCXXThrowExpr(ThrowExpr, /*KeepInsertionPoint*/false);
- return None;
+ return std::nullopt;
}
return CGF.EmitLValue(Operand);
@@ -4609,7 +4585,7 @@ static Optional<LValue> EmitLValueOrThrowExpression(CodeGenFunction &CGF,
namespace {
// Handle the case where the condition is a constant evaluatable simple integer,
// which means we don't have to separately handle the true/false blocks.
-llvm::Optional<LValue> HandleConditionalOperatorLValueSimpleCase(
+std::optional<LValue> HandleConditionalOperatorLValueSimpleCase(
CodeGenFunction &CGF, const AbstractConditionalOperator *E) {
const Expr *condExpr = E->getCond();
bool CondExprBool;
@@ -4635,11 +4611,11 @@ llvm::Optional<LValue> HandleConditionalOperatorLValueSimpleCase(
return CGF.EmitLValue(Live);
}
}
- return llvm::None;
+ return std::nullopt;
}
struct ConditionalInfo {
llvm::BasicBlock *lhsBlock, *rhsBlock;
- Optional<LValue> LHS, RHS;
+ std::optional<LValue> LHS, RHS;
};
// Create and generate the 3 blocks for a conditional operator.
@@ -4649,8 +4625,8 @@ ConditionalInfo EmitConditionalBlocks(CodeGenFunction &CGF,
const AbstractConditionalOperator *E,
const FuncTy &BranchGenFunc) {
ConditionalInfo Info{CGF.createBasicBlock("cond.true"),
- CGF.createBasicBlock("cond.false"), llvm::None,
- llvm::None};
+ CGF.createBasicBlock("cond.false"), std::nullopt,
+ std::nullopt};
llvm::BasicBlock *endBlock = CGF.createBasicBlock("cond.end");
CodeGenFunction::ConditionalEvaluation eval(CGF);
@@ -4708,7 +4684,7 @@ LValue CodeGenFunction::EmitConditionalOperatorLValue(
}
OpaqueValueMapping binding(*this, expr);
- if (llvm::Optional<LValue> Res =
+ if (std::optional<LValue> Res =
HandleConditionalOperatorLValueSimpleCase(*this, expr))
return *Res;
@@ -5046,7 +5022,9 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
if (auto builtinID = FD->getBuiltinID()) {
std::string NoBuiltinFD = ("no-builtin-" + FD->getName()).str();
std::string NoBuiltins = "no-builtins";
- std::string FDInlineName = (FD->getName() + ".inline").str();
+
+ StringRef Ident = CGF.CGM.getMangledName(GD);
+ std::string FDInlineName = (Ident + ".inline").str();
bool IsPredefinedLibFunction =
CGF.getContext().BuiltinInfo.isPredefinedLibFunction(builtinID);
@@ -5271,6 +5249,15 @@ llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface,
return CGM.getObjCRuntime().EmitIvarOffset(*this, Interface, Ivar);
}
+llvm::Value *
+CodeGenFunction::EmitIvarOffsetAsPointerDiff(const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar) {
+ llvm::Value *OffsetValue = EmitIvarOffset(Interface, Ivar);
+ QualType PointerDiffType = getContext().getPointerDiffType();
+ return Builder.CreateZExtOrTrunc(OffsetValue,
+ getTypes().ConvertType(PointerDiffType));
+}
+
LValue CodeGenFunction::EmitLValueForIvar(QualType ObjectTy,
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 73b05690537d..34e535a78dd6 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -87,8 +87,9 @@ public:
void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
- void EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
- QualType ArrayQTy, InitListExpr *E);
+ void EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, QualType ArrayQTy,
+ Expr *ExprToVisit, ArrayRef<Expr *> Args,
+ Expr *ArrayFiller);
AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) {
if (CGF.getLangOpts().getGC() && TypeRequiresGCollection(T))
@@ -172,6 +173,9 @@ public:
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
void VisitChooseExpr(const ChooseExpr *CE);
void VisitInitListExpr(InitListExpr *E);
+ void VisitCXXParenListOrInitListExpr(Expr *ExprToVisit, ArrayRef<Expr *> Args,
+ FieldDecl *InitializedFieldInUnion,
+ Expr *ArrayFiller);
void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
llvm::Value *outerBegin = nullptr);
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
@@ -201,10 +205,22 @@ public:
return EmitFinalDestCopy(E->getType(), LV);
}
- CGF.EmitPseudoObjectRValue(E, EnsureSlot(E->getType()));
+ AggValueSlot Slot = EnsureSlot(E->getType());
+ bool NeedsDestruction =
+ !Slot.isExternallyDestructed() &&
+ E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct;
+ if (NeedsDestruction)
+ Slot.setExternallyDestructed();
+ CGF.EmitPseudoObjectRValue(E, Slot);
+ if (NeedsDestruction)
+ CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Slot.getAddress(),
+ E->getType());
}
void VisitVAArgExpr(VAArgExpr *E);
+ void VisitCXXParenListInitExpr(CXXParenListInitExpr *E);
+ void VisitCXXParenListOrInitListExpr(Expr *ExprToVisit, ArrayRef<Expr *> Args,
+ Expr *ArrayFiller);
void EmitInitializationToLValue(Expr *E, LValue Address);
void EmitNullInitializationToLValue(LValue Address);
@@ -471,10 +487,12 @@ static bool isTrivialFiller(Expr *E) {
return false;
}
-/// Emit initialization of an array from an initializer list.
+/// Emit initialization of an array from an initializer list. ExprToVisit must
+/// be either an InitListEpxr a CXXParenInitListExpr.
void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
- QualType ArrayQTy, InitListExpr *E) {
- uint64_t NumInitElements = E->getNumInits();
+ QualType ArrayQTy, Expr *ExprToVisit,
+ ArrayRef<Expr *> Args, Expr *ArrayFiller) {
+ uint64_t NumInitElements = Args.size();
uint64_t NumArrayElements = AType->getNumElements();
assert(NumInitElements <= NumArrayElements);
@@ -503,7 +521,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
CodeGen::CodeGenModule &CGM = CGF.CGM;
ConstantEmitter Emitter(CGF);
LangAS AS = ArrayQTy.getAddressSpace();
- if (llvm::Constant *C = Emitter.tryEmitForInitializer(E, AS, ArrayQTy)) {
+ if (llvm::Constant *C =
+ Emitter.tryEmitForInitializer(ExprToVisit, AS, ArrayQTy)) {
auto GV = new llvm::GlobalVariable(
CGM.getModule(), C->getType(),
CGM.isTypeConstant(ArrayQTy, /* ExcludeCtorDtor= */ true),
@@ -568,12 +587,11 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
LValue elementLV = CGF.MakeAddrLValue(
Address(element, llvmElementType, elementAlign), elementType);
- EmitInitializationToLValue(E->getInit(i), elementLV);
+ EmitInitializationToLValue(Args[i], elementLV);
}
// Check whether there's a non-trivial array-fill expression.
- Expr *filler = E->getArrayFiller();
- bool hasTrivialFiller = isTrivialFiller(filler);
+ bool hasTrivialFiller = isTrivialFiller(ArrayFiller);
// Any remaining elements need to be zero-initialized, possibly
// using the filler expression. We can skip this if the we're
@@ -616,8 +634,8 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
CodeGenFunction::RunCleanupsScope CleanupsScope(CGF);
LValue elementLV = CGF.MakeAddrLValue(
Address(currentElement, llvmElementType, elementAlign), elementType);
- if (filler)
- EmitInitializationToLValue(filler, elementLV);
+ if (ArrayFiller)
+ EmitInitializationToLValue(ArrayFiller, elementLV);
else
EmitNullInitializationToLValue(elementLV);
}
@@ -850,7 +868,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
return;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CK_NoOp:
@@ -1591,46 +1609,64 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
}
}
+void AggExprEmitter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
+ VisitCXXParenListOrInitListExpr(E, E->getInitExprs(),
+ E->getInitializedFieldInUnion(),
+ E->getArrayFiller());
+}
+
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
+ if (E->hadArrayRangeDesignator())
+ CGF.ErrorUnsupported(E, "GNU array range designator extension");
+
+ if (E->isTransparent())
+ return Visit(E->getInit(0));
+
+ VisitCXXParenListOrInitListExpr(
+ E, E->inits(), E->getInitializedFieldInUnion(), E->getArrayFiller());
+}
+
+void AggExprEmitter::VisitCXXParenListOrInitListExpr(
+ Expr *ExprToVisit, ArrayRef<Expr *> InitExprs,
+ FieldDecl *InitializedFieldInUnion, Expr *ArrayFiller) {
#if 0
// FIXME: Assess perf here? Figure out what cases are worth optimizing here
// (Length of globals? Chunks of zeroed-out space?).
//
// If we can, prefer a copy from a global; this is a lot less code for long
// globals, and it's easier for the current optimizers to analyze.
- if (llvm::Constant* C = CGF.CGM.EmitConstantExpr(E, E->getType(), &CGF)) {
+ if (llvm::Constant *C =
+ CGF.CGM.EmitConstantExpr(ExprToVisit, ExprToVisit->getType(), &CGF)) {
llvm::GlobalVariable* GV =
new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true,
llvm::GlobalValue::InternalLinkage, C, "");
- EmitFinalDestCopy(E->getType(), CGF.MakeAddrLValue(GV, E->getType()));
+ EmitFinalDestCopy(ExprToVisit->getType(),
+ CGF.MakeAddrLValue(GV, ExprToVisit->getType()));
return;
}
#endif
- if (E->hadArrayRangeDesignator())
- CGF.ErrorUnsupported(E, "GNU array range designator extension");
-
- if (E->isTransparent())
- return Visit(E->getInit(0));
- AggValueSlot Dest = EnsureSlot(E->getType());
+ AggValueSlot Dest = EnsureSlot(ExprToVisit->getType());
- LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), E->getType());
+ LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), ExprToVisit->getType());
// Handle initialization of an array.
- if (E->getType()->isArrayType()) {
+ if (ExprToVisit->getType()->isArrayType()) {
auto AType = cast<llvm::ArrayType>(Dest.getAddress().getElementType());
- EmitArrayInit(Dest.getAddress(), AType, E->getType(), E);
+ EmitArrayInit(Dest.getAddress(), AType, ExprToVisit->getType(), ExprToVisit,
+ InitExprs, ArrayFiller);
return;
}
- assert(E->getType()->isRecordType() && "Only support structs/unions here!");
+ assert(ExprToVisit->getType()->isRecordType() &&
+ "Only support structs/unions here!");
// Do struct initialization; this code just sets each individual member
// to the approprate value. This makes bitfield support automatic;
// the disadvantage is that the generated code is more difficult for
// the optimizer, especially with bitfields.
- unsigned NumInitElements = E->getNumInits();
- RecordDecl *record = E->getType()->castAs<RecordType>()->getDecl();
+ unsigned NumInitElements = InitExprs.size();
+ RecordDecl *record = ExprToVisit->getType()->castAs<RecordType>()->getDecl();
// We'll need to enter cleanup scopes in case any of the element
// initializers throws an exception.
@@ -1648,7 +1684,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Emit initialization of base classes.
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(record)) {
- assert(E->getNumInits() >= CXXRD->getNumBases() &&
+ assert(NumInitElements >= CXXRD->getNumBases() &&
"missing initializer for base class");
for (auto &Base : CXXRD->bases()) {
assert(!Base.isVirtual() && "should not see vbases here");
@@ -1662,7 +1698,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
CGF.getOverlapForBaseInit(CXXRD, BaseRD, Base.isVirtual()));
- CGF.EmitAggExpr(E->getInit(curInitIndex++), AggSlot);
+ CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot);
if (QualType::DestructionKind dtorKind =
Base.getType().isDestructedType()) {
@@ -1678,25 +1714,25 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (record->isUnion()) {
// Only initialize one field of a union. The field itself is
// specified by the initializer list.
- if (!E->getInitializedFieldInUnion()) {
+ if (!InitializedFieldInUnion) {
// Empty union; we have nothing to do.
#ifndef NDEBUG
// Make sure that it's really an empty and not a failure of
// semantic analysis.
for (const auto *Field : record->fields())
- assert(Field->isUnnamedBitfield() && "Only unnamed bitfields allowed");
+ assert((Field->isUnnamedBitfield() || Field->isAnonymousStructOrUnion()) && "Only unnamed bitfields or ananymous class allowed");
#endif
return;
}
// FIXME: volatility
- FieldDecl *Field = E->getInitializedFieldInUnion();
+ FieldDecl *Field = InitializedFieldInUnion;
LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestLV, Field);
if (NumInitElements) {
// Store the initializer into the field
- EmitInitializationToLValue(E->getInit(0), FieldLoc);
+ EmitInitializationToLValue(InitExprs[0], FieldLoc);
} else {
// Default-initialize to null.
EmitNullInitializationToLValue(FieldLoc);
@@ -1720,7 +1756,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// have a zeroed object, and the rest of the fields are
// zero-initializable.
if (curInitIndex == NumInitElements && Dest.isZeroed() &&
- CGF.getTypes().isZeroInitializable(E->getType()))
+ CGF.getTypes().isZeroInitializable(ExprToVisit->getType()))
break;
@@ -1730,7 +1766,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (curInitIndex < NumInitElements) {
// Store the initializer into the field.
- EmitInitializationToLValue(E->getInit(curInitIndex++), LV);
+ EmitInitializationToLValue(InitExprs[curInitIndex++], LV);
} else {
// We're out of initializers; default-initialize to null
EmitNullInitializationToLValue(LV);
@@ -1926,7 +1962,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
// Reference values are always non-null and have the width of a pointer.
if (Field->getType()->isReferenceType())
NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits(
- CGF.getTarget().getPointerWidth(0));
+ CGF.getTarget().getPointerWidth(LangAS::Default));
else
NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF);
}
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 3cc144361542..b889a4e05ee1 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -646,7 +646,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
case CXXConstructExpr::CK_VirtualBase:
ForVirtualBase = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CXXConstructExpr::CK_NonVirtualBase:
Type = Ctor_Base;
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 5409e82d437e..7a14a418c7b6 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -206,12 +206,13 @@ public:
return VisitPrePostIncDec(E, true, true);
}
ComplexPairTy VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
- ComplexPairTy VisitUnaryPlus (const UnaryOperator *E) {
- TestAndClearIgnoreReal();
- TestAndClearIgnoreImag();
- return Visit(E->getSubExpr());
- }
- ComplexPairTy VisitUnaryMinus (const UnaryOperator *E);
+
+ ComplexPairTy VisitUnaryPlus(const UnaryOperator *E,
+ QualType PromotionType = QualType());
+ ComplexPairTy VisitPlus(const UnaryOperator *E, QualType PromotionType);
+ ComplexPairTy VisitUnaryMinus(const UnaryOperator *E,
+ QualType PromotionType = QualType());
+ ComplexPairTy VisitMinus(const UnaryOperator *E, QualType PromotionType);
ComplexPairTy VisitUnaryNot (const UnaryOperator *E);
// LNot,Real,Imag never return complex.
ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) {
@@ -251,9 +252,13 @@ public:
ComplexPairTy LHS;
ComplexPairTy RHS;
QualType Ty; // Computation Type.
+ FPOptions FPFeatures;
};
- BinOpInfo EmitBinOps(const BinaryOperator *E);
+ BinOpInfo EmitBinOps(const BinaryOperator *E,
+ QualType PromotionTy = QualType());
+ ComplexPairTy EmitPromoted(const Expr *E, QualType PromotionTy);
+ ComplexPairTy EmitPromotedComplexOperand(const Expr *E, QualType PromotionTy);
LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
ComplexPairTy (ComplexExprEmitter::*Func)
(const BinOpInfo &),
@@ -270,19 +275,33 @@ public:
ComplexPairTy EmitComplexBinOpLibCall(StringRef LibCallName,
const BinOpInfo &Op);
- ComplexPairTy VisitBinAdd(const BinaryOperator *E) {
- return EmitBinAdd(EmitBinOps(E));
- }
- ComplexPairTy VisitBinSub(const BinaryOperator *E) {
- return EmitBinSub(EmitBinOps(E));
- }
- ComplexPairTy VisitBinMul(const BinaryOperator *E) {
- return EmitBinMul(EmitBinOps(E));
+ QualType getPromotionType(QualType Ty) {
+ if (auto *CT = Ty->getAs<ComplexType>()) {
+ QualType ElementType = CT->getElementType();
+ if (ElementType.UseExcessPrecision(CGF.getContext()))
+ return CGF.getContext().getComplexType(CGF.getContext().FloatTy);
+ }
+ if (Ty.UseExcessPrecision(CGF.getContext()))
+ return CGF.getContext().FloatTy;
+ return QualType();
}
- ComplexPairTy VisitBinDiv(const BinaryOperator *E) {
- return EmitBinDiv(EmitBinOps(E));
+
+#define HANDLEBINOP(OP) \
+ ComplexPairTy VisitBin##OP(const BinaryOperator *E) { \
+ QualType promotionTy = getPromotionType(E->getType()); \
+ ComplexPairTy result = EmitBin##OP(EmitBinOps(E, promotionTy)); \
+ if (!promotionTy.isNull()) \
+ result = \
+ CGF.EmitUnPromotedValue(result, E->getType()); \
+ return result; \
}
+ HANDLEBINOP(Mul)
+ HANDLEBINOP(Div)
+ HANDLEBINOP(Add)
+ HANDLEBINOP(Sub)
+#undef HANDLEBINOP
+
ComplexPairTy VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) {
return Visit(E->getSemanticForm());
}
@@ -556,10 +575,45 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
llvm_unreachable("unknown cast resulting in complex value");
}
-ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
+ComplexPairTy ComplexExprEmitter::VisitUnaryPlus(const UnaryOperator *E,
+ QualType PromotionType) {
+ QualType promotionTy = PromotionType.isNull()
+ ? getPromotionType(E->getSubExpr()->getType())
+ : PromotionType;
+ ComplexPairTy result = VisitPlus(E, promotionTy);
+ if (!promotionTy.isNull())
+ return CGF.EmitUnPromotedValue(result, E->getSubExpr()->getType());
+ return result;
+}
+
+ComplexPairTy ComplexExprEmitter::VisitPlus(const UnaryOperator *E,
+ QualType PromotionType) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
- ComplexPairTy Op = Visit(E->getSubExpr());
+ if (!PromotionType.isNull())
+ return CGF.EmitPromotedComplexExpr(E->getSubExpr(), PromotionType);
+ return Visit(E->getSubExpr());
+}
+
+ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E,
+ QualType PromotionType) {
+ QualType promotionTy = PromotionType.isNull()
+ ? getPromotionType(E->getSubExpr()->getType())
+ : PromotionType;
+ ComplexPairTy result = VisitMinus(E, promotionTy);
+ if (!promotionTy.isNull())
+ return CGF.EmitUnPromotedValue(result, E->getSubExpr()->getType());
+ return result;
+}
+ComplexPairTy ComplexExprEmitter::VisitMinus(const UnaryOperator *E,
+ QualType PromotionType) {
+ TestAndClearIgnoreReal();
+ TestAndClearIgnoreImag();
+ ComplexPairTy Op;
+ if (!PromotionType.isNull())
+ Op = CGF.EmitPromotedComplexExpr(E->getSubExpr(), PromotionType);
+ else
+ Op = Visit(E->getSubExpr());
llvm::Value *ResR, *ResI;
if (Op.first->getType()->isFloatingPointTy()) {
@@ -590,6 +644,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
llvm::Value *ResR, *ResI;
if (Op.LHS.first->getType()->isFloatingPointTy()) {
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
ResR = Builder.CreateFAdd(Op.LHS.first, Op.RHS.first, "add.r");
if (Op.LHS.second && Op.RHS.second)
ResI = Builder.CreateFAdd(Op.LHS.second, Op.RHS.second, "add.i");
@@ -608,6 +663,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinAdd(const BinOpInfo &Op) {
ComplexPairTy ComplexExprEmitter::EmitBinSub(const BinOpInfo &Op) {
llvm::Value *ResR, *ResI;
if (Op.LHS.first->getType()->isFloatingPointTy()) {
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
ResR = Builder.CreateFSub(Op.LHS.first, Op.RHS.first, "sub.r");
if (Op.LHS.second && Op.RHS.second)
ResI = Builder.CreateFSub(Op.LHS.second, Op.RHS.second, "sub.i");
@@ -700,6 +756,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinMul(const BinOpInfo &Op) {
// FIXME: C11 also provides for imaginary types which would allow folding
// still more of this within the type system.
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
if (Op.LHS.second && Op.RHS.second) {
// If both operands are complex, emit the core math directly, and then
// test for NaNs. If we find NaNs in the result, we delegate to a libcall
@@ -801,6 +858,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
//
// FIXME: We would be able to avoid the libcall in many places if we
// supported imaginary types in addition to complex types.
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, Op.FPFeatures);
if (RHSi && !CGF.getLangOpts().FastMath) {
BinOpInfo LibCallOp = Op;
// If LHS was a real, supply a null imaginary part.
@@ -876,21 +934,103 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
return ComplexPairTy(DSTr, DSTi);
}
+ComplexPairTy CodeGenFunction::EmitUnPromotedValue(ComplexPairTy result,
+ QualType UnPromotionType) {
+ llvm::Type *ComplexElementTy =
+ ConvertType(UnPromotionType->castAs<ComplexType>()->getElementType());
+ if (result.first)
+ result.first =
+ Builder.CreateFPTrunc(result.first, ComplexElementTy, "unpromotion");
+ if (result.second)
+ result.second =
+ Builder.CreateFPTrunc(result.second, ComplexElementTy, "unpromotion");
+ return result;
+}
+
+ComplexPairTy CodeGenFunction::EmitPromotedValue(ComplexPairTy result,
+ QualType PromotionType) {
+ llvm::Type *ComplexElementTy =
+ ConvertType(PromotionType->castAs<ComplexType>()->getElementType());
+ if (result.first)
+ result.first = Builder.CreateFPExt(result.first, ComplexElementTy, "ext");
+ if (result.second)
+ result.second = Builder.CreateFPExt(result.second, ComplexElementTy, "ext");
+
+ return result;
+}
+
+ComplexPairTy ComplexExprEmitter::EmitPromoted(const Expr *E,
+ QualType PromotionType) {
+ E = E->IgnoreParens();
+ if (auto BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+#define HANDLE_BINOP(OP) \
+ case BO_##OP: \
+ return EmitBin##OP(EmitBinOps(BO, PromotionType));
+ HANDLE_BINOP(Add)
+ HANDLE_BINOP(Sub)
+ HANDLE_BINOP(Mul)
+ HANDLE_BINOP(Div)
+#undef HANDLE_BINOP
+ default:
+ break;
+ }
+ } else if (auto UO = dyn_cast<UnaryOperator>(E)) {
+ switch (UO->getOpcode()) {
+ case UO_Minus:
+ return VisitMinus(UO, PromotionType);
+ case UO_Plus:
+ return VisitPlus(UO, PromotionType);
+ default:
+ break;
+ }
+ }
+ auto result = Visit(const_cast<Expr *>(E));
+ if (!PromotionType.isNull())
+ return CGF.EmitPromotedValue(result, PromotionType);
+ else
+ return result;
+}
+
+ComplexPairTy CodeGenFunction::EmitPromotedComplexExpr(const Expr *E,
+ QualType DstTy) {
+ return ComplexExprEmitter(*this).EmitPromoted(E, DstTy);
+}
+
+ComplexPairTy
+ComplexExprEmitter::EmitPromotedComplexOperand(const Expr *E,
+ QualType OverallPromotionType) {
+ if (E->getType()->isAnyComplexType()) {
+ if (!OverallPromotionType.isNull())
+ return CGF.EmitPromotedComplexExpr(E, OverallPromotionType);
+ else
+ return Visit(const_cast<Expr *>(E));
+ } else {
+ if (!OverallPromotionType.isNull()) {
+ QualType ComplexElementTy =
+ OverallPromotionType->castAs<ComplexType>()->getElementType();
+ return ComplexPairTy(CGF.EmitPromotedScalarExpr(E, ComplexElementTy),
+ nullptr);
+ } else {
+ return ComplexPairTy(CGF.EmitScalarExpr(E), nullptr);
+ }
+ }
+}
+
ComplexExprEmitter::BinOpInfo
-ComplexExprEmitter::EmitBinOps(const BinaryOperator *E) {
+ComplexExprEmitter::EmitBinOps(const BinaryOperator *E,
+ QualType PromotionType) {
TestAndClearIgnoreReal();
TestAndClearIgnoreImag();
BinOpInfo Ops;
- if (E->getLHS()->getType()->isRealFloatingType())
- Ops.LHS = ComplexPairTy(CGF.EmitScalarExpr(E->getLHS()), nullptr);
- else
- Ops.LHS = Visit(E->getLHS());
- if (E->getRHS()->getType()->isRealFloatingType())
- Ops.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
- else
- Ops.RHS = Visit(E->getRHS());
- Ops.Ty = E->getType();
+ Ops.LHS = EmitPromotedComplexOperand(E->getLHS(), PromotionType);
+ Ops.RHS = EmitPromotedComplexOperand(E->getRHS(), PromotionType);
+ if (!PromotionType.isNull())
+ Ops.Ty = PromotionType;
+ else
+ Ops.Ty = E->getType();
+ Ops.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts());
return Ops;
}
@@ -905,41 +1045,74 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
if (const AtomicType *AT = LHSTy->getAs<AtomicType>())
LHSTy = AT->getValueType();
- CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, E);
BinOpInfo OpInfo;
+ OpInfo.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts());
+ CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, OpInfo.FPFeatures);
// Load the RHS and LHS operands.
// __block variables need to have the rhs evaluated first, plus this should
// improve codegen a little.
- OpInfo.Ty = E->getComputationResultType();
- QualType ComplexElementTy = cast<ComplexType>(OpInfo.Ty)->getElementType();
+ QualType PromotionTypeCR;
+ PromotionTypeCR = getPromotionType(E->getComputationResultType());
+ if (PromotionTypeCR.isNull())
+ PromotionTypeCR = E->getComputationResultType();
+ OpInfo.Ty = PromotionTypeCR;
+ QualType ComplexElementTy =
+ OpInfo.Ty->castAs<ComplexType>()->getElementType();
+ QualType PromotionTypeRHS = getPromotionType(E->getRHS()->getType());
// The RHS should have been converted to the computation type.
if (E->getRHS()->getType()->isRealFloatingType()) {
- assert(
- CGF.getContext()
- .hasSameUnqualifiedType(ComplexElementTy, E->getRHS()->getType()));
- OpInfo.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
+ if (!PromotionTypeRHS.isNull())
+ OpInfo.RHS = ComplexPairTy(
+ CGF.EmitPromotedScalarExpr(E->getRHS(), PromotionTypeRHS), nullptr);
+ else {
+ assert(CGF.getContext().hasSameUnqualifiedType(ComplexElementTy,
+ E->getRHS()->getType()));
+
+ OpInfo.RHS = ComplexPairTy(CGF.EmitScalarExpr(E->getRHS()), nullptr);
+ }
} else {
- assert(CGF.getContext()
- .hasSameUnqualifiedType(OpInfo.Ty, E->getRHS()->getType()));
- OpInfo.RHS = Visit(E->getRHS());
+ if (!PromotionTypeRHS.isNull()) {
+ OpInfo.RHS = ComplexPairTy(
+ CGF.EmitPromotedComplexExpr(E->getRHS(), PromotionTypeRHS));
+ } else {
+ assert(CGF.getContext().hasSameUnqualifiedType(OpInfo.Ty,
+ E->getRHS()->getType()));
+ OpInfo.RHS = Visit(E->getRHS());
+ }
}
LValue LHS = CGF.EmitLValue(E->getLHS());
// Load from the l-value and convert it.
SourceLocation Loc = E->getExprLoc();
+ QualType PromotionTypeLHS = getPromotionType(E->getComputationLHSType());
if (LHSTy->isAnyComplexType()) {
ComplexPairTy LHSVal = EmitLoadOfLValue(LHS, Loc);
- OpInfo.LHS = EmitComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty, Loc);
+ if (!PromotionTypeLHS.isNull())
+ OpInfo.LHS =
+ EmitComplexToComplexCast(LHSVal, LHSTy, PromotionTypeLHS, Loc);
+ else
+ OpInfo.LHS = EmitComplexToComplexCast(LHSVal, LHSTy, OpInfo.Ty, Loc);
} else {
llvm::Value *LHSVal = CGF.EmitLoadOfScalar(LHS, Loc);
// For floating point real operands we can directly pass the scalar form
// to the binary operator emission and potentially get more efficient code.
if (LHSTy->isRealFloatingType()) {
- if (!CGF.getContext().hasSameUnqualifiedType(ComplexElementTy, LHSTy))
- LHSVal = CGF.EmitScalarConversion(LHSVal, LHSTy, ComplexElementTy, Loc);
+ QualType PromotedComplexElementTy;
+ if (!PromotionTypeLHS.isNull()) {
+ PromotedComplexElementTy =
+ cast<ComplexType>(PromotionTypeLHS)->getElementType();
+ if (!CGF.getContext().hasSameUnqualifiedType(PromotedComplexElementTy,
+ PromotionTypeLHS))
+ LHSVal = CGF.EmitScalarConversion(LHSVal, LHSTy,
+ PromotedComplexElementTy, Loc);
+ } else {
+ if (!CGF.getContext().hasSameUnqualifiedType(ComplexElementTy, LHSTy))
+ LHSVal =
+ CGF.EmitScalarConversion(LHSVal, LHSTy, ComplexElementTy, Loc);
+ }
OpInfo.LHS = ComplexPairTy(LHSVal, nullptr);
} else {
OpInfo.LHS = EmitScalarToComplexCast(LHSVal, LHSTy, OpInfo.Ty, Loc);
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index b83a87443250..c38feaaca35a 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -29,6 +29,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -46,7 +47,7 @@ struct ConstantAggregateBuilderUtils {
CharUnits getAlignment(const llvm::Constant *C) const {
return CharUnits::fromQuantity(
- CGM.getDataLayout().getABITypeAlignment(C->getType()));
+ CGM.getDataLayout().getABITypeAlign(C->getType()));
}
CharUnits getSize(llvm::Type *Ty) const {
@@ -94,7 +95,7 @@ class ConstantAggregateBuilder : private ConstantAggregateBuilderUtils {
bool NaturalLayout = true;
bool split(size_t Index, CharUnits Hint);
- Optional<size_t> splitAt(CharUnits Pos);
+ std::optional<size_t> splitAt(CharUnits Pos);
static llvm::Constant *buildFrom(CodeGenModule &CGM,
ArrayRef<llvm::Constant *> Elems,
@@ -158,12 +159,12 @@ bool ConstantAggregateBuilder::add(llvm::Constant *C, CharUnits Offset,
}
// Uncommon case: constant overlaps what we've already created.
- llvm::Optional<size_t> FirstElemToReplace = splitAt(Offset);
+ std::optional<size_t> FirstElemToReplace = splitAt(Offset);
if (!FirstElemToReplace)
return false;
CharUnits CSize = getSize(C);
- llvm::Optional<size_t> LastElemToReplace = splitAt(Offset + CSize);
+ std::optional<size_t> LastElemToReplace = splitAt(Offset + CSize);
if (!LastElemToReplace)
return false;
@@ -222,10 +223,10 @@ bool ConstantAggregateBuilder::addBits(llvm::APInt Bits, uint64_t OffsetInBits,
// Partial byte: update the existing integer if there is one. If we
// can't split out a 1-CharUnit range to update, then we can't add
// these bits and fail the entire constant emission.
- llvm::Optional<size_t> FirstElemToUpdate = splitAt(OffsetInChars);
+ std::optional<size_t> FirstElemToUpdate = splitAt(OffsetInChars);
if (!FirstElemToUpdate)
return false;
- llvm::Optional<size_t> LastElemToUpdate =
+ std::optional<size_t> LastElemToUpdate =
splitAt(OffsetInChars + CharUnits::One());
if (!LastElemToUpdate)
return false;
@@ -283,8 +284,8 @@ bool ConstantAggregateBuilder::addBits(llvm::APInt Bits, uint64_t OffsetInBits,
/// Returns a position within Elems and Offsets such that all elements
/// before the returned index end before Pos and all elements at or after
/// the returned index begin at or after Pos. Splits elements as necessary
-/// to ensure this. Returns None if we find something we can't split.
-Optional<size_t> ConstantAggregateBuilder::splitAt(CharUnits Pos) {
+/// to ensure this. Returns std::nullopt if we find something we can't split.
+std::optional<size_t> ConstantAggregateBuilder::splitAt(CharUnits Pos) {
if (Pos >= Size)
return Offsets.size();
@@ -305,7 +306,7 @@ Optional<size_t> ConstantAggregateBuilder::splitAt(CharUnits Pos) {
// Try to decompose it into smaller constants.
if (!split(LastAtOrBeforePosIndex, Pos))
- return None;
+ return std::nullopt;
}
}
@@ -517,12 +518,12 @@ void ConstantAggregateBuilder::condense(CharUnits Offset,
llvm::Type *DesiredTy) {
CharUnits Size = getSize(DesiredTy);
- llvm::Optional<size_t> FirstElemToReplace = splitAt(Offset);
+ std::optional<size_t> FirstElemToReplace = splitAt(Offset);
if (!FirstElemToReplace)
return;
size_t First = *FirstElemToReplace;
- llvm::Optional<size_t> LastElemToReplace = splitAt(Offset + Size);
+ std::optional<size_t> LastElemToReplace = splitAt(Offset + Size);
if (!LastElemToReplace)
return;
size_t Last = *LastElemToReplace;
@@ -543,8 +544,8 @@ void ConstantAggregateBuilder::condense(CharUnits Offset,
}
llvm::Constant *Replacement = buildFrom(
- CGM, makeArrayRef(Elems).slice(First, Length),
- makeArrayRef(Offsets).slice(First, Length), Offset, getSize(DesiredTy),
+ CGM, ArrayRef(Elems).slice(First, Length),
+ ArrayRef(Offsets).slice(First, Length), Offset, getSize(DesiredTy),
/*known to have natural layout=*/false, DesiredTy, false);
replace(Elems, First, Last, {Replacement});
replace(Offsets, First, Last, {Offset});
@@ -913,17 +914,16 @@ bool ConstStructBuilder::UpdateStruct(ConstantEmitter &Emitter,
// ConstExprEmitter
//===----------------------------------------------------------------------===//
-static ConstantAddress tryEmitGlobalCompoundLiteral(CodeGenModule &CGM,
- CodeGenFunction *CGF,
- const CompoundLiteralExpr *E) {
+static ConstantAddress
+tryEmitGlobalCompoundLiteral(ConstantEmitter &emitter,
+ const CompoundLiteralExpr *E) {
+ CodeGenModule &CGM = emitter.CGM;
CharUnits Align = CGM.getContext().getTypeAlignInChars(E->getType());
if (llvm::GlobalVariable *Addr =
CGM.getAddrOfConstantCompoundLiteralIfEmitted(E))
return ConstantAddress(Addr, Addr->getValueType(), Align);
LangAS addressSpace = E->getType().getAddressSpace();
-
- ConstantEmitter emitter(CGM, CGF);
llvm::Constant *C = emitter.tryEmitForInitializer(E->getInitializer(),
addressSpace, E->getType());
if (!C) {
@@ -972,7 +972,7 @@ EmitArrayConstant(CodeGenModule &CGM, llvm::ArrayType *DesiredType,
if (CommonElementType && NonzeroLength >= 8) {
llvm::Constant *Initial = llvm::ConstantArray::get(
llvm::ArrayType::get(CommonElementType, NonzeroLength),
- makeArrayRef(Elements).take_front(NonzeroLength));
+ ArrayRef(Elements).take_front(NonzeroLength));
Elements.resize(2);
Elements[0] = Initial;
} else {
@@ -1395,15 +1395,12 @@ ConstantEmitter::tryEmitAbstract(const APValue &value, QualType destType) {
llvm::Constant *ConstantEmitter::tryEmitConstantExpr(const ConstantExpr *CE) {
if (!CE->hasAPValueResult())
return nullptr;
- const Expr *Inner = CE->getSubExpr()->IgnoreImplicit();
- QualType RetType;
- if (auto *Call = dyn_cast<CallExpr>(Inner))
- RetType = Call->getCallReturnType(CGM.getContext());
- else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Inner))
- RetType = Ctor->getType();
- llvm::Constant *Res =
- emitAbstract(CE->getBeginLoc(), CE->getAPValueResult(), RetType);
- return Res;
+
+ QualType RetType = CE->getType();
+ if (CE->isGLValue())
+ RetType = CGM.getContext().getLValueReferenceType(RetType);
+
+ return emitAbstract(CE->getBeginLoc(), CE->getAPValueResult(), RetType);
}
llvm::Constant *
@@ -1970,7 +1967,9 @@ ConstantLValueEmitter::VisitConstantExpr(const ConstantExpr *E) {
ConstantLValue
ConstantLValueEmitter::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
- return tryEmitGlobalCompoundLiteral(CGM, Emitter.CGF, E);
+ ConstantEmitter CompoundLiteralEmitter(CGM, Emitter.CGF);
+ CompoundLiteralEmitter.setInConstantContext(Emitter.isInConstantContext());
+ return tryEmitGlobalCompoundLiteral(CompoundLiteralEmitter, E);
}
ConstantLValue
@@ -2214,7 +2213,8 @@ void CodeGenModule::setAddrOfConstantCompoundLiteral(
ConstantAddress
CodeGenModule::GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *E) {
assert(E->isFileScope() && "not a file-scope compound literal expr");
- return tryEmitGlobalCompoundLiteral(*this, nullptr, E);
+ ConstantEmitter emitter(*this);
+ return tryEmitGlobalCompoundLiteral(emitter, E);
}
llvm::Constant *
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index b150aaa376eb..a0dcb978b1ac 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -28,7 +28,6 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFixedPoint.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
@@ -43,6 +42,7 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/TypeSize.h"
#include <cstdarg>
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -152,16 +152,16 @@ static bool MustVisitNullValue(const Expr *E) {
}
/// If \p E is a widened promoted integer, get its base (unpromoted) type.
-static llvm::Optional<QualType> getUnwidenedIntegerType(const ASTContext &Ctx,
- const Expr *E) {
+static std::optional<QualType> getUnwidenedIntegerType(const ASTContext &Ctx,
+ const Expr *E) {
const Expr *Base = E->IgnoreImpCasts();
if (E == Base)
- return llvm::None;
+ return std::nullopt;
QualType BaseTy = Base->getType();
- if (!BaseTy->isPromotableIntegerType() ||
+ if (!Ctx.isPromotableIntegerType(BaseTy) ||
Ctx.getTypeSize(BaseTy) >= Ctx.getTypeSize(E->getType()))
- return llvm::None;
+ return std::nullopt;
return BaseTy;
}
@@ -255,7 +255,7 @@ public:
if (VD->getType()->isReferenceType()) {
if (const auto *TTy =
- dyn_cast<TypedefType>(VD->getType().getNonReferenceType()))
+ VD->getType().getNonReferenceType()->getAs<TypedefType>())
AVAttr = TTy->getDecl()->getAttr<AlignValueAttr>();
} else {
// Assumptions for function parameters are emitted at the start of the
@@ -271,8 +271,7 @@ public:
}
if (!AVAttr)
- if (const auto *TTy =
- dyn_cast<TypedefType>(E->getType()))
+ if (const auto *TTy = E->getType()->getAs<TypedefType>())
AVAttr = TTy->getDecl()->getAttr<AlignValueAttr>();
if (!AVAttr)
@@ -468,6 +467,9 @@ public:
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
}
Value *VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) {
+ if (E->getType()->isVoidType())
+ return nullptr;
+
return EmitNullValue(E->getType());
}
Value *VisitGNUNullExpr(const GNUNullExpr *E) {
@@ -620,16 +622,22 @@ public:
return Visit(E->getSubExpr()); // the actual value should be unused
return EmitLoadOfLValue(E);
}
- Value *VisitUnaryPlus(const UnaryOperator *E) {
- // This differs from gcc, though, most likely due to a bug in gcc.
- TestAndClearIgnoreResultAssign();
- return Visit(E->getSubExpr());
- }
- Value *VisitUnaryMinus (const UnaryOperator *E);
+
+ Value *VisitUnaryPlus(const UnaryOperator *E,
+ QualType PromotionType = QualType());
+ Value *VisitPlus(const UnaryOperator *E, QualType PromotionType);
+ Value *VisitUnaryMinus(const UnaryOperator *E,
+ QualType PromotionType = QualType());
+ Value *VisitMinus(const UnaryOperator *E, QualType PromotionType);
+
Value *VisitUnaryNot (const UnaryOperator *E);
Value *VisitUnaryLNot (const UnaryOperator *E);
- Value *VisitUnaryReal (const UnaryOperator *E);
- Value *VisitUnaryImag (const UnaryOperator *E);
+ Value *VisitUnaryReal(const UnaryOperator *E,
+ QualType PromotionType = QualType());
+ Value *VisitReal(const UnaryOperator *E, QualType PromotionType);
+ Value *VisitUnaryImag(const UnaryOperator *E,
+ QualType PromotionType = QualType());
+ Value *VisitImag(const UnaryOperator *E, QualType PromotionType);
Value *VisitUnaryExtension(const UnaryOperator *E) {
return Visit(E->getSubExpr());
}
@@ -719,7 +727,7 @@ public:
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LangOptions::SOB_Trapping:
if (CanElideOverflowCheck(CGF.getContext(), Ops))
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
@@ -791,7 +799,13 @@ public:
// Helper functions for fixed point binary operations.
Value *EmitFixedPointBinOp(const BinOpInfo &Ops);
- BinOpInfo EmitBinOps(const BinaryOperator *E);
+ BinOpInfo EmitBinOps(const BinaryOperator *E,
+ QualType PromotionTy = QualType());
+
+ Value *EmitPromotedValue(Value *result, QualType PromotionType);
+ Value *EmitUnPromotedValue(Value *result, QualType ExprType);
+ Value *EmitPromoted(const Expr *E, QualType PromotionType);
+
LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
Value *&Result);
@@ -799,13 +813,28 @@ public:
Value *EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
+ QualType getPromotionType(QualType Ty) {
+ if (auto *CT = Ty->getAs<ComplexType>()) {
+ QualType ElementType = CT->getElementType();
+ if (ElementType.UseExcessPrecision(CGF.getContext()))
+ return CGF.getContext().getComplexType(CGF.getContext().FloatTy);
+ }
+ if (Ty.UseExcessPrecision(CGF.getContext()))
+ return CGF.getContext().FloatTy;
+ return QualType();
+ }
+
// Binary operators and binary compound assignment operators.
-#define HANDLEBINOP(OP) \
- Value *VisitBin ## OP(const BinaryOperator *E) { \
- return Emit ## OP(EmitBinOps(E)); \
- } \
- Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) { \
- return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP); \
+#define HANDLEBINOP(OP) \
+ Value *VisitBin##OP(const BinaryOperator *E) { \
+ QualType promotionTy = getPromotionType(E->getType()); \
+ auto result = Emit##OP(EmitBinOps(E, promotionTy)); \
+ if (result && !promotionTy.isNull()) \
+ result = EmitUnPromotedValue(result, E->getType()); \
+ return result; \
+ } \
+ Value *VisitBin##OP##Assign(const CompoundAssignOperator *E) { \
+ return EmitCompoundAssign(E, &ScalarExprEmitter::Emit##OP); \
}
HANDLEBINOP(Mul)
HANDLEBINOP(Div)
@@ -1599,21 +1628,14 @@ Value *ScalarExprEmitter::VisitExpr(Expr *E) {
Value *
ScalarExprEmitter::VisitSYCLUniqueStableNameExpr(SYCLUniqueStableNameExpr *E) {
ASTContext &Context = CGF.getContext();
- llvm::Optional<LangAS> GlobalAS =
- Context.getTargetInfo().getConstantAddressSpace();
+ unsigned AddrSpace =
+ Context.getTargetAddressSpace(CGF.CGM.GetGlobalConstantAddressSpace());
llvm::Constant *GlobalConstStr = Builder.CreateGlobalStringPtr(
- E->ComputeName(Context), "__usn_str",
- static_cast<unsigned>(GlobalAS.value_or(LangAS::Default)));
+ E->ComputeName(Context), "__usn_str", AddrSpace);
- unsigned ExprAS = Context.getTargetAddressSpace(E->getType());
-
- if (GlobalConstStr->getType()->getPointerAddressSpace() == ExprAS)
- return GlobalConstStr;
-
- llvm::PointerType *PtrTy = cast<llvm::PointerType>(GlobalConstStr->getType());
- llvm::PointerType *NewPtrTy =
- llvm::PointerType::getWithSamePointeeType(PtrTy, ExprAS);
- return Builder.CreateAddrSpaceCast(GlobalConstStr, NewPtrTy, "usn_addr_cast");
+ llvm::Type *ExprTy = ConvertType(E->getType());
+ return Builder.CreatePointerBitCastOrAddrSpaceCast(GlobalConstStr, ExprTy,
+ "usn_addr_cast");
}
Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
@@ -1643,7 +1665,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
// newv = insert newv, x, i
auto *RTy = llvm::FixedVectorType::get(LTy->getElementType(),
MTy->getNumElements());
- Value* NewV = llvm::UndefValue::get(RTy);
+ Value* NewV = llvm::PoisonValue::get(RTy);
for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) {
Value *IIndx = llvm::ConstantInt::get(CGF.SizeTy, i);
Value *Indx = Builder.CreateExtractElement(Mask, IIndx, "shuf_idx");
@@ -1999,6 +2021,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
Expr *E = CE->getSubExpr();
QualType DestTy = CE->getType();
CastKind Kind = CE->getCastKind();
+ CodeGenFunction::CGFPOptionsRAII FPOptions(CGF, CE);
// These cases are generally not written to ignore the result of
// evaluating their sub-expressions, so we clear this now.
@@ -2479,7 +2502,7 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior(
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWAdd(InVal, Amount, Name);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LangOptions::SOB_Trapping:
if (!E->canOverflow())
return Builder.CreateNSWAdd(InVal, Amount, Name);
@@ -2584,7 +2607,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
} else if (type->isIntegerType()) {
QualType promotedType;
bool canPerformLossyDemotionCheck = false;
- if (type->isPromotableIntegerType()) {
+ if (CGF.getContext().isPromotableIntegerType(type)) {
promotedType = CGF.getContext().getPromotedIntegerType(type);
assert(promotedType != type && "Shouldn't promote to the same type.");
canPerformLossyDemotionCheck = true;
@@ -2818,10 +2841,45 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
}
+Value *ScalarExprEmitter::VisitUnaryPlus(const UnaryOperator *E,
+ QualType PromotionType) {
+ QualType promotionTy = PromotionType.isNull()
+ ? getPromotionType(E->getSubExpr()->getType())
+ : PromotionType;
+ Value *result = VisitPlus(E, promotionTy);
+ if (result && !promotionTy.isNull())
+ result = EmitUnPromotedValue(result, E->getType());
+ return result;
+}
-Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
+Value *ScalarExprEmitter::VisitPlus(const UnaryOperator *E,
+ QualType PromotionType) {
+ // This differs from gcc, though, most likely due to a bug in gcc.
TestAndClearIgnoreResultAssign();
- Value *Op = Visit(E->getSubExpr());
+ if (!PromotionType.isNull())
+ return CGF.EmitPromotedScalarExpr(E->getSubExpr(), PromotionType);
+ return Visit(E->getSubExpr());
+}
+
+Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E,
+ QualType PromotionType) {
+ QualType promotionTy = PromotionType.isNull()
+ ? getPromotionType(E->getSubExpr()->getType())
+ : PromotionType;
+ Value *result = VisitMinus(E, promotionTy);
+ if (result && !promotionTy.isNull())
+ result = EmitUnPromotedValue(result, E->getType());
+ return result;
+}
+
+Value *ScalarExprEmitter::VisitMinus(const UnaryOperator *E,
+ QualType PromotionType) {
+ TestAndClearIgnoreResultAssign();
+ Value *Op;
+ if (!PromotionType.isNull())
+ Op = CGF.EmitPromotedScalarExpr(E->getSubExpr(), PromotionType);
+ else
+ Op = Visit(E->getSubExpr());
// Generate a unary FNeg for FP ops.
if (Op->getType()->isFPOrFPVectorTy())
@@ -2841,7 +2899,7 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
TestAndClearIgnoreResultAssign();
Value *Op = Visit(E->getSubExpr());
- return Builder.CreateNot(Op, "neg");
+ return Builder.CreateNot(Op, "not");
}
Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
@@ -3006,33 +3064,75 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
return Builder.getInt(E->EvaluateKnownConstInt(CGF.getContext()));
}
-Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) {
+Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E,
+ QualType PromotionType) {
+ QualType promotionTy = PromotionType.isNull()
+ ? getPromotionType(E->getSubExpr()->getType())
+ : PromotionType;
+ Value *result = VisitReal(E, promotionTy);
+ if (result && !promotionTy.isNull())
+ result = EmitUnPromotedValue(result, E->getType());
+ return result;
+}
+
+Value *ScalarExprEmitter::VisitReal(const UnaryOperator *E,
+ QualType PromotionType) {
Expr *Op = E->getSubExpr();
if (Op->getType()->isAnyComplexType()) {
// If it's an l-value, load through the appropriate subobject l-value.
// Note that we have to ask E because Op might be an l-value that
// this won't work for, e.g. an Obj-C property.
- if (E->isGLValue())
- return CGF.EmitLoadOfLValue(CGF.EmitLValue(E),
- E->getExprLoc()).getScalarVal();
-
+ if (E->isGLValue()) {
+ if (!PromotionType.isNull()) {
+ CodeGenFunction::ComplexPairTy result = CGF.EmitComplexExpr(
+ Op, /*IgnoreReal*/ IgnoreResultAssign, /*IgnoreImag*/ true);
+ if (result.first)
+ result.first = CGF.EmitPromotedValue(result, PromotionType).first;
+ return result.first;
+ } else {
+ return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc())
+ .getScalarVal();
+ }
+ }
// Otherwise, calculate and project.
return CGF.EmitComplexExpr(Op, false, true).first;
}
+ if (!PromotionType.isNull())
+ return CGF.EmitPromotedScalarExpr(Op, PromotionType);
return Visit(Op);
}
-Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
+Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E,
+ QualType PromotionType) {
+ QualType promotionTy = PromotionType.isNull()
+ ? getPromotionType(E->getSubExpr()->getType())
+ : PromotionType;
+ Value *result = VisitImag(E, promotionTy);
+ if (result && !promotionTy.isNull())
+ result = EmitUnPromotedValue(result, E->getType());
+ return result;
+}
+
+Value *ScalarExprEmitter::VisitImag(const UnaryOperator *E,
+ QualType PromotionType) {
Expr *Op = E->getSubExpr();
if (Op->getType()->isAnyComplexType()) {
// If it's an l-value, load through the appropriate subobject l-value.
// Note that we have to ask E because Op might be an l-value that
// this won't work for, e.g. an Obj-C property.
- if (Op->isGLValue())
- return CGF.EmitLoadOfLValue(CGF.EmitLValue(E),
- E->getExprLoc()).getScalarVal();
-
+ if (Op->isGLValue()) {
+ if (!PromotionType.isNull()) {
+ CodeGenFunction::ComplexPairTy result = CGF.EmitComplexExpr(
+ Op, /*IgnoreReal*/ true, /*IgnoreImag*/ IgnoreResultAssign);
+ if (result.second)
+ result.second = CGF.EmitPromotedValue(result, PromotionType).second;
+ return result.second;
+ } else {
+ return CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getExprLoc())
+ .getScalarVal();
+ }
+ }
// Otherwise, calculate and project.
return CGF.EmitComplexExpr(Op, true, false).second;
}
@@ -3041,8 +3141,12 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
// effects are evaluated, but not the actual value.
if (Op->isGLValue())
CGF.EmitLValue(Op);
+ else if (!PromotionType.isNull())
+ CGF.EmitPromotedScalarExpr(Op, PromotionType);
else
CGF.EmitScalarExpr(Op, true);
+ if (!PromotionType.isNull())
+ return llvm::Constant::getNullValue(ConvertType(PromotionType));
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
@@ -3050,12 +3154,65 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) {
// Binary Operators
//===----------------------------------------------------------------------===//
-BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) {
+Value *ScalarExprEmitter::EmitPromotedValue(Value *result,
+ QualType PromotionType) {
+ return CGF.Builder.CreateFPExt(result, ConvertType(PromotionType), "ext");
+}
+
+Value *ScalarExprEmitter::EmitUnPromotedValue(Value *result,
+ QualType ExprType) {
+ return CGF.Builder.CreateFPTrunc(result, ConvertType(ExprType), "unpromotion");
+}
+
+Value *ScalarExprEmitter::EmitPromoted(const Expr *E, QualType PromotionType) {
+ E = E->IgnoreParens();
+ if (auto BO = dyn_cast<BinaryOperator>(E)) {
+ switch (BO->getOpcode()) {
+#define HANDLE_BINOP(OP) \
+ case BO_##OP: \
+ return Emit##OP(EmitBinOps(BO, PromotionType));
+ HANDLE_BINOP(Add)
+ HANDLE_BINOP(Sub)
+ HANDLE_BINOP(Mul)
+ HANDLE_BINOP(Div)
+#undef HANDLE_BINOP
+ default:
+ break;
+ }
+ } else if (auto UO = dyn_cast<UnaryOperator>(E)) {
+ switch (UO->getOpcode()) {
+ case UO_Imag:
+ return VisitImag(UO, PromotionType);
+ case UO_Real:
+ return VisitReal(UO, PromotionType);
+ case UO_Minus:
+ return VisitMinus(UO, PromotionType);
+ case UO_Plus:
+ return VisitPlus(UO, PromotionType);
+ default:
+ break;
+ }
+ }
+ auto result = Visit(const_cast<Expr *>(E));
+ if (result) {
+ if (!PromotionType.isNull())
+ return EmitPromotedValue(result, PromotionType);
+ else
+ return EmitUnPromotedValue(result, E->getType());
+ }
+ return result;
+}
+
+BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E,
+ QualType PromotionType) {
TestAndClearIgnoreResultAssign();
BinOpInfo Result;
- Result.LHS = Visit(E->getLHS());
- Result.RHS = Visit(E->getRHS());
- Result.Ty = E->getType();
+ Result.LHS = CGF.EmitPromotedScalarExpr(E->getLHS(), PromotionType);
+ Result.RHS = CGF.EmitPromotedScalarExpr(E->getRHS(), PromotionType);
+ if (!PromotionType.isNull())
+ Result.Ty = PromotionType;
+ else
+ Result.Ty = E->getType();
Result.Opcode = E->getOpcode();
Result.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts());
Result.E = E;
@@ -3074,8 +3231,18 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
// Emit the RHS first. __block variables need to have the rhs evaluated
// first, plus this should improve codegen a little.
- OpInfo.RHS = Visit(E->getRHS());
- OpInfo.Ty = E->getComputationResultType();
+
+ QualType PromotionTypeCR;
+ PromotionTypeCR = getPromotionType(E->getComputationResultType());
+ if (PromotionTypeCR.isNull())
+ PromotionTypeCR = E->getComputationResultType();
+ QualType PromotionTypeLHS = getPromotionType(E->getComputationLHSType());
+ QualType PromotionTypeRHS = getPromotionType(E->getRHS()->getType());
+ if (!PromotionTypeRHS.isNull())
+ OpInfo.RHS = CGF.EmitPromotedScalarExpr(E->getRHS(), PromotionTypeRHS);
+ else
+ OpInfo.RHS = Visit(E->getRHS());
+ OpInfo.Ty = PromotionTypeCR;
OpInfo.Opcode = E->getOpcode();
OpInfo.FPFeatures = E->getFPFeaturesInEffect(CGF.getLangOpts());
OpInfo.E = E;
@@ -3154,16 +3321,20 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(CGF, OpInfo.FPFeatures);
SourceLocation Loc = E->getExprLoc();
- OpInfo.LHS =
- EmitScalarConversion(OpInfo.LHS, LHSTy, E->getComputationLHSType(), Loc);
+ if (!PromotionTypeLHS.isNull())
+ OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, PromotionTypeLHS,
+ E->getExprLoc());
+ else
+ OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
+ E->getComputationLHSType(), Loc);
// Expand the binary operator.
Result = (this->*Func)(OpInfo);
// Convert the result back to the LHS type,
// potentially with Implicit Conversion sanitizer check.
- Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy,
- Loc, ScalarConversionOpts(CGF.SanOpts));
+ Result = EmitScalarConversion(Result, PromotionTypeCR, LHSTy, Loc,
+ ScalarConversionOpts(CGF.SanOpts));
if (atomicPHI) {
llvm::BasicBlock *curBlock = Builder.GetInsertBlock();
@@ -3651,7 +3822,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LangOptions::SOB_Trapping:
if (CanElideOverflowCheck(CGF.getContext(), op))
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
@@ -3801,7 +3972,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
case LangOptions::SOB_Undefined:
if (!CGF.SanOpts.has(SanitizerKind::SignedIntegerOverflow))
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LangOptions::SOB_Trapping:
if (CanElideOverflowCheck(CGF.getContext(), op))
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
@@ -4759,8 +4930,7 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) {
static Value *ConvertVec3AndVec4(CGBuilderTy &Builder, CodeGenFunction &CGF,
Value *Src, unsigned NumElementsDst) {
static constexpr int Mask[] = {0, 1, 2, -1};
- return Builder.CreateShuffleVector(Src,
- llvm::makeArrayRef(Mask, NumElementsDst));
+ return Builder.CreateShuffleVector(Src, llvm::ArrayRef(Mask, NumElementsDst));
}
// Create cast instructions for converting LLVM value \p Src to LLVM type \p
@@ -4897,6 +5067,16 @@ Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
}
+Value *
+CodeGenFunction::EmitPromotedScalarExpr(const Expr *E,
+ QualType PromotionType) {
+ if (!PromotionType.isNull())
+ return ScalarExprEmitter(*this).EmitPromoted(E, PromotionType);
+ else
+ return ScalarExprEmitter(*this).Visit(const_cast<Expr *>(E));
+}
+
+
llvm::Value *CodeGenFunction::
EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
diff --git a/clang/lib/CodeGen/CGGPUBuiltin.cpp b/clang/lib/CodeGen/CGGPUBuiltin.cpp
index fdd2fa18bb4a..c39e0cc75f2d 100644
--- a/clang/lib/CodeGen/CGGPUBuiltin.cpp
+++ b/clang/lib/CodeGen/CGGPUBuiltin.cpp
@@ -162,7 +162,7 @@ RValue EmitDevicePrintfCallExpr(const CallExpr *E, CodeGenFunction *CGF,
// amdgpu
llvm::Constant *Size =
llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGM.getLLVMContext()),
- static_cast<uint32_t>(r.second.getFixedSize()));
+ static_cast<uint32_t>(r.second.getFixedValue()));
Vec.push_back(Size);
}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 7dfcc65969a8..5882f491d597 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -13,16 +13,22 @@
//===----------------------------------------------------------------------===//
#include "CGHLSLRuntime.h"
+#include "CGDebugInfo.h"
#include "CodeGenModule.h"
+#include "clang/AST/Decl.h"
#include "clang/Basic/TargetOptions.h"
+#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/FormatVariadic.h"
using namespace clang;
using namespace CodeGen;
+using namespace clang::hlsl;
using namespace llvm;
namespace {
+
void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
// The validation of ValVersionStr is done at HLSLToolChain::TranslateArgs.
// Assume ValVersionStr is legal here.
@@ -39,14 +45,415 @@ void addDxilValVersion(StringRef ValVersionStr, llvm::Module &M) {
IRBuilder<> B(M.getContext());
MDNode *Val = MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(Major)),
ConstantAsMetadata::get(B.getInt32(Minor))});
- StringRef DxilValKey = "dx.valver";
- M.addModuleFlag(llvm::Module::ModFlagBehavior::AppendUnique, DxilValKey, Val);
+ StringRef DXILValKey = "dx.valver";
+ auto *DXILValMD = M.getOrInsertNamedMetadata(DXILValKey);
+ DXILValMD->addOperand(Val);
+}
+void addDisableOptimizations(llvm::Module &M) {
+ StringRef Key = "dx.disable_optimizations";
+ M.addModuleFlag(llvm::Module::ModFlagBehavior::Override, Key, 1);
+}
+// cbuffer will be translated into global variable in special address space.
+// If translate into C,
+// cbuffer A {
+// float a;
+// float b;
+// }
+// float foo() { return a + b; }
+//
+// will be translated into
+//
+// struct A {
+// float a;
+// float b;
+// } cbuffer_A __attribute__((address_space(4)));
+// float foo() { return cbuffer_A.a + cbuffer_A.b; }
+//
+// layoutBuffer will create the struct A type.
+// replaceBuffer will replace use of global variable a and b with cbuffer_A.a
+// and cbuffer_A.b.
+//
+void layoutBuffer(CGHLSLRuntime::Buffer &Buf, const DataLayout &DL) {
+ if (Buf.Constants.empty())
+ return;
+
+ std::vector<llvm::Type *> EltTys;
+ for (auto &Const : Buf.Constants) {
+ GlobalVariable *GV = Const.first;
+ Const.second = EltTys.size();
+ llvm::Type *Ty = GV->getValueType();
+ EltTys.emplace_back(Ty);
+ }
+ Buf.LayoutStruct = llvm::StructType::get(EltTys[0]->getContext(), EltTys);
+}
+
+GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) {
+ // Create global variable for CB.
+ GlobalVariable *CBGV = new GlobalVariable(
+ Buf.LayoutStruct, /*isConstant*/ true,
+ GlobalValue::LinkageTypes::ExternalLinkage, nullptr,
+ llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb." : ".tb."),
+ GlobalValue::NotThreadLocal);
+
+ IRBuilder<> B(CBGV->getContext());
+ Value *ZeroIdx = B.getInt32(0);
+ // Replace Const use with CB use.
+ for (auto &[GV, Offset] : Buf.Constants) {
+ Value *GEP =
+ B.CreateGEP(Buf.LayoutStruct, CBGV, {ZeroIdx, B.getInt32(Offset)});
+
+ assert(Buf.LayoutStruct->getElementType(Offset) == GV->getValueType() &&
+ "constant type mismatch");
+
+ // Replace.
+ GV->replaceAllUsesWith(GEP);
+ // Erase GV.
+ GV->removeDeadConstantUsers();
+ GV->eraseFromParent();
+ }
+ return CBGV;
}
+
} // namespace
+void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) {
+ if (D->getStorageClass() == SC_Static) {
+ // For static inside cbuffer, take as global static.
+ // Don't add to cbuffer.
+ CGM.EmitGlobal(D);
+ return;
+ }
+
+ auto *GV = cast<GlobalVariable>(CGM.GetAddrOfGlobalVar(D));
+ // Add debug info for constVal.
+ if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
+ if (CGM.getCodeGenOpts().getDebugInfo() >=
+ codegenoptions::DebugInfoKind::LimitedDebugInfo)
+ DI->EmitGlobalVariable(cast<GlobalVariable>(GV), D);
+
+ // FIXME: support packoffset.
+ // See https://github.com/llvm/llvm-project/issues/57914.
+ uint32_t Offset = 0;
+ bool HasUserOffset = false;
+
+ unsigned LowerBound = HasUserOffset ? Offset : UINT_MAX;
+ CB.Constants.emplace_back(std::make_pair(GV, LowerBound));
+}
+
+void CGHLSLRuntime::addBufferDecls(const DeclContext *DC, Buffer &CB) {
+ for (Decl *it : DC->decls()) {
+ if (auto *ConstDecl = dyn_cast<VarDecl>(it)) {
+ addConstant(ConstDecl, CB);
+ } else if (isa<CXXRecordDecl, EmptyDecl>(it)) {
+ // Nothing to do for this declaration.
+ } else if (isa<FunctionDecl>(it)) {
+ // A function within an cbuffer is effectively a top-level function,
+ // as it only refers to globally scoped declarations.
+ CGM.EmitTopLevelDecl(it);
+ }
+ }
+}
+
+void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *D) {
+ Buffers.emplace_back(Buffer(D));
+ addBufferDecls(D, Buffers.back());
+}
+
void CGHLSLRuntime::finishCodeGen() {
auto &TargetOpts = CGM.getTarget().getTargetOpts();
+ llvm::Module &M = CGM.getModule();
+ Triple T(M.getTargetTriple());
+ if (T.getArch() == Triple::ArchType::dxil)
+ addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
+
+ generateGlobalCtorDtorCalls();
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0)
+ addDisableOptimizations(M);
+
+ const DataLayout &DL = M.getDataLayout();
+
+ for (auto &Buf : Buffers) {
+ layoutBuffer(Buf, DL);
+ GlobalVariable *GV = replaceBuffer(Buf);
+ M.getGlobalList().push_back(GV);
+ llvm::hlsl::ResourceClass RC = Buf.IsCBuffer
+ ? llvm::hlsl::ResourceClass::CBuffer
+ : llvm::hlsl::ResourceClass::SRV;
+ llvm::hlsl::ResourceKind RK = Buf.IsCBuffer
+ ? llvm::hlsl::ResourceKind::CBuffer
+ : llvm::hlsl::ResourceKind::TBuffer;
+ std::string TyName =
+ Buf.Name.str() + (Buf.IsCBuffer ? ".cb." : ".tb.") + "ty";
+ addBufferResourceAnnotation(GV, TyName, RC, RK, Buf.Binding);
+ }
+}
+
+CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
+ : Name(D->getName()), IsCBuffer(D->isCBuffer()),
+ Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
+void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
+ llvm::StringRef TyName,
+ llvm::hlsl::ResourceClass RC,
+ llvm::hlsl::ResourceKind RK,
+ BufferResBinding &Binding) {
llvm::Module &M = CGM.getModule();
- addDxilValVersion(TargetOpts.DxilValidatorVersion, M);
+
+ NamedMDNode *ResourceMD = nullptr;
+ switch (RC) {
+ case llvm::hlsl::ResourceClass::UAV:
+ ResourceMD = M.getOrInsertNamedMetadata("hlsl.uavs");
+ break;
+ case llvm::hlsl::ResourceClass::SRV:
+ ResourceMD = M.getOrInsertNamedMetadata("hlsl.srvs");
+ break;
+ case llvm::hlsl::ResourceClass::CBuffer:
+ ResourceMD = M.getOrInsertNamedMetadata("hlsl.cbufs");
+ break;
+ default:
+ assert(false && "Unsupported buffer type!");
+ return;
+ }
+
+ assert(ResourceMD != nullptr &&
+ "ResourceMD must have been set by the switch above.");
+
+ llvm::hlsl::FrontendResource Res(
+ GV, TyName, RK, Binding.Reg.value_or(UINT_MAX), Binding.Space);
+ ResourceMD->addOperand(Res.getMetadata());
+}
+
+static llvm::hlsl::ResourceKind
+castResourceShapeToResourceKind(HLSLResourceAttr::ResourceKind RK) {
+ switch (RK) {
+ case HLSLResourceAttr::ResourceKind::Texture1D:
+ return llvm::hlsl::ResourceKind::Texture1D;
+ case HLSLResourceAttr::ResourceKind::Texture2D:
+ return llvm::hlsl::ResourceKind::Texture2D;
+ case HLSLResourceAttr::ResourceKind::Texture2DMS:
+ return llvm::hlsl::ResourceKind::Texture2DMS;
+ case HLSLResourceAttr::ResourceKind::Texture3D:
+ return llvm::hlsl::ResourceKind::Texture3D;
+ case HLSLResourceAttr::ResourceKind::TextureCube:
+ return llvm::hlsl::ResourceKind::TextureCube;
+ case HLSLResourceAttr::ResourceKind::Texture1DArray:
+ return llvm::hlsl::ResourceKind::Texture1DArray;
+ case HLSLResourceAttr::ResourceKind::Texture2DArray:
+ return llvm::hlsl::ResourceKind::Texture2DArray;
+ case HLSLResourceAttr::ResourceKind::Texture2DMSArray:
+ return llvm::hlsl::ResourceKind::Texture2DMSArray;
+ case HLSLResourceAttr::ResourceKind::TextureCubeArray:
+ return llvm::hlsl::ResourceKind::TextureCubeArray;
+ case HLSLResourceAttr::ResourceKind::TypedBuffer:
+ return llvm::hlsl::ResourceKind::TypedBuffer;
+ case HLSLResourceAttr::ResourceKind::RawBuffer:
+ return llvm::hlsl::ResourceKind::RawBuffer;
+ case HLSLResourceAttr::ResourceKind::StructuredBuffer:
+ return llvm::hlsl::ResourceKind::StructuredBuffer;
+ case HLSLResourceAttr::ResourceKind::CBufferKind:
+ return llvm::hlsl::ResourceKind::CBuffer;
+ case HLSLResourceAttr::ResourceKind::SamplerKind:
+ return llvm::hlsl::ResourceKind::Sampler;
+ case HLSLResourceAttr::ResourceKind::TBuffer:
+ return llvm::hlsl::ResourceKind::TBuffer;
+ case HLSLResourceAttr::ResourceKind::RTAccelerationStructure:
+ return llvm::hlsl::ResourceKind::RTAccelerationStructure;
+ case HLSLResourceAttr::ResourceKind::FeedbackTexture2D:
+ return llvm::hlsl::ResourceKind::FeedbackTexture2D;
+ case HLSLResourceAttr::ResourceKind::FeedbackTexture2DArray:
+ return llvm::hlsl::ResourceKind::FeedbackTexture2DArray;
+ }
+ // Make sure to update HLSLResourceAttr::ResourceKind when add new Kind to
+ // hlsl::ResourceKind. Assume FeedbackTexture2DArray is the last enum for
+ // HLSLResourceAttr::ResourceKind.
+ static_assert(
+ static_cast<uint32_t>(
+ HLSLResourceAttr::ResourceKind::FeedbackTexture2DArray) ==
+ (static_cast<uint32_t>(llvm::hlsl::ResourceKind::NumEntries) - 2));
+ llvm_unreachable("all switch cases should be covered");
+}
+
+void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
+ const Type *Ty = D->getType()->getPointeeOrArrayElementType();
+ if (!Ty)
+ return;
+ const auto *RD = Ty->getAsCXXRecordDecl();
+ if (!RD)
+ return;
+ const auto *Attr = RD->getAttr<HLSLResourceAttr>();
+ if (!Attr)
+ return;
+
+ HLSLResourceAttr::ResourceClass RC = Attr->getResourceType();
+ llvm::hlsl::ResourceKind RK =
+ castResourceShapeToResourceKind(Attr->getResourceShape());
+
+ QualType QT(Ty, 0);
+ BufferResBinding Binding(D->getAttr<HLSLResourceBindingAttr>());
+ addBufferResourceAnnotation(GV, QT.getAsString(),
+ static_cast<llvm::hlsl::ResourceClass>(RC), RK,
+ Binding);
+}
+
+CGHLSLRuntime::BufferResBinding::BufferResBinding(
+ HLSLResourceBindingAttr *Binding) {
+ if (Binding) {
+ llvm::APInt RegInt(64, 0);
+ Binding->getSlot().substr(1).getAsInteger(10, RegInt);
+ Reg = RegInt.getLimitedValue();
+ llvm::APInt SpaceInt(64, 0);
+ Binding->getSpace().substr(5).getAsInteger(10, SpaceInt);
+ Space = SpaceInt.getLimitedValue();
+ } else {
+ Space = 0;
+ }
+}
+
+void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes(
+ const FunctionDecl *FD, llvm::Function *Fn) {
+ const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
+ assert(ShaderAttr && "All entry functions must have a HLSLShaderAttr");
+ const StringRef ShaderAttrKindStr = "hlsl.shader";
+ Fn->addFnAttr(ShaderAttrKindStr,
+ ShaderAttr->ConvertShaderTypeToStr(ShaderAttr->getType()));
+ if (HLSLNumThreadsAttr *NumThreadsAttr = FD->getAttr<HLSLNumThreadsAttr>()) {
+ const StringRef NumThreadsKindStr = "hlsl.numthreads";
+ std::string NumThreadsStr =
+ formatv("{0},{1},{2}", NumThreadsAttr->getX(), NumThreadsAttr->getY(),
+ NumThreadsAttr->getZ());
+ Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
+ }
+}
+
+static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
+ if (const auto *VT = dyn_cast<FixedVectorType>(Ty)) {
+ Value *Result = PoisonValue::get(Ty);
+ for (unsigned I = 0; I < VT->getNumElements(); ++I) {
+ Value *Elt = B.CreateCall(F, {B.getInt32(I)});
+ Result = B.CreateInsertElement(Result, Elt, I);
+ }
+ return Result;
+ }
+ return B.CreateCall(F, {B.getInt32(0)});
+}
+
+llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
+ const ParmVarDecl &D,
+ llvm::Type *Ty) {
+ assert(D.hasAttrs() && "Entry parameter missing annotation attribute!");
+ if (D.hasAttr<HLSLSV_GroupIndexAttr>()) {
+ llvm::Function *DxGroupIndex =
+ CGM.getIntrinsic(Intrinsic::dx_flattened_thread_id_in_group);
+ return B.CreateCall(FunctionCallee(DxGroupIndex));
+ }
+ if (D.hasAttr<HLSLSV_DispatchThreadIDAttr>()) {
+ llvm::Function *DxThreadID = CGM.getIntrinsic(Intrinsic::dx_thread_id);
+ return buildVectorInput(B, DxThreadID, Ty);
+ }
+ assert(false && "Unhandled parameter attribute");
+ return nullptr;
+}
+
+void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD,
+ llvm::Function *Fn) {
+ llvm::Module &M = CGM.getModule();
+ llvm::LLVMContext &Ctx = M.getContext();
+ auto *EntryTy = llvm::FunctionType::get(llvm::Type::getVoidTy(Ctx), false);
+ Function *EntryFn =
+ Function::Create(EntryTy, Function::ExternalLinkage, FD->getName(), &M);
+
+ // Copy function attributes over, we have no argument or return attributes
+ // that can be valid on the real entry.
+ AttributeList NewAttrs = AttributeList::get(Ctx, AttributeList::FunctionIndex,
+ Fn->getAttributes().getFnAttrs());
+ EntryFn->setAttributes(NewAttrs);
+ setHLSLEntryAttributes(FD, EntryFn);
+
+ // Set the called function as internal linkage.
+ Fn->setLinkage(GlobalValue::InternalLinkage);
+
+ BasicBlock *BB = BasicBlock::Create(Ctx, "entry", EntryFn);
+ IRBuilder<> B(BB);
+ llvm::SmallVector<Value *> Args;
+ // FIXME: support struct parameters where semantics are on members.
+ // See: https://github.com/llvm/llvm-project/issues/57874
+ unsigned SRetOffset = 0;
+ for (const auto &Param : Fn->args()) {
+ if (Param.hasStructRetAttr()) {
+ // FIXME: support output.
+ // See: https://github.com/llvm/llvm-project/issues/57874
+ SRetOffset = 1;
+ Args.emplace_back(PoisonValue::get(Param.getType()));
+ continue;
+ }
+ const ParmVarDecl *PD = FD->getParamDecl(Param.getArgNo() - SRetOffset);
+ Args.push_back(emitInputSemantic(B, *PD, Param.getType()));
+ }
+
+ CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args);
+ (void)CI;
+ // FIXME: Handle codegen for return type semantics.
+ // See: https://github.com/llvm/llvm-project/issues/57875
+ B.CreateRetVoid();
+}
+
+static void gatherFunctions(SmallVectorImpl<Function *> &Fns, llvm::Module &M,
+ bool CtorOrDtor) {
+ const auto *GV =
+ M.getNamedGlobal(CtorOrDtor ? "llvm.global_ctors" : "llvm.global_dtors");
+ if (!GV)
+ return;
+ const auto *CA = dyn_cast<ConstantArray>(GV->getInitializer());
+ if (!CA)
+ return;
+ // The global_ctor array elements are a struct [Priority, Fn *, COMDat].
+ // HLSL neither supports priorities or COMDat values, so we will check those
+ // in an assert but not handle them.
+
+ llvm::SmallVector<Function *> CtorFns;
+ for (const auto &Ctor : CA->operands()) {
+ if (isa<ConstantAggregateZero>(Ctor))
+ continue;
+ ConstantStruct *CS = cast<ConstantStruct>(Ctor);
+
+ assert(cast<ConstantInt>(CS->getOperand(0))->getValue() == 65535 &&
+ "HLSL doesn't support setting priority for global ctors.");
+ assert(isa<ConstantPointerNull>(CS->getOperand(2)) &&
+ "HLSL doesn't support COMDat for global ctors.");
+ Fns.push_back(cast<Function>(CS->getOperand(1)));
+ }
+}
+
+void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
+ llvm::Module &M = CGM.getModule();
+ SmallVector<Function *> CtorFns;
+ SmallVector<Function *> DtorFns;
+ gatherFunctions(CtorFns, M, true);
+ gatherFunctions(DtorFns, M, false);
+
+ // Insert a call to the global constructor at the beginning of the entry block
+ // to externally exported functions. This is a bit of a hack, but HLSL allows
+ // global constructors, but doesn't support driver initialization of globals.
+ for (auto &F : M.functions()) {
+ if (!F.hasFnAttribute("hlsl.shader"))
+ continue;
+ IRBuilder<> B(&F.getEntryBlock(), F.getEntryBlock().begin());
+ for (auto *Fn : CtorFns)
+ B.CreateCall(FunctionCallee(Fn));
+
+ // Insert global dtors before the terminator of the last instruction
+ B.SetInsertPoint(F.back().getTerminator());
+ for (auto *Fn : DtorFns)
+ B.CreateCall(FunctionCallee(Fn));
+ }
+
+ // No need to keep global ctors/dtors for non-lib profile after call to
+ // ctors/dtors added for entry.
+ Triple T(M.getTargetTriple());
+ if (T.getEnvironment() != Triple::EnvironmentType::Library) {
+ if (auto *GV = M.getNamedGlobal("llvm.global_ctors"))
+ GV->eraseFromParent();
+ if (auto *GV = M.getNamedGlobal("llvm.global_dtors"))
+ GV->eraseFromParent();
+ }
}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 268810f2ec9e..67413fbd4a78 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -15,21 +15,88 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H
#define LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H
+#include "llvm/IR/IRBuilder.h"
+
+#include "clang/Basic/HLSLRuntime.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Frontend/HLSL/HLSLResource.h"
+
+#include <optional>
+#include <vector>
+
+namespace llvm {
+class GlobalVariable;
+class Function;
+class StructType;
+} // namespace llvm
+
namespace clang {
+class VarDecl;
+class ParmVarDecl;
+class HLSLBufferDecl;
+class HLSLResourceBindingAttr;
+class Type;
+class DeclContext;
+
+class FunctionDecl;
namespace CodeGen {
class CodeGenModule;
class CGHLSLRuntime {
+public:
+ struct BufferResBinding {
+ // The ID like 2 in register(b2, space1).
+ std::optional<unsigned> Reg;
+ // The Space like 1 is register(b2, space1).
+ // Default value is 0.
+ unsigned Space;
+ BufferResBinding(HLSLResourceBindingAttr *Attr);
+ };
+ struct Buffer {
+ Buffer(const HLSLBufferDecl *D);
+ llvm::StringRef Name;
+ // IsCBuffer - Whether the buffer is a cbuffer (and not a tbuffer).
+ bool IsCBuffer;
+ BufferResBinding Binding;
+ // Global variable and offset for each constant.
+ std::vector<std::pair<llvm::GlobalVariable *, unsigned>> Constants;
+ llvm::StructType *LayoutStruct = nullptr;
+ };
+
protected:
CodeGenModule &CGM;
+ llvm::Value *emitInputSemantic(llvm::IRBuilder<> &B, const ParmVarDecl &D,
+ llvm::Type *Ty);
+
public:
CGHLSLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
virtual ~CGHLSLRuntime() {}
+ void annotateHLSLResource(const VarDecl *D, llvm::GlobalVariable *GV);
+ void generateGlobalCtorDtorCalls();
+
+ void addBuffer(const HLSLBufferDecl *D);
void finishCodeGen();
+
+ void setHLSLEntryAttributes(const FunctionDecl *FD, llvm::Function *Fn);
+
+ void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn);
+ void setHLSLFunctionAttributes(llvm::Function *, const FunctionDecl *);
+
+private:
+ void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
+ llvm::StringRef TyName,
+ llvm::hlsl::ResourceClass RC,
+ llvm::hlsl::ResourceKind RK,
+ BufferResBinding &Binding);
+ void addConstant(VarDecl *D, Buffer &CB);
+ void addBufferDecls(const DeclContext *DC, Buffer &CB);
+ llvm::SmallVector<Buffer> Buffers;
};
} // namespace CodeGen
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index 12a6cd8da603..e5d9db273c2d 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -17,6 +17,7 @@
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Metadata.h"
+#include <optional>
using namespace clang::CodeGen;
using namespace llvm;
@@ -37,7 +38,7 @@ MDNode *LoopInfo::createPipeliningMetadata(const LoopAttributes &Attrs,
bool &HasUserTransforms) {
LLVMContext &Ctx = Header->getContext();
- Optional<bool> Enabled;
+ std::optional<bool> Enabled;
if (Attrs.PipelineDisabled)
Enabled = false;
else if (Attrs.PipelineInitiationInterval != 0)
@@ -82,11 +83,11 @@ LoopInfo::createPartialUnrollMetadata(const LoopAttributes &Attrs,
bool &HasUserTransforms) {
LLVMContext &Ctx = Header->getContext();
- Optional<bool> Enabled;
+ std::optional<bool> Enabled;
if (Attrs.UnrollEnable == LoopAttributes::Disable)
Enabled = false;
else if (Attrs.UnrollEnable == LoopAttributes::Full)
- Enabled = None;
+ Enabled = std::nullopt;
else if (Attrs.UnrollEnable != LoopAttributes::Unspecified ||
Attrs.UnrollCount != 0)
Enabled = true;
@@ -144,7 +145,7 @@ LoopInfo::createUnrollAndJamMetadata(const LoopAttributes &Attrs,
bool &HasUserTransforms) {
LLVMContext &Ctx = Header->getContext();
- Optional<bool> Enabled;
+ std::optional<bool> Enabled;
if (Attrs.UnrollAndJamEnable == LoopAttributes::Disable)
Enabled = false;
else if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable ||
@@ -212,7 +213,7 @@ LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs,
bool &HasUserTransforms) {
LLVMContext &Ctx = Header->getContext();
- Optional<bool> Enabled;
+ std::optional<bool> Enabled;
if (Attrs.VectorizeEnable == LoopAttributes::Disable)
Enabled = false;
else if (Attrs.VectorizeEnable != LoopAttributes::Unspecified ||
@@ -330,7 +331,7 @@ LoopInfo::createLoopDistributeMetadata(const LoopAttributes &Attrs,
bool &HasUserTransforms) {
LLVMContext &Ctx = Header->getContext();
- Optional<bool> Enabled;
+ std::optional<bool> Enabled;
if (Attrs.DistributeEnable == LoopAttributes::Disable)
Enabled = false;
if (Attrs.DistributeEnable == LoopAttributes::Enable)
@@ -380,7 +381,7 @@ MDNode *LoopInfo::createFullUnrollMetadata(const LoopAttributes &Attrs,
bool &HasUserTransforms) {
LLVMContext &Ctx = Header->getContext();
- Optional<bool> Enabled;
+ std::optional<bool> Enabled;
if (Attrs.UnrollEnable == LoopAttributes::Disable)
Enabled = false;
else if (Attrs.UnrollEnable == LoopAttributes::Full)
@@ -496,7 +497,7 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
!EndLoc && !Attrs.MustProgress)
return;
- TempLoopID = MDNode::getTemporary(Header->getContext(), None);
+ TempLoopID = MDNode::getTemporary(Header->getContext(), std::nullopt);
}
void LoopInfo::finish() {
diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
index 1b6acb2b7212..7df2088a81d7 100644
--- a/clang/lib/CodeGen/CGObjC.cpp
+++ b/clang/lib/CodeGen/CGObjC.cpp
@@ -22,11 +22,14 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/CodeGenABITypes.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/ObjCARCUtil.h"
#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -138,7 +141,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getBeginLoc());
cast<llvm::LoadInst>(Ptr)->setMetadata(
CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(getLLVMContext(), None));
+ llvm::MDNode::get(getLLVMContext(), std::nullopt));
return Builder.CreateBitCast(Ptr, ConvertType(E->getType()));
}
@@ -370,16 +373,14 @@ static const Expr *findWeakLValue(const Expr *E) {
///
/// If the runtime does support a required entrypoint, then this method will
/// generate a call and return the resulting value. Otherwise it will return
-/// None and the caller can generate a msgSend instead.
-static Optional<llvm::Value *>
-tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
- llvm::Value *Receiver,
- const CallArgList& Args, Selector Sel,
- const ObjCMethodDecl *method,
- bool isClassMessage) {
+/// std::nullopt and the caller can generate a msgSend instead.
+static std::optional<llvm::Value *> tryGenerateSpecializedMessageSend(
+ CodeGenFunction &CGF, QualType ResultType, llvm::Value *Receiver,
+ const CallArgList &Args, Selector Sel, const ObjCMethodDecl *method,
+ bool isClassMessage) {
auto &CGM = CGF.CGM;
if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
- return None;
+ return std::nullopt;
auto &Runtime = CGM.getLangOpts().ObjCRuntime;
switch (Sel.getMethodFamily()) {
@@ -400,7 +401,7 @@ tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
if (isa<llvm::ConstantPointerNull>(arg))
return CGF.EmitObjCAllocWithZone(Receiver,
CGF.ConvertType(ResultType));
- return None;
+ return std::nullopt;
}
}
break;
@@ -431,7 +432,7 @@ tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
default:
break;
}
- return None;
+ return std::nullopt;
}
CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
@@ -439,7 +440,7 @@ CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
Selector Sel, llvm::Value *Receiver, const CallArgList &Args,
const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method,
bool isClassMessage) {
- if (Optional<llvm::Value *> SpecializedResult =
+ if (std::optional<llvm::Value *> SpecializedResult =
tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args,
Sel, Method, isClassMessage)) {
return RValue::get(*SpecializedResult);
@@ -520,36 +521,36 @@ CGObjCRuntime::GetRuntimeProtocolList(ObjCProtocolDecl::protocol_iterator begin,
/// Instead of '[[MyClass alloc] init]', try to generate
/// 'objc_alloc_init(MyClass)'. This provides a code size improvement on the
/// caller side, as well as the optimized objc_alloc.
-static Optional<llvm::Value *>
+static std::optional<llvm::Value *>
tryEmitSpecializedAllocInit(CodeGenFunction &CGF, const ObjCMessageExpr *OME) {
auto &Runtime = CGF.getLangOpts().ObjCRuntime;
if (!Runtime.shouldUseRuntimeFunctionForCombinedAllocInit())
- return None;
+ return std::nullopt;
// Match the exact pattern '[[MyClass alloc] init]'.
Selector Sel = OME->getSelector();
if (OME->getReceiverKind() != ObjCMessageExpr::Instance ||
!OME->getType()->isObjCObjectPointerType() || !Sel.isUnarySelector() ||
Sel.getNameForSlot(0) != "init")
- return None;
+ return std::nullopt;
// Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]'
// with 'cls' a Class.
auto *SubOME =
dyn_cast<ObjCMessageExpr>(OME->getInstanceReceiver()->IgnoreParenCasts());
if (!SubOME)
- return None;
+ return std::nullopt;
Selector SubSel = SubOME->getSelector();
if (!SubOME->getType()->isObjCObjectPointerType() ||
!SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc")
- return None;
+ return std::nullopt;
llvm::Value *Receiver = nullptr;
switch (SubOME->getReceiverKind()) {
case ObjCMessageExpr::Instance:
if (!SubOME->getInstanceReceiver()->getType()->isObjCClassType())
- return None;
+ return std::nullopt;
Receiver = CGF.EmitScalarExpr(SubOME->getInstanceReceiver());
break;
@@ -563,7 +564,7 @@ tryEmitSpecializedAllocInit(CodeGenFunction &CGF, const ObjCMessageExpr *OME) {
}
case ObjCMessageExpr::SuperInstance:
case ObjCMessageExpr::SuperClass:
- return None;
+ return std::nullopt;
}
return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));
@@ -590,7 +591,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
}
}
- if (Optional<llvm::Value *> Val = tryEmitSpecializedAllocInit(*this, E))
+ if (std::optional<llvm::Value *> Val = tryEmitSpecializedAllocInit(*this, E))
return AdjustObjCObjectType(*this, E->getType(), RValue::get(*Val));
// We don't retain the receiver in delegate init calls, and this is
@@ -768,7 +769,8 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
}
args.push_back(OMD->getSelfDecl());
- args.push_back(OMD->getCmdDecl());
+ if (!OMD->isDirectMethod())
+ args.push_back(OMD->getCmdDecl());
args.append(OMD->param_begin(), OMD->param_end());
@@ -1110,11 +1112,47 @@ static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
callee, ReturnValueSlot(), args);
}
+// emitCmdValueForGetterSetterBody - Handle emitting the load necessary for
+// the `_cmd` selector argument for getter/setter bodies. For direct methods,
+// this returns an undefined/poison value; this matches behavior prior to `_cmd`
+// being removed from the direct method ABI as the getter/setter caller would
+// never load one. For non-direct methods, this emits a load of the implicit
+// `_cmd` storage.
+static llvm::Value *emitCmdValueForGetterSetterBody(CodeGenFunction &CGF,
+ ObjCMethodDecl *MD) {
+ if (MD->isDirectMethod()) {
+ // Direct methods do not have a `_cmd` argument. Emit an undefined/poison
+ // value. This will be passed to objc_getProperty/objc_setProperty, which
+ // has not appeared bothered by the `_cmd` argument being undefined before.
+ llvm::Type *selType = CGF.ConvertType(CGF.getContext().getObjCSelType());
+ return llvm::PoisonValue::get(selType);
+ }
+
+ return CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(MD->getCmdDecl()), "cmd");
+}
+
void
CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyImplDecl *propImpl,
const ObjCMethodDecl *GetterMethodDecl,
llvm::Constant *AtomicHelperFn) {
+
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+
+ if (ivar->getType().isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
+ if (!AtomicHelperFn) {
+ LValue Src =
+ EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
+ LValue Dst = MakeAddrLValue(ReturnValue, ivar->getType());
+ callCStructCopyConstructor(Dst, Src);
+ } else {
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+ emitCPPObjectAtomicGetterCall(*this, ReturnValue.getPointer(), ivar,
+ AtomicHelperFn);
+ }
+ return;
+ }
+
// If there's a non-trivial 'get' expression, we just have to emit that.
if (!hasTrivialGetExpr(propImpl)) {
if (!AtomicHelperFn) {
@@ -1135,8 +1173,6 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
QualType propType = prop->getType();
ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl();
- ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
-
// Pick an implementation strategy.
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
@@ -1188,11 +1224,10 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
// Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true).
// FIXME: Can't this be simpler? This might even be worse than the
// corresponding gcc code.
- llvm::Value *cmd =
- Builder.CreateLoad(GetAddrOfLocalVar(getterMethod->getCmdDecl()), "cmd");
+ llvm::Value *cmd = emitCmdValueForGetterSetterBody(*this, getterMethod);
llvm::Value *self = Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
llvm::Value *ivarOffset =
- EmitIvarOffset(classImpl->getClassInterface(), ivar);
+ EmitIvarOffsetAsPointerDiff(classImpl->getClassInterface(), ivar);
CallArgList args;
args.add(RValue::get(self), getContext().getObjCIdType());
@@ -1404,6 +1439,24 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
ObjCMethodDecl *setterMethod = propImpl->getSetterMethodDecl();
+ if (ivar->getType().isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
+ ParmVarDecl *PVD = *setterMethod->param_begin();
+ if (!AtomicHelperFn) {
+ // Call the move assignment operator instead of calling the copy
+ // assignment operator and destructor.
+ LValue Dst = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar,
+ /*quals*/ 0);
+ LValue Src = MakeAddrLValue(GetAddrOfLocalVar(PVD), ivar->getType());
+ callCStructMoveAssignmentOperator(Dst, Src);
+ } else {
+ // If atomic, assignment is called via a locking api.
+ emitCPPObjectAtomicSetterCall(*this, setterMethod, ivar, AtomicHelperFn);
+ }
+ // Decativate the destructor for the setter parameter.
+ DeactivateCleanupBlock(CalleeDestructedParamCleanups[PVD], AllocaInsertPt);
+ return;
+ }
+
// Just use the setter expression if Sema gave us one and it's
// non-trivial.
if (!hasTrivialSetExpr(propImpl)) {
@@ -1474,12 +1527,11 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
// Emit objc_setProperty((id) self, _cmd, offset, arg,
// <is-atomic>, <is-copy>).
- llvm::Value *cmd =
- Builder.CreateLoad(GetAddrOfLocalVar(setterMethod->getCmdDecl()));
+ llvm::Value *cmd = emitCmdValueForGetterSetterBody(*this, setterMethod);
llvm::Value *self =
Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
llvm::Value *ivarOffset =
- EmitIvarOffset(classImpl->getClassInterface(), ivar);
+ EmitIvarOffsetAsPointerDiff(classImpl->getClassInterface(), ivar);
Address argAddr = GetAddrOfLocalVar(*setterMethod->param_begin());
llvm::Value *arg = Builder.CreateLoad(argAddr, "arg");
arg = Builder.CreateBitCast(arg, VoidPtrTy);
@@ -1749,7 +1801,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
&CGM.getContext().Idents.get("count")
};
Selector FastEnumSel =
- CGM.getContext().Selectors.getSelector(llvm::array_lengthof(II), &II[0]);
+ CGM.getContext().Selectors.getSelector(std::size(II), &II[0]);
QualType ItemsTy =
getContext().getConstantArrayType(getContext().getObjCIdType(),
@@ -2290,7 +2342,7 @@ llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
CGM.getObjCEntrypoints().objc_retainBlock);
call->setMetadata("clang.arc.copy_on_escape",
- llvm::MDNode::get(Builder.getContext(), None));
+ llvm::MDNode::get(Builder.getContext(), std::nullopt));
}
return result;
@@ -2332,7 +2384,8 @@ static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
// Call the marker asm if we made one, which we do only at -O0.
if (marker)
- CGF.Builder.CreateCall(marker, None, CGF.getBundlesForFunclet(marker));
+ CGF.Builder.CreateCall(marker, std::nullopt,
+ CGF.getBundlesForFunclet(marker));
}
static llvm::Value *emitOptimizedARCReturnCall(llvm::Value *value,
@@ -2418,7 +2471,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value,
if (precise == ARCImpreciseLifetime) {
call->setMetadata("clang.imprecise_release",
- llvm::MDNode::get(Builder.getContext(), None));
+ llvm::MDNode::get(Builder.getContext(), std::nullopt));
}
}
@@ -2816,7 +2869,7 @@ void CodeGenFunction::EmitObjCRelease(llvm::Value *value,
if (precise == ARCImpreciseLifetime) {
call->setMetadata("clang.imprecise_release",
- llvm::MDNode::get(Builder.getContext(), None));
+ llvm::MDNode::get(Builder.getContext(), std::nullopt));
}
}
@@ -3661,15 +3714,27 @@ void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
llvm::Constant *
CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
+ const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
+ return nullptr;
+
+ QualType Ty = PID->getPropertyIvarDecl()->getType();
+ ASTContext &C = getContext();
+
+ if (Ty.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
+ // Call the move assignment operator instead of calling the copy assignment
+ // operator and destructor.
+ CharUnits Alignment = C.getTypeAlignInChars(Ty);
+ llvm::Constant *Fn = getNonTrivialCStructMoveAssignmentOperator(
+ CGM, Alignment, Alignment, Ty.isVolatileQualified(), Ty);
+ return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
+ }
+
if (!getLangOpts().CPlusPlus ||
!getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return nullptr;
- QualType Ty = PID->getPropertyIvarDecl()->getType();
if (!Ty->isRecordType())
return nullptr;
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
- return nullptr;
llvm::Constant *HelperFn = nullptr;
if (hasTrivialSetExpr(PID))
return nullptr;
@@ -3677,7 +3742,6 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
if ((HelperFn = CGM.getAtomicSetterHelperFnMap(Ty)))
return HelperFn;
- ASTContext &C = getContext();
IdentifierInfo *II
= &CGM.getContext().Idents.get("__assign_helper_atomic_property_");
@@ -3748,18 +3812,27 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
return HelperFn;
}
-llvm::Constant *
-CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
- const ObjCPropertyImplDecl *PID) {
+llvm::Constant *CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
+ const ObjCPropertyImplDecl *PID) {
+ const ObjCPropertyDecl *PD = PID->getPropertyDecl();
+ if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
+ return nullptr;
+
+ QualType Ty = PD->getType();
+ ASTContext &C = getContext();
+
+ if (Ty.isNonTrivialToPrimitiveCopy() == QualType::PCK_Struct) {
+ CharUnits Alignment = C.getTypeAlignInChars(Ty);
+ llvm::Constant *Fn = getNonTrivialCStructCopyConstructor(
+ CGM, Alignment, Alignment, Ty.isVolatileQualified(), Ty);
+ return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
+ }
+
if (!getLangOpts().CPlusPlus ||
!getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return nullptr;
- const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- QualType Ty = PD->getType();
if (!Ty->isRecordType())
return nullptr;
- if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
- return nullptr;
llvm::Constant *HelperFn = nullptr;
if (hasTrivialGetExpr(PID))
return nullptr;
@@ -3767,7 +3840,6 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty)))
return HelperFn;
- ASTContext &C = getContext();
IdentifierInfo *II =
&CGM.getContext().Idents.get("__copy_helper_atomic_property_");
@@ -3911,7 +3983,8 @@ static llvm::Value *emitIsPlatformVersionAtLeast(CodeGenFunction &CGF,
llvm::SmallVector<llvm::Value *, 8> Args;
auto EmitArgs = [&](const VersionTuple &Version, const llvm::Triple &TT) {
- Optional<unsigned> Min = Version.getMinor(), SMin = Version.getSubminor();
+ std::optional<unsigned> Min = Version.getMinor(),
+ SMin = Version.getSubminor();
Args.push_back(
llvm::ConstantInt::get(CGM.Int32Ty, getBaseMachOPlatformID(TT)));
Args.push_back(llvm::ConstantInt::get(CGM.Int32Ty, Version.getMajor()));
@@ -3949,7 +4022,8 @@ CodeGenFunction::EmitBuiltinAvailable(const VersionTuple &Version) {
CGM.CreateRuntimeFunction(FTy, "__isOSVersionAtLeast");
}
- Optional<unsigned> Min = Version.getMinor(), SMin = Version.getSubminor();
+ std::optional<unsigned> Min = Version.getMinor(),
+ SMin = Version.getSubminor();
llvm::Value *Args[] = {
llvm::ConstantInt::get(CGM.Int32Ty, Version.getMajor()),
llvm::ConstantInt::get(CGM.Int32Ty, Min.value_or(0)),
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index 7bbe9af7ed59..c7b193e34ea0 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -71,7 +71,7 @@ public:
FTy = llvm::FunctionType::get(RetTy, ArgTys, false);
}
else {
- FTy = llvm::FunctionType::get(RetTy, None, false);
+ FTy = llvm::FunctionType::get(RetTy, std::nullopt, false);
}
}
@@ -985,7 +985,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
auto LiteralLength = SL->getLength();
- if ((CGM.getTarget().getPointerWidth(0) == 64) &&
+ if ((CGM.getTarget().getPointerWidth(LangAS::Default) == 64) &&
(LiteralLength < 9) && !isNonASCII) {
// Tiny strings are only used on 64-bit platforms. They store 8 7-bit
// ASCII characters in the high 56 bits, followed by a 4-bit length and a
@@ -1064,7 +1064,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
// Hash. Not currently initialised by the compiler.
Fields.addInt(Int32Ty, 0);
// pointer to the data string.
- auto Arr = llvm::makeArrayRef(&ToBuf[0], ToPtr+1);
+ auto Arr = llvm::ArrayRef(&ToBuf[0], ToPtr + 1);
auto *C = llvm::ConstantDataArray::get(VMContext, Arr);
auto *Buffer = new llvm::GlobalVariable(TheModule, C->getType(),
/*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, C, ".str");
@@ -3316,7 +3316,7 @@ llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) {
auto fields = builder.beginStruct();
fields.addInt(Int32Ty, values.size());
auto array = fields.beginArray();
- for (auto v : values) array.add(v);
+ for (auto *v : values) array.add(v);
array.finishAndAddTo(fields);
llvm::Constant *GS =
@@ -3851,9 +3851,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
llvm::Type *moduleEltTys[] = {
LongTy, LongTy, PtrToInt8Ty, symtab->getType(), IntTy
};
- llvm::StructType *moduleTy =
- llvm::StructType::get(CGM.getLLVMContext(),
- makeArrayRef(moduleEltTys).drop_back(unsigned(RuntimeVersion < 10)));
+ llvm::StructType *moduleTy = llvm::StructType::get(
+ CGM.getLLVMContext(),
+ ArrayRef(moduleEltTys).drop_back(unsigned(RuntimeVersion < 10)));
ConstantInitBuilder builder(CGM);
auto module = builder.beginStruct(moduleTy);
@@ -3864,8 +3864,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
// The path to the source file where this module was declared
SourceManager &SM = CGM.getContext().getSourceManager();
- Optional<FileEntryRef> mainFile =
- SM.getFileEntryRefForID(SM.getMainFileID());
+ OptionalFileEntryRef mainFile = SM.getFileEntryRefForID(SM.getMainFileID());
std::string path =
(mainFile->getDir().getName() + "/" + mainFile->getName()).str();
module.add(MakeConstantString(path, ".objc_source_file_name"));
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index 46e65eb1ed43..c739d3742f80 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -174,6 +174,7 @@ protected:
public:
llvm::IntegerType *ShortTy, *IntTy, *LongTy;
llvm::PointerType *Int8PtrTy, *Int8PtrPtrTy;
+ llvm::PointerType *Int8PtrProgramASTy;
llvm::Type *IvarOffsetVarTy;
/// ObjectPtrTy - LLVM type for object handles (typeof(id))
@@ -736,14 +737,17 @@ public:
// Also it is safe to make it readnone, since we never load or store the
// classref except by calling this function.
llvm::Type *params[] = { Int8PtrPtrTy };
+ llvm::LLVMContext &C = CGM.getLLVMContext();
+ llvm::AttributeSet AS = llvm::AttributeSet::get(C, {
+ llvm::Attribute::get(C, llvm::Attribute::NonLazyBind),
+ llvm::Attribute::getWithMemoryEffects(C, llvm::MemoryEffects::none()),
+ llvm::Attribute::get(C, llvm::Attribute::NoUnwind),
+ });
llvm::FunctionCallee F = CGM.CreateRuntimeFunction(
llvm::FunctionType::get(ClassnfABIPtrTy, params, false),
"objc_loadClassref",
llvm::AttributeList::get(CGM.getLLVMContext(),
- llvm::AttributeList::FunctionIndex,
- {llvm::Attribute::NonLazyBind,
- llvm::Attribute::ReadNone,
- llvm::Attribute::NoUnwind}));
+ llvm::AttributeList::FunctionIndex, AS));
if (!CGM.getTriple().isOSBinFormatCOFF())
cast<llvm::Function>(F.getCallee())->setLinkage(
llvm::Function::ExternalWeakLinkage);
@@ -1170,7 +1174,7 @@ public:
static ProtocolMethodLists get(const ObjCProtocolDecl *PD) {
ProtocolMethodLists result;
- for (auto MD : PD->methods()) {
+ for (auto *MD : PD->methods()) {
size_t index = (2 * size_t(MD->isOptional()))
+ (size_t(MD->isClassMethod()));
result.Methods[index].push_back(MD);
@@ -2144,7 +2148,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy);
ActualArgs.add(RValue::get(Arg0), Arg0Ty);
- ActualArgs.add(RValue::get(SelValue), selTy);
+ if (!Method || !Method->isDirectMethod())
+ ActualArgs.add(RValue::get(SelValue), selTy);
ActualArgs.addFrom(CallArgs);
// If we're calling a method, use the formal signature.
@@ -2402,8 +2407,8 @@ void IvarLayoutBuilder::visitBlock(const CGBlockInfo &blockInfo) {
Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), type);
if (GCAttr == Qualifiers::Strong) {
- assert(CGM.getContext().getTypeSize(type)
- == CGM.getTarget().getPointerWidth(0));
+ assert(CGM.getContext().getTypeSize(type) ==
+ CGM.getTarget().getPointerWidth(LangAS::Default));
IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
}
}
@@ -2696,7 +2701,7 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
if (RunSkipBlockVars.empty())
return nullPtr;
- unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
+ unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(LangAS::Default);
unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
@@ -2882,7 +2887,7 @@ void CGObjCCommonMac::fillRunSkipBlockVars(CodeGenModule &CGM,
RunSkipBlockVars.clear();
bool hasUnion = false;
- unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
+ unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(LangAS::Default);
unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
@@ -3453,7 +3458,7 @@ static bool hasWeakMember(QualType type) {
}
if (auto recType = type->getAs<RecordType>()) {
- for (auto field : recType->getDecl()->fields()) {
+ for (auto *field : recType->getDecl()->fields()) {
if (hasWeakMember(field->getType()))
return true;
}
@@ -4102,6 +4107,9 @@ void CGObjCCommonMac::GenerateDirectMethodPrologue(
// only synthesize _cmd if it's referenced
if (OMD->getCmdDecl()->isUsed()) {
+ // `_cmd` is not a parameter to direct methods, so storage must be
+ // explicitly declared for it.
+ CGF.EmitVarDecl(*OMD->getCmdDecl());
Builder.CreateStore(GetSelector(CGF, OMD),
CGF.GetAddrOfLocalVar(OMD->getCmdDecl()));
}
@@ -5739,11 +5747,13 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
{
CodeGen::CodeGenTypes &Types = CGM.getTypes();
ASTContext &Ctx = CGM.getContext();
+ unsigned ProgramAS = CGM.getDataLayout().getProgramAddressSpace();
ShortTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.ShortTy));
IntTy = CGM.IntTy;
LongTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.LongTy));
Int8PtrTy = CGM.Int8PtrTy;
+ Int8PtrProgramASTy = llvm::PointerType::get(CGM.Int8Ty, ProgramAS);
Int8PtrPtrTy = CGM.Int8PtrPtrTy;
// arm64 targets use "int" ivar offset variables. All others,
@@ -5812,7 +5822,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
// char *_imp;
// }
MethodTy = llvm::StructType::create("struct._objc_method", SelectorPtrTy,
- Int8PtrTy, Int8PtrTy);
+ Int8PtrTy, Int8PtrProgramASTy);
// struct _objc_cache *
CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
@@ -6198,8 +6208,7 @@ void CGObjCNonFragileABIMac::AddModuleClassList(
llvm::GlobalVariable *GV = new llvm::GlobalVariable(
CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::PrivateLinkage, Init, SymbolName);
- GV->setAlignment(
- llvm::Align(CGM.getDataLayout().getABITypeAlignment(Init->getType())));
+ GV->setAlignment(CGM.getDataLayout().getABITypeAlign(Init->getType()));
GV->setSection(SectionName);
CGM.addCompilerUsedGlobal(GV);
}
@@ -6431,8 +6440,7 @@ CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI,
if (CGM.getTriple().isOSBinFormatMachO())
GV->setSection("__DATA, __objc_data");
- GV->setAlignment(llvm::Align(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy)));
+ GV->setAlignment(CGM.getDataLayout().getABITypeAlign(ObjCTypes.ClassnfABITy));
if (!CGM.getTriple().isOSBinFormatCOFF())
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
@@ -6771,11 +6779,11 @@ void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
if (forProtocol) {
// Protocol methods have no implementation. So, this entry is always NULL.
- method.addNullPointer(ObjCTypes.Int8PtrTy);
+ method.addNullPointer(ObjCTypes.Int8PtrProgramASTy);
} else {
llvm::Function *fn = GetMethodDefinition(MD);
assert(fn && "no definition for method?");
- method.addBitCast(fn, ObjCTypes.Int8PtrTy);
+ method.addBitCast(fn, ObjCTypes.Int8PtrProgramASTy);
}
method.finishAndAddTo(builder);
@@ -6893,8 +6901,8 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
IvarOffsetGV->setInitializer(
llvm::ConstantInt::get(ObjCTypes.IvarOffsetVarTy, Offset));
- IvarOffsetGV->setAlignment(llvm::Align(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.IvarOffsetVarTy)));
+ IvarOffsetGV->setAlignment(
+ CGM.getDataLayout().getABITypeAlign(ObjCTypes.IvarOffsetVarTy));
if (!CGM.getTriple().isOSBinFormatCOFF()) {
// FIXME: This matches gcc, but shouldn't the visibility be set on the use
@@ -7122,8 +7130,8 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
ProtocolRef);
if (!CGM.getTriple().isOSBinFormatMachO())
PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef));
- PTGV->setAlignment(llvm::Align(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)));
+ PTGV->setAlignment(
+ CGM.getDataLayout().getABITypeAlign(ObjCTypes.ProtocolnfABIPtrTy));
PTGV->setSection(GetSectionName("__objc_protolist",
"coalesced,no_dead_strip"));
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
@@ -7222,7 +7230,7 @@ CGObjCNonFragileABIMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF,
if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
cast<llvm::LoadInst>(IvarOffsetValue)
->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext, None));
+ llvm::MDNode::get(VMContext, std::nullopt));
}
// This could be 32bit int or 64bit integer depending on the architecture.
@@ -7622,7 +7630,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
llvm::LoadInst* LI = CGF.Builder.CreateLoad(Addr);
LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext, None));
+ llvm::MDNode::get(VMContext, std::nullopt));
return LI;
}
diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp
index 550fd3d70bdc..9097a8cf7009 100644
--- a/clang/lib/CodeGen/CGObjCRuntime.cpp
+++ b/clang/lib/CodeGen/CGObjCRuntime.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGen/CodeGenABITypes.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -227,13 +228,18 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CatchHandler &Handler = Handlers[I];
CGF.EmitBlock(Handler.Block);
- llvm::CatchPadInst *CPI = nullptr;
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(CGF.CurrentFuncletPad);
- if (useFunclets)
- if ((CPI = dyn_cast_or_null<llvm::CatchPadInst>(Handler.Block->getFirstNonPHI()))) {
+
+ CodeGenFunction::LexicalScope Cleanups(CGF, Handler.Body->getSourceRange());
+ SaveAndRestore RevertAfterScope(CGF.CurrentFuncletPad);
+ if (useFunclets) {
+ llvm::Instruction *CPICandidate = Handler.Block->getFirstNonPHI();
+ if (auto *CPI = dyn_cast_or_null<llvm::CatchPadInst>(CPICandidate)) {
CGF.CurrentFuncletPad = CPI;
CPI->setOperand(2, CGF.getExceptionSlot().getPointer());
+ CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
}
+ }
+
llvm::Value *RawExn = CGF.getExceptionFromSlot();
// Enter the catch.
@@ -241,8 +247,6 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
if (beginCatchFn)
Exn = CGF.EmitNounwindRuntimeCall(beginCatchFn, RawExn, "exn.adjusted");
- CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange());
-
if (endCatchFn) {
// Add a cleanup to leave the catch.
bool EndCatchMightThrow = (Handler.Variable == nullptr);
@@ -260,15 +264,13 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CGF.EmitAutoVarDecl(*CatchParam);
EmitInitOfCatchParam(CGF, CastExn, CatchParam);
}
- if (CPI)
- CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
CGF.ObjCEHValueStack.push_back(Exn);
CGF.EmitStmt(Handler.Body);
CGF.ObjCEHValueStack.pop_back();
// Leave any cleanups associated with the catch.
- cleanups.ForceCleanup();
+ Cleanups.ForceCleanup();
CGF.EmitBranchThroughCleanup(Cont);
}
@@ -293,7 +295,7 @@ void CGObjCRuntime::EmitInitOfCatchParam(CodeGenFunction &CGF,
switch (paramDecl->getType().getQualifiers().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
exn = CGF.EmitARCRetainNonBlock(exn);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
@@ -360,13 +362,15 @@ CGObjCRuntime::MessageSendInfo
CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
QualType resultType,
CallArgList &callArgs) {
+ unsigned ProgramAS = CGM.getDataLayout().getProgramAddressSpace();
+
// If there's a method, use information from that.
if (method) {
const CGFunctionInfo &signature =
CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty);
llvm::PointerType *signatureType =
- CGM.getTypes().GetFunctionType(signature)->getPointerTo();
+ CGM.getTypes().GetFunctionType(signature)->getPointerTo(ProgramAS);
const CGFunctionInfo &signatureForCall =
CGM.getTypes().arrangeCall(signature, callArgs);
@@ -380,7 +384,7 @@ CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
// Derive the signature to call from that.
llvm::PointerType *signatureType =
- CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo();
+ CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo(ProgramAS);
return MessageSendInfo(argsInfo, signatureType);
}
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 091eb9da5af4..2284aa1d1eb6 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -42,6 +42,7 @@
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <numeric>
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -409,7 +410,7 @@ private:
/// RAII for emitting code of OpenMP constructs.
class InlinedOpenMPRegionRAII {
CodeGenFunction &CGF;
- llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
FieldDecl *LambdaThisCaptureField = nullptr;
const CodeGen::CGBlockInfo *BlockInfo = nullptr;
bool NoInheritance = false;
@@ -1057,14 +1058,16 @@ static FieldDecl *addFieldToRecordDecl(ASTContext &C, DeclContext *DC,
return Field;
}
-CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator,
- StringRef Separator)
- : CGM(CGM), FirstSeparator(FirstSeparator), Separator(Separator),
- OMPBuilder(CGM.getModule()), OffloadEntriesInfoManager(CGM) {
+CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
+ : CGM(CGM), OMPBuilder(CGM.getModule()), OffloadEntriesInfoManager() {
KmpCriticalNameTy = llvm::ArrayType::get(CGM.Int32Ty, /*NumElements*/ 8);
-
+ llvm::OpenMPIRBuilderConfig Config(CGM.getLangOpts().OpenMPIsDevice, false,
+ hasRequiresUnifiedSharedMemory(),
+ CGM.getLangOpts().OpenMPOffloadMandatory);
// Initialize Types used in OpenMPIRBuilder from OMPKinds.def
OMPBuilder.initialize();
+ OMPBuilder.setConfig(Config);
+ OffloadEntriesInfoManager.setConfig(Config);
loadOffloadInfoMetadata();
}
@@ -1084,14 +1087,7 @@ void CGOpenMPRuntime::clear() {
}
std::string CGOpenMPRuntime::getName(ArrayRef<StringRef> Parts) const {
- SmallString<128> Buffer;
- llvm::raw_svector_ostream OS(Buffer);
- StringRef Sep = FirstSeparator;
- for (StringRef Part : Parts) {
- OS << Sep << Part;
- Sep = Separator;
- }
- return std::string(OS.str());
+ return OMPBuilder.createPlatformSpecificName(Parts);
}
static llvm::Function *
@@ -1369,10 +1365,11 @@ static StringRef getIdentStringFromSourceLocation(CodeGenFunction &CGF,
llvm::Value *CGOpenMPRuntime::emitUpdateLocation(CodeGenFunction &CGF,
SourceLocation Loc,
- unsigned Flags) {
+ unsigned Flags, bool EmitLoc) {
uint32_t SrcLocStrSize;
llvm::Constant *SrcLocStr;
- if (CGM.getCodeGenOpts().getDebugInfo() == codegenoptions::NoDebugInfo ||
+ if ((!EmitLoc &&
+ CGM.getCodeGenOpts().getDebugInfo() == codegenoptions::NoDebugInfo) ||
Loc.isInvalid()) {
SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(SrcLocStrSize);
} else {
@@ -1595,9 +1592,9 @@ CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize, bool IVSigned) {
/// 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) {
+static llvm::TargetRegionEntryInfo
+getTargetEntryUniqueInfo(ASTContext &C, SourceLocation Loc,
+ StringRef ParentName = "") {
SourceManager &SM = C.getSourceManager();
// The loc should be always valid and have a file ID (the user cannot use
@@ -1617,29 +1614,27 @@ static void getTargetEntryUniqueInfo(ASTContext &C, SourceLocation Loc,
<< PLoc.getFilename() << EC.message();
}
- DeviceID = ID.getDevice();
- FileID = ID.getFile();
- LineNum = PLoc.getLine();
+ return llvm::TargetRegionEntryInfo(ParentName, ID.getDevice(), ID.getFile(),
+ PLoc.getLine());
}
Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) {
if (CGM.getLangOpts().OpenMPSimd)
return Address::invalid();
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (Res && (*Res == OMPDeclareTargetDeclAttr::MT_Link ||
- (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
HasRequiresUnifiedSharedMemory))) {
SmallString<64> PtrName;
{
llvm::raw_svector_ostream OS(PtrName);
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);
+ auto EntryInfo = getTargetEntryUniqueInfo(
+ CGM.getContext(), VD->getCanonicalDecl()->getBeginLoc());
+ OS << llvm::format("_%x", EntryInfo.FileID);
}
OS << "_decl_tgt_ref_ptr";
}
@@ -1647,7 +1642,7 @@ Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) {
QualType PtrTy = CGM.getContext().getPointerType(VD->getType());
llvm::Type *LlvmPtrTy = CGM.getTypes().ConvertTypeForMem(PtrTy);
if (!Ptr) {
- Ptr = getOrCreateInternalVariable(LlvmPtrTy, PtrName);
+ Ptr = OMPBuilder.getOrCreateInternalVariable(LlvmPtrTy, PtrName);
auto *GV = cast<llvm::GlobalVariable>(Ptr);
GV->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
@@ -1667,8 +1662,8 @@ CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD) {
!CGM.getContext().getTargetInfo().isTLSSupported());
// Lookup the entry, lazily creating it if necessary.
std::string Suffix = getName({"cache", ""});
- return getOrCreateInternalVariable(
- CGM.Int8PtrPtrTy, Twine(CGM.getMangledName(VD)).concat(Suffix));
+ return OMPBuilder.getOrCreateInternalVariable(
+ CGM.Int8PtrPtrTy, Twine(CGM.getMangledName(VD)).concat(Suffix).str());
}
Address CGOpenMPRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF,
@@ -1840,10 +1835,11 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
if (CGM.getLangOpts().OMPTargetTriples.empty() &&
!CGM.getLangOpts().OpenMPIsDevice)
return false;
- Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link ||
- (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
HasRequiresUnifiedSharedMemory))
return CGM.getLangOpts().OpenMPIsDevice;
VD = VD->getDefinition(CGM.getContext());
@@ -1858,16 +1854,10 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
// Produce the unique prefix to identify the new target regions. We use
// the source location of the variable declaration which we know to not
// conflict with any target region.
- unsigned DeviceID;
- unsigned FileID;
- unsigned Line;
- getTargetEntryUniqueInfo(CGM.getContext(), Loc, DeviceID, FileID, Line);
+ auto EntryInfo =
+ getTargetEntryUniqueInfo(CGM.getContext(), Loc, VD->getName());
SmallString<128> Buffer, Out;
- {
- llvm::raw_svector_ostream OS(Buffer);
- OS << "__omp_offloading_" << llvm::format("_%x", DeviceID)
- << llvm::format("_%x_", FileID) << VD->getName() << "_l" << Line;
- }
+ OffloadEntriesInfoManager.getTargetRegionEntryFnName(Buffer, EntryInfo);
const Expr *Init = VD->getAnyInitializer();
if (CGM.getLangOpts().CPlusPlus && PerformInit) {
@@ -1883,6 +1873,7 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
llvm::Function *Fn = CGM.CreateGlobalInitOrCleanUpFunction(
FTy, Twine(Buffer, "_ctor"), FI, Loc, false,
llvm::GlobalValue::WeakODRLinkage);
+ Fn->setVisibility(llvm::GlobalValue::ProtectedVisibility);
if (CGM.getTriple().isAMDGCN())
Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
auto NL = ApplyDebugLocation::CreateEmpty(CtorCGF);
@@ -1912,9 +1903,11 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
// Register the information for the entry associated with the constructor.
Out.clear();
+ auto CtorEntryInfo = EntryInfo;
+ CtorEntryInfo.ParentName = Twine(Buffer, "_ctor").toStringRef(Out);
OffloadEntriesInfoManager.registerTargetRegionEntryInfo(
- DeviceID, FileID, Twine(Buffer, "_ctor").toStringRef(Out), Line, Ctor,
- ID, OffloadEntriesInfoManagerTy::OMPTargetRegionEntryCtor);
+ CtorEntryInfo, Ctor, ID,
+ llvm::OffloadEntriesInfoManager::OMPTargetRegionEntryCtor);
}
if (VD->getType().isDestructedType() != QualType::DK_none) {
llvm::Constant *Dtor;
@@ -1929,6 +1922,7 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
llvm::Function *Fn = CGM.CreateGlobalInitOrCleanUpFunction(
FTy, Twine(Buffer, "_dtor"), FI, Loc, false,
llvm::GlobalValue::WeakODRLinkage);
+ Fn->setVisibility(llvm::GlobalValue::ProtectedVisibility);
if (CGM.getTriple().isAMDGCN())
Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
auto NL = ApplyDebugLocation::CreateEmpty(DtorCGF);
@@ -1958,9 +1952,11 @@ bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
}
// Register the information for the entry associated with the destructor.
Out.clear();
+ auto DtorEntryInfo = EntryInfo;
+ DtorEntryInfo.ParentName = Twine(Buffer, "_dtor").toStringRef(Out);
OffloadEntriesInfoManager.registerTargetRegionEntryInfo(
- DeviceID, FileID, Twine(Buffer, "_dtor").toStringRef(Out), Line, Dtor,
- ID, OffloadEntriesInfoManagerTy::OMPTargetRegionEntryDtor);
+ DtorEntryInfo, Dtor, ID,
+ llvm::OffloadEntriesInfoManager::OMPTargetRegionEntryDtor);
}
return CGM.getLangOpts().OpenMPIsDevice;
}
@@ -1970,8 +1966,8 @@ Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
StringRef Name) {
std::string Suffix = getName({"artificial", ""});
llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType);
- llvm::GlobalVariable *GAddr =
- getOrCreateInternalVariable(VarLVType, Twine(Name).concat(Suffix));
+ llvm::GlobalVariable *GAddr = OMPBuilder.getOrCreateInternalVariable(
+ VarLVType, Twine(Name).concat(Suffix).str());
if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPUseTLS &&
CGM.getTarget().isTLSSupported()) {
GAddr->setThreadLocal(/*Val=*/true);
@@ -1985,8 +1981,9 @@ Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(GAddr, CGM.VoidPtrTy),
CGF.Builder.CreateIntCast(CGF.getTypeSize(VarType), CGM.SizeTy,
/*isSigned=*/false),
- getOrCreateInternalVariable(
- CGM.VoidPtrPtrTy, Twine(Name).concat(Suffix).concat(CacheSuffix))};
+ OMPBuilder.getOrCreateInternalVariable(
+ CGM.VoidPtrPtrTy,
+ Twine(Name).concat(Suffix).concat(CacheSuffix).str())};
return Address(
CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
CGF.EmitRuntimeCall(
@@ -2131,30 +2128,10 @@ Address CGOpenMPRuntime::emitThreadIDAddress(CodeGenFunction &CGF,
return ThreadIDTemp;
}
-llvm::GlobalVariable *CGOpenMPRuntime::getOrCreateInternalVariable(
- llvm::Type *Ty, const llvm::Twine &Name, unsigned AddressSpace) {
- SmallString<256> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- Out << Name;
- StringRef RuntimeName = Out.str();
- auto &Elem = *InternalVars.try_emplace(RuntimeName, nullptr).first;
- if (Elem.second) {
- assert(Elem.second->getType()->isOpaqueOrPointeeTypeMatches(Ty) &&
- "OMP internal variable has different type than requested");
- return &*Elem.second;
- }
-
- return Elem.second = new llvm::GlobalVariable(
- CGM.getModule(), Ty, /*IsConstant*/ false,
- llvm::GlobalValue::CommonLinkage, llvm::Constant::getNullValue(Ty),
- Elem.first(), /*InsertBefore=*/nullptr,
- llvm::GlobalValue::NotThreadLocal, AddressSpace);
-}
-
llvm::Value *CGOpenMPRuntime::getCriticalRegionLock(StringRef CriticalName) {
std::string Prefix = Twine("gomp_critical_user_", CriticalName).str();
std::string Name = getName({Prefix, "var"});
- return getOrCreateInternalVariable(KmpCriticalNameTy, Name);
+ return OMPBuilder.getOrCreateInternalVariable(KmpCriticalNameTy, Name);
}
namespace {
@@ -2583,6 +2560,22 @@ void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
Args);
}
+void CGOpenMPRuntime::emitErrorCall(CodeGenFunction &CGF, SourceLocation Loc,
+ Expr *ME, bool IsFatal) {
+ llvm::Value *MVL =
+ ME ? CGF.EmitStringLiteralLValue(cast<StringLiteral>(ME)).getPointer(CGF)
+ : llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
+ // Build call void __kmpc_error(ident_t *loc, int severity, const char
+ // *message)
+ llvm::Value *Args[] = {
+ emitUpdateLocation(CGF, Loc, /*Flags=*/0, /*GenLoc=*/true),
+ llvm::ConstantInt::get(CGM.Int32Ty, IsFatal ? 2 : 1),
+ CGF.Builder.CreatePointerCast(MVL, CGM.Int8PtrTy)};
+ CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
+ CGM.getModule(), OMPRTL___kmpc_error),
+ Args);
+}
+
/// Map the OpenMP loop schedule to the runtime enumeration.
static OpenMPSchedType getRuntimeSchedule(OpenMPScheduleClauseKind ScheduleKind,
bool Chunked, bool Ordered) {
@@ -2951,328 +2944,55 @@ enum KmpTaskTFields {
};
} // anonymous namespace
-bool CGOpenMPRuntime::OffloadEntriesInfoManagerTy::empty() const {
- return OffloadEntriesTargetRegion.empty() &&
- OffloadEntriesDeviceGlobalVar.empty();
-}
-
-/// Initialize target region entry.
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- initializeTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- unsigned Order) {
- assert(CGM.getLangOpts().OpenMPIsDevice && "Initialization of entries is "
- "only required for the device "
- "code generation.");
- OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum] =
- OffloadEntryInfoTargetRegion(Order, /*Addr=*/nullptr, /*ID=*/nullptr,
- OMPTargetRegionEntryTargetRegion);
- ++OffloadingEntriesNum;
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- registerTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- llvm::Constant *Addr, llvm::Constant *ID,
- OMPTargetRegionEntryKind Flags) {
- // If we are emitting code for a target, the entry is already initialized,
- // only has to be registered.
- if (CGM.getLangOpts().OpenMPIsDevice) {
- // This could happen if the device compilation is invoked standalone.
- if (!hasTargetRegionEntryInfo(DeviceID, FileID, ParentName, LineNum))
- return;
- auto &Entry =
- OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum];
- Entry.setAddress(Addr);
- Entry.setID(ID);
- Entry.setFlags(Flags);
- } else {
- if (Flags ==
- OffloadEntriesInfoManagerTy::OMPTargetRegionEntryTargetRegion &&
- hasTargetRegionEntryInfo(DeviceID, FileID, ParentName, LineNum,
- /*IgnoreAddressId*/ true))
- return;
- assert(!hasTargetRegionEntryInfo(DeviceID, FileID, ParentName, LineNum) &&
- "Target region entry already registered!");
- OffloadEntryInfoTargetRegion Entry(OffloadingEntriesNum, Addr, ID, Flags);
- OffloadEntriesTargetRegion[DeviceID][FileID][ParentName][LineNum] = Entry;
- ++OffloadingEntriesNum;
- }
-}
-
-bool CGOpenMPRuntime::OffloadEntriesInfoManagerTy::hasTargetRegionEntryInfo(
- unsigned DeviceID, unsigned FileID, StringRef ParentName, unsigned LineNum,
- bool IgnoreAddressId) const {
- auto PerDevice = OffloadEntriesTargetRegion.find(DeviceID);
- if (PerDevice == OffloadEntriesTargetRegion.end())
- return false;
- auto PerFile = PerDevice->second.find(FileID);
- if (PerFile == PerDevice->second.end())
- return false;
- auto PerParentName = PerFile->second.find(ParentName);
- if (PerParentName == PerFile->second.end())
- return false;
- auto PerLine = PerParentName->second.find(LineNum);
- if (PerLine == PerParentName->second.end())
- return false;
- // Fail if this entry is already registered.
- if (!IgnoreAddressId &&
- (PerLine->second.getAddress() || PerLine->second.getID()))
- return false;
- return true;
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::actOnTargetRegionEntriesInfo(
- const OffloadTargetRegionEntryInfoActTy &Action) {
- // Scan all target region entries and perform the provided action.
- for (const auto &D : OffloadEntriesTargetRegion)
- for (const auto &F : D.second)
- for (const auto &P : F.second)
- for (const auto &L : P.second)
- Action(D.first, F.first, P.first(), L.first, L.second);
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- initializeDeviceGlobalVarEntryInfo(StringRef Name,
- OMPTargetGlobalVarEntryKind Flags,
- unsigned Order) {
- assert(CGM.getLangOpts().OpenMPIsDevice && "Initialization of entries is "
- "only required for the device "
- "code generation.");
- OffloadEntriesDeviceGlobalVar.try_emplace(Name, Order, Flags);
- ++OffloadingEntriesNum;
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- registerDeviceGlobalVarEntryInfo(StringRef VarName, llvm::Constant *Addr,
- CharUnits VarSize,
- OMPTargetGlobalVarEntryKind Flags,
- llvm::GlobalValue::LinkageTypes Linkage) {
- if (CGM.getLangOpts().OpenMPIsDevice) {
- // This could happen if the device compilation is invoked standalone.
- if (!hasDeviceGlobalVarEntryInfo(VarName))
- return;
- auto &Entry = OffloadEntriesDeviceGlobalVar[VarName];
- if (Entry.getAddress() && hasDeviceGlobalVarEntryInfo(VarName)) {
- if (Entry.getVarSize().isZero()) {
- Entry.setVarSize(VarSize);
- Entry.setLinkage(Linkage);
- }
- return;
- }
- Entry.setVarSize(VarSize);
- Entry.setLinkage(Linkage);
- Entry.setAddress(Addr);
- } else {
- if (hasDeviceGlobalVarEntryInfo(VarName)) {
- auto &Entry = OffloadEntriesDeviceGlobalVar[VarName];
- assert(Entry.isValid() && Entry.getFlags() == Flags &&
- "Entry not initialized!");
- if (Entry.getVarSize().isZero()) {
- Entry.setVarSize(VarSize);
- Entry.setLinkage(Linkage);
- }
- return;
- }
- OffloadEntriesDeviceGlobalVar.try_emplace(
- VarName, OffloadingEntriesNum, Addr, VarSize, Flags, Linkage);
- ++OffloadingEntriesNum;
- }
-}
-
-void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
- actOnDeviceGlobalVarEntriesInfo(
- const OffloadDeviceGlobalVarEntryInfoActTy &Action) {
- // Scan all target region entries and perform the provided action.
- for (const auto &E : OffloadEntriesDeviceGlobalVar)
- Action(E.getKey(), E.getValue());
-}
-
-void CGOpenMPRuntime::createOffloadEntry(
- llvm::Constant *ID, llvm::Constant *Addr, uint64_t Size, int32_t Flags,
- llvm::GlobalValue::LinkageTypes Linkage) {
- OMPBuilder.emitOffloadingEntry(ID, Addr->getName(), Size, Flags);
-}
-
void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
- // Emit the offloading entries and metadata so that the device codegen side
- // can easily figure out what to emit. The produced metadata looks like
- // this:
- //
- // !omp_offload.info = !{!1, ...}
- //
- // Right now we only generate metadata for function that contain target
- // regions.
-
// 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<std::tuple<const OffloadEntriesInfoManagerTy::OffloadEntryInfo *,
- SourceLocation, StringRef>,
- 16>
- OrderedEntries(OffloadEntriesInfoManager.size());
- llvm::SmallVector<StringRef, 16> ParentFunctions(
- OffloadEntriesInfoManager.size());
-
- // Auxiliary methods to create metadata values and strings.
- auto &&GetMDInt = [this](unsigned V) {
- return llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(CGM.Int32Ty, V));
- };
-
- auto &&GetMDString = [&C](StringRef V) { return llvm::MDString::get(C, V); };
-
- // Create the offloading info metadata node.
- llvm::NamedMDNode *MD = M.getOrInsertNamedMetadata("omp_offload.info");
-
- // Create function that emits metadata for each target region entry;
- auto &&TargetRegionMetadataEmitter =
- [this, &C, MD, &OrderedEntries, &ParentFunctions, &GetMDInt,
- &GetMDString](
- unsigned DeviceID, unsigned FileID, StringRef ParentName,
- unsigned Line,
- const OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion &E) {
- // Generate metadata for target regions. Each entry of this metadata
- // contains:
- // - Entry 0 -> Kind of this type of metadata (0).
- // - Entry 1 -> Device ID of the file where the entry was identified.
- // - Entry 2 -> File ID of the file where the entry was identified.
- // - Entry 3 -> Mangled name of the function where the entry was
- // identified.
- // - Entry 4 -> Line in the file where the entry was identified.
- // - Entry 5 -> Order the entry was created.
- // The first element of the metadata node is the kind.
- llvm::Metadata *Ops[] = {GetMDInt(E.getKind()), GetMDInt(DeviceID),
- 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()] = std::make_tuple(&E, Loc, ParentName);
- ParentFunctions[E.getOrder()] = ParentName;
-
- // Add metadata to the named metadata node.
- MD->addOperand(llvm::MDNode::get(C, Ops));
- };
-
- OffloadEntriesInfoManager.actOnTargetRegionEntriesInfo(
- TargetRegionMetadataEmitter);
-
- // Create function that emits metadata for each device global variable entry;
- auto &&DeviceGlobalVarMetadataEmitter =
- [&C, &OrderedEntries, &GetMDInt, &GetMDString,
- MD](StringRef MangledName,
- const OffloadEntriesInfoManagerTy::OffloadEntryInfoDeviceGlobalVar
- &E) {
- // Generate metadata for global variables. Each entry of this metadata
- // contains:
- // - Entry 0 -> Kind of this type of metadata (1).
- // - Entry 1 -> Mangled name of the variable.
- // - Entry 2 -> Declare target kind.
- // - Entry 3 -> Order the entry was created.
- // The first element of the metadata node is the kind.
- llvm::Metadata *Ops[] = {
- GetMDInt(E.getKind()), GetMDString(MangledName),
- GetMDInt(E.getFlags()), GetMDInt(E.getOrder())};
-
- // Save this entry in the right position of the ordered entries array.
- OrderedEntries[E.getOrder()] =
- std::make_tuple(&E, SourceLocation(), MangledName);
-
- // Add metadata to the named metadata node.
- MD->addOperand(llvm::MDNode::get(C, Ops));
- };
-
- OffloadEntriesInfoManager.actOnDeviceGlobalVarEntriesInfo(
- DeviceGlobalVarMetadataEmitter);
-
- for (const auto &E : OrderedEntries) {
- assert(std::get<0>(E) && "All ordered entries must exist!");
- if (const auto *CE =
- dyn_cast<OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion>(
- 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()];
- if (!CGM.GetGlobalValue(FnName))
- continue;
- unsigned DiagID = CGM.getDiags().getCustomDiagID(
- DiagnosticsEngine::Error,
- "Offloading entry for target region in %0 is incorrect: either the "
- "address or the ID is invalid.");
- 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>(
- std::get<0>(E))) {
- OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind Flags =
- static_cast<OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind>(
- CE->getFlags());
- switch (Flags) {
- case OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryTo: {
- if (CGM.getLangOpts().OpenMPIsDevice &&
- CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory())
- continue;
- if (!CE->getAddress()) {
- unsigned DiagID = CGM.getDiags().getCustomDiagID(
- 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.
- if (CE->getVarSize().isZero())
- continue;
- break;
- }
- case OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryLink:
- assert(((CGM.getLangOpts().OpenMPIsDevice && !CE->getAddress()) ||
- (!CGM.getLangOpts().OpenMPIsDevice && CE->getAddress())) &&
- "Declaret target link address is set.");
- if (CGM.getLangOpts().OpenMPIsDevice)
- 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);
- continue;
+ llvm::OpenMPIRBuilder::EmitMetadataErrorReportFunctionTy &&ErrorReportFn =
+ [this](llvm::OpenMPIRBuilder::EmitMetadataErrorKind Kind,
+ const llvm::TargetRegionEntryInfo &EntryInfo) -> void {
+ SourceLocation Loc;
+ if (Kind != llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_LINK_ERROR) {
+ for (auto I = CGM.getContext().getSourceManager().fileinfo_begin(),
+ E = CGM.getContext().getSourceManager().fileinfo_end();
+ I != E; ++I) {
+ if (I->getFirst()->getUniqueID().getDevice() == EntryInfo.DeviceID &&
+ I->getFirst()->getUniqueID().getFile() == EntryInfo.FileID) {
+ Loc = CGM.getContext().getSourceManager().translateFileLineCol(
+ I->getFirst(), EntryInfo.Line, 1);
+ break;
}
- break;
}
-
- // Hidden or internal symbols on the device are not externally visible. We
- // should not attempt to register them by creating an offloading entry.
- if (auto *GV = dyn_cast<llvm::GlobalValue>(CE->getAddress()))
- if (GV->hasLocalLinkage() || GV->hasHiddenVisibility())
- continue;
-
- createOffloadEntry(CE->getAddress(), CE->getAddress(),
- CE->getVarSize().getQuantity(), Flags,
- CE->getLinkage());
- } else {
- llvm_unreachable("Unsupported entry kind.");
}
- }
+ switch (Kind) {
+ case llvm::OpenMPIRBuilder::EMIT_MD_TARGET_REGION_ERROR: {
+ unsigned DiagID = CGM.getDiags().getCustomDiagID(
+ DiagnosticsEngine::Error, "Offloading entry for target region in "
+ "%0 is incorrect: either the "
+ "address or the ID is invalid.");
+ CGM.getDiags().Report(Loc, DiagID) << EntryInfo.ParentName;
+ } break;
+ case llvm::OpenMPIRBuilder::EMIT_MD_DECLARE_TARGET_ERROR: {
+ unsigned DiagID = CGM.getDiags().getCustomDiagID(
+ DiagnosticsEngine::Error, "Offloading entry for declare target "
+ "variable %0 is incorrect: the "
+ "address is invalid.");
+ CGM.getDiags().Report(Loc, DiagID) << EntryInfo.ParentName;
+ } break;
+ case llvm::OpenMPIRBuilder::EMIT_MD_GLOBAL_VAR_LINK_ERROR: {
+ unsigned DiagID = CGM.getDiags().getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "Offloading entry for declare target variable is incorrect: the "
+ "address is invalid.");
+ CGM.getDiags().Report(DiagID);
+ } break;
+ }
+ };
+
+ OMPBuilder.createOffloadEntriesAndInfoMetadata(OffloadEntriesInfoManager,
+ ErrorReportFn);
}
/// Loads all the offload entries information from the host IR
@@ -3306,42 +3026,7 @@ void CGOpenMPRuntime::loadOffloadInfoMetadata() {
return;
}
- llvm::NamedMDNode *MD = ME.get()->getNamedMetadata("omp_offload.info");
- if (!MD)
- return;
-
- for (llvm::MDNode *MN : MD->operands()) {
- auto &&GetMDInt = [MN](unsigned Idx) {
- auto *V = cast<llvm::ConstantAsMetadata>(MN->getOperand(Idx));
- return cast<llvm::ConstantInt>(V->getValue())->getZExtValue();
- };
-
- auto &&GetMDString = [MN](unsigned Idx) {
- auto *V = cast<llvm::MDString>(MN->getOperand(Idx));
- return V->getString();
- };
-
- switch (GetMDInt(0)) {
- default:
- llvm_unreachable("Unexpected metadata!");
- break;
- case OffloadEntriesInfoManagerTy::OffloadEntryInfo::
- OffloadingEntryInfoTargetRegion:
- OffloadEntriesInfoManager.initializeTargetRegionEntryInfo(
- /*DeviceID=*/GetMDInt(1), /*FileID=*/GetMDInt(2),
- /*ParentName=*/GetMDString(3), /*Line=*/GetMDInt(4),
- /*Order=*/GetMDInt(5));
- break;
- case OffloadEntriesInfoManagerTy::OffloadEntryInfo::
- OffloadingEntryInfoDeviceGlobalVar:
- OffloadEntriesInfoManager.initializeDeviceGlobalVarEntryInfo(
- /*MangledName=*/GetMDString(1),
- static_cast<OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind>(
- /*Flags=*/GetMDInt(2)),
- /*Order=*/GetMDInt(3));
- break;
- }
- }
+ OMPBuilder.loadOffloadInfoMetadata(*ME.get(), OffloadEntriesInfoManager);
}
void CGOpenMPRuntime::emitKmpRoutineEntryT(QualType KmpInt32Ty) {
@@ -4501,39 +4186,26 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc,
return Result;
}
-namespace {
-/// Dependence kind for RTL.
-enum RTLDependenceKindTy {
- DepIn = 0x01,
- DepInOut = 0x3,
- DepMutexInOutSet = 0x4,
- DepInOutSet = 0x8,
- DepOmpAllMem = 0x80,
-};
-/// Fields ids in kmp_depend_info record.
-enum RTLDependInfoFieldsTy { BaseAddr, Len, Flags };
-} // namespace
-
/// Translates internal dependency kind into the runtime kind.
static RTLDependenceKindTy translateDependencyKind(OpenMPDependClauseKind K) {
RTLDependenceKindTy DepKind;
switch (K) {
case OMPC_DEPEND_in:
- DepKind = DepIn;
+ DepKind = RTLDependenceKindTy::DepIn;
break;
// Out and InOut dependencies must use the same code.
case OMPC_DEPEND_out:
case OMPC_DEPEND_inout:
- DepKind = DepInOut;
+ DepKind = RTLDependenceKindTy::DepInOut;
break;
case OMPC_DEPEND_mutexinoutset:
- DepKind = DepMutexInOutSet;
+ DepKind = RTLDependenceKindTy::DepMutexInOutSet;
break;
case OMPC_DEPEND_inoutset:
- DepKind = DepInOutSet;
+ DepKind = RTLDependenceKindTy::DepInOutSet;
break;
case OMPC_DEPEND_outallmemory:
- DepKind = DepOmpAllMem;
+ DepKind = RTLDependenceKindTy::DepOmpAllMem;
break;
case OMPC_DEPEND_source:
case OMPC_DEPEND_sink:
@@ -4581,7 +4253,9 @@ CGOpenMPRuntime::getDepobjElements(CodeGenFunction &CGF, LValue DepobjLVal,
DepObjAddr, KmpDependInfoTy, Base.getBaseInfo(), Base.getTBAAInfo());
// NumDeps = deps[i].base_addr;
LValue BaseAddrLVal = CGF.EmitLValueForField(
- NumDepsBase, *std::next(KmpDependInfoRD->field_begin(), BaseAddr));
+ NumDepsBase,
+ *std::next(KmpDependInfoRD->field_begin(),
+ static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
llvm::Value *NumDeps = CGF.EmitLoadOfScalar(BaseAddrLVal, Loc);
return std::make_pair(NumDeps, Base);
}
@@ -4627,18 +4301,24 @@ static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy,
}
// deps[i].base_addr = &<Dependencies[i].second>;
LValue BaseAddrLVal = CGF.EmitLValueForField(
- Base, *std::next(KmpDependInfoRD->field_begin(), BaseAddr));
+ Base,
+ *std::next(KmpDependInfoRD->field_begin(),
+ static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
CGF.EmitStoreOfScalar(Addr, BaseAddrLVal);
// deps[i].len = sizeof(<Dependencies[i].second>);
LValue LenLVal = CGF.EmitLValueForField(
- Base, *std::next(KmpDependInfoRD->field_begin(), Len));
+ Base, *std::next(KmpDependInfoRD->field_begin(),
+ static_cast<unsigned int>(RTLDependInfoFields::Len)));
CGF.EmitStoreOfScalar(Size, LenLVal);
// deps[i].flags = <Dependencies[i].first>;
RTLDependenceKindTy DepKind = translateDependencyKind(Data.DepKind);
LValue FlagsLVal = CGF.EmitLValueForField(
- Base, *std::next(KmpDependInfoRD->field_begin(), Flags));
- CGF.EmitStoreOfScalar(llvm::ConstantInt::get(LLVMFlagsTy, DepKind),
- FlagsLVal);
+ Base,
+ *std::next(KmpDependInfoRD->field_begin(),
+ static_cast<unsigned int>(RTLDependInfoFields::Flags)));
+ CGF.EmitStoreOfScalar(
+ llvm::ConstantInt::get(LLVMFlagsTy, static_cast<unsigned int>(DepKind)),
+ FlagsLVal);
if (unsigned *P = Pos.dyn_cast<unsigned *>()) {
++(*P);
} else {
@@ -4655,7 +4335,7 @@ SmallVector<llvm::Value *, 4> CGOpenMPRuntime::emitDepobjElementsSizes(
CodeGenFunction &CGF, QualType &KmpDependInfoTy,
const OMPTaskDataTy::DependData &Data) {
assert(Data.DepKind == OMPC_DEPEND_depobj &&
- "Expected depobj dependecy kind.");
+ "Expected depobj dependency kind.");
SmallVector<llvm::Value *, 4> Sizes;
SmallVector<LValue, 4> SizeLVals;
ASTContext &C = CGF.getContext();
@@ -4695,7 +4375,7 @@ void CGOpenMPRuntime::emitDepobjElements(CodeGenFunction &CGF,
const OMPTaskDataTy::DependData &Data,
Address DependenciesArray) {
assert(Data.DepKind == OMPC_DEPEND_depobj &&
- "Expected depobj dependecy kind.");
+ "Expected depobj dependency kind.");
llvm::Value *ElSize = CGF.getTypeSize(KmpDependInfoTy);
{
OMPIteratorGeneratorScope IteratorScope(
@@ -4751,7 +4431,8 @@ std::pair<llvm::Value *, Address> CGOpenMPRuntime::emitDependClause(
llvm::Value *NumOfDepobjElements = llvm::ConstantInt::get(CGF.IntPtrTy, 0);
llvm::Value *NumOfRegularWithIterators =
llvm::ConstantInt::get(CGF.IntPtrTy, 0);
- // Calculate number of depobj dependecies and regular deps with the iterators.
+ // Calculate number of depobj dependencies and regular deps with the
+ // iterators.
for (const OMPTaskDataTy::DependData &D : Dependencies) {
if (D.DepKind == OMPC_DEPEND_depobj) {
SmallVector<llvm::Value *, 4> Sizes =
@@ -4825,7 +4506,7 @@ std::pair<llvm::Value *, Address> CGOpenMPRuntime::emitDependClause(
emitDependData(CGF, KmpDependInfoTy, &Pos, Dependencies[I],
DependenciesArray);
}
- // Copy regular dependecies with iterators.
+ // Copy regular dependencies with iterators.
LValue PosLVal = CGF.MakeAddrLValue(
CGF.CreateMemTemp(C.getSizeType(), "dep.counter.addr"), C.getSizeType());
CGF.EmitStoreOfScalar(llvm::ConstantInt::get(CGF.SizeTy, Pos), PosLVal);
@@ -4913,7 +4594,9 @@ Address CGOpenMPRuntime::emitDepobjDependClause(
LValue Base = CGF.MakeAddrLValue(DependenciesArray, KmpDependInfoTy);
// deps[i].base_addr = NumDependencies;
LValue BaseAddrLVal = CGF.EmitLValueForField(
- Base, *std::next(KmpDependInfoRD->field_begin(), BaseAddr));
+ Base,
+ *std::next(KmpDependInfoRD->field_begin(),
+ static_cast<unsigned int>(RTLDependInfoFields::BaseAddr)));
CGF.EmitStoreOfScalar(NumDepsVal, BaseAddrLVal);
llvm::PointerUnion<unsigned *, LValue *> Pos;
unsigned Idx = 1;
@@ -4993,9 +4676,11 @@ void CGOpenMPRuntime::emitUpdateClause(CodeGenFunction &CGF, LValue DepobjLVal,
// deps[i].flags = NewDepKind;
RTLDependenceKindTy DepKind = translateDependencyKind(NewDepKind);
LValue FlagsLVal = CGF.EmitLValueForField(
- Base, *std::next(KmpDependInfoRD->field_begin(), Flags));
- CGF.EmitStoreOfScalar(llvm::ConstantInt::get(LLVMFlagsTy, DepKind),
- FlagsLVal);
+ Base, *std::next(KmpDependInfoRD->field_begin(),
+ static_cast<unsigned int>(RTLDependInfoFields::Flags)));
+ CGF.EmitStoreOfScalar(
+ llvm::ConstantInt::get(LLVMFlagsTy, static_cast<unsigned int>(DepKind)),
+ FlagsLVal);
// Shift the address forward by one element.
Address ElementNext =
@@ -5073,7 +4758,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
Region->emitUntiedSwitch(CGF);
};
- llvm::Value *DepWaitTaskArgs[6];
+ llvm::Value *DepWaitTaskArgs[7];
if (!Data.Dependences.empty()) {
DepWaitTaskArgs[0] = UpLoc;
DepWaitTaskArgs[1] = ThreadID;
@@ -5081,6 +4766,8 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
DepWaitTaskArgs[3] = DependenciesArray.getPointer();
DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
+ DepWaitTaskArgs[6] =
+ llvm::ConstantInt::get(CGF.Int32Ty, Data.HasNowaitClause);
}
auto &M = CGM.getModule();
auto &&ElseCodeGen = [this, &M, &TaskArgs, ThreadID, NewTaskNewTaskTTy,
@@ -5092,9 +4779,9 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
// ndeps_noalias, kmp_depend_info_t *noalias_dep_list); if dependence info
// is specified.
if (!Data.Dependences.empty())
- CGF.EmitRuntimeCall(
- OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_omp_wait_deps),
- DepWaitTaskArgs);
+ CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
+ M, OMPRTL___kmpc_omp_taskwait_deps_51),
+ DepWaitTaskArgs);
// Call proxy_task_entry(gtid, new_task);
auto &&CodeGen = [TaskEntry, ThreadID, NewTaskNewTaskTTy,
Loc](CodeGenFunction &CGF, PrePostActionTy &Action) {
@@ -5595,7 +5282,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
};
RegionCodeGenTy RCG(CodeGen);
CommonActionTy Action(
- nullptr, llvm::None,
+ nullptr, std::nullopt,
OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), WithNowait ? OMPRTL___kmpc_end_reduce_nowait
: OMPRTL___kmpc_end_reduce),
@@ -5717,7 +5404,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
ThreadId, // i32 <gtid>
Lock // kmp_critical_name *&<lock>
};
- CommonActionTy Action(nullptr, llvm::None,
+ CommonActionTy Action(nullptr, std::nullopt,
OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_end_reduce),
EndArgs);
@@ -6142,24 +5829,26 @@ void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc,
llvm::Value *NumOfElements;
std::tie(NumOfElements, DependenciesArray) =
emitDependClause(CGF, Data.Dependences, Loc);
- llvm::Value *DepWaitTaskArgs[6];
if (!Data.Dependences.empty()) {
+ llvm::Value *DepWaitTaskArgs[7];
DepWaitTaskArgs[0] = UpLoc;
DepWaitTaskArgs[1] = ThreadID;
DepWaitTaskArgs[2] = NumOfElements;
DepWaitTaskArgs[3] = DependenciesArray.getPointer();
DepWaitTaskArgs[4] = CGF.Builder.getInt32(0);
DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy);
+ DepWaitTaskArgs[6] =
+ llvm::ConstantInt::get(CGF.Int32Ty, Data.HasNowaitClause);
CodeGenFunction::RunCleanupsScope LocalScope(CGF);
- // Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid,
+ // Build void __kmpc_omp_taskwait_deps_51(ident_t *, kmp_int32 gtid,
// kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32
- // ndeps_noalias, kmp_depend_info_t *noalias_dep_list); if dependence info
- // is specified.
- CGF.EmitRuntimeCall(
- OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_omp_wait_deps),
- DepWaitTaskArgs);
+ // ndeps_noalias, kmp_depend_info_t *noalias_dep_list,
+ // kmp_int32 has_no_wait); if dependence info is specified.
+ CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
+ M, OMPRTL___kmpc_omp_taskwait_deps_51),
+ DepWaitTaskArgs);
} else {
@@ -6333,7 +6022,7 @@ void CGOpenMPRuntime::emitTargetOutlinedFunction(
const OMPExecutableDirective &D, StringRef ParentName,
llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
- assert(!ParentName.empty() && "Invalid target region parent name!");
+ assert(!ParentName.empty() && "Invalid target entry parent name!");
HasEmittedTargetRegion = true;
SmallVector<std::pair<const Expr *, const Expr *>, 4> Allocators;
for (const auto *C : D.getClausesOfKind<OMPUsesAllocatorsClause>()) {
@@ -6405,99 +6094,32 @@ void CGOpenMPRuntime::emitTargetOutlinedFunctionHelper(
const OMPExecutableDirective &D, StringRef ParentName,
llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
bool IsOffloadEntry, const RegionCodeGenTy &CodeGen) {
- // Create a unique name for the entry function using the source location
- // information of the current target region. The name will be something like:
- //
- // __omp_offloading_DD_FFFF_PP_lBB
- //
- // where DD_FFFF is an ID unique to the file (device and file IDs), PP is the
- // mangled name of the function that encloses the target region and BB is the
- // line number of the target region.
-
- const bool BuildOutlinedFn = CGM.getLangOpts().OpenMPIsDevice ||
- !CGM.getLangOpts().OpenMPOffloadMandatory;
- unsigned DeviceID;
- unsigned FileID;
- unsigned Line;
- getTargetEntryUniqueInfo(CGM.getContext(), D.getBeginLoc(), DeviceID, FileID,
- Line);
- SmallString<64> EntryFnName;
- {
- llvm::raw_svector_ostream OS(EntryFnName);
- OS << "__omp_offloading" << llvm::format("_%x", DeviceID)
- << llvm::format("_%x_", FileID) << ParentName << "_l" << Line;
- }
- const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
+ auto EntryInfo =
+ getTargetEntryUniqueInfo(CGM.getContext(), D.getBeginLoc(), ParentName);
CodeGenFunction CGF(CGM, true);
- CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName);
- CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
-
- if (BuildOutlinedFn)
- OutlinedFn = CGF.GenerateOpenMPCapturedStmtFunction(CS, D.getBeginLoc());
-
- // If this target outline function is not an offload entry, we don't need to
- // register it.
- if (!IsOffloadEntry)
- return;
+ llvm::OpenMPIRBuilder::FunctionGenCallback &&GenerateOutlinedFunction =
+ [&CGF, &D, &CodeGen](StringRef EntryFnName) {
+ const CapturedStmt &CS = *D.getCapturedStmt(OMPD_target);
- // The target region ID is used by the runtime library to identify the current
- // target region, so it only has to be unique and not necessarily point to
- // anything. It could be the pointer to the outlined function that implements
- // the target region, but we aren't using that so that the compiler doesn't
- // need to keep that, and could therefore inline the host function if proven
- // worthwhile during optimization. In the other hand, if emitting code for the
- // device, the ID has to be the function address so that it can retrieved from
- // the offloading entry and launched by the runtime library. We also mark the
- // outlined function to have external linkage in case we are emitting code for
- // the device, because these functions will be entry points to the device.
+ CGOpenMPTargetRegionInfo CGInfo(CS, CodeGen, EntryFnName);
+ CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
+ return CGF.GenerateOpenMPCapturedStmtFunction(CS, D.getBeginLoc());
+ };
- if (CGM.getLangOpts().OpenMPIsDevice) {
- OutlinedFnID = llvm::ConstantExpr::getBitCast(OutlinedFn, CGM.Int8PtrTy);
- OutlinedFn->setLinkage(llvm::GlobalValue::WeakODRLinkage);
- OutlinedFn->setDSOLocal(false);
- if (CGM.getTriple().isAMDGCN())
- OutlinedFn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL);
- } else {
- std::string Name = getName({EntryFnName, "region_id"});
- OutlinedFnID = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::WeakAnyLinkage,
- llvm::Constant::getNullValue(CGM.Int8Ty), Name);
- }
-
- // If we do not allow host fallback we still need a named address to use.
- llvm::Constant *TargetRegionEntryAddr = OutlinedFn;
- if (!BuildOutlinedFn) {
- assert(!CGM.getModule().getGlobalVariable(EntryFnName, true) &&
- "Named kernel already exists?");
- TargetRegionEntryAddr = new llvm::GlobalVariable(
- CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::InternalLinkage,
- llvm::Constant::getNullValue(CGM.Int8Ty), EntryFnName);
- }
-
- // Register the information for the entry associated with this target region.
- OffloadEntriesInfoManager.registerTargetRegionEntryInfo(
- DeviceID, FileID, ParentName, Line, TargetRegionEntryAddr, OutlinedFnID,
- OffloadEntriesInfoManagerTy::OMPTargetRegionEntryTargetRegion);
-
- // Add NumTeams and ThreadLimit attributes to the outlined GPU function
+ // Get NumTeams and ThreadLimit attributes
int32_t DefaultValTeams = -1;
- getNumTeamsExprForTargetDirective(CGF, D, DefaultValTeams);
- if (DefaultValTeams > 0 && OutlinedFn) {
- OutlinedFn->addFnAttr("omp_target_num_teams",
- std::to_string(DefaultValTeams));
- }
int32_t DefaultValThreads = -1;
+ getNumTeamsExprForTargetDirective(CGF, D, DefaultValTeams);
getNumThreadsExprForTargetDirective(CGF, D, DefaultValThreads);
- if (DefaultValThreads > 0 && OutlinedFn) {
- OutlinedFn->addFnAttr("omp_target_thread_limit",
- std::to_string(DefaultValThreads));
- }
- if (BuildOutlinedFn)
+ OMPBuilder.emitTargetRegionFunction(OffloadEntriesInfoManager, EntryInfo,
+ GenerateOutlinedFunction, DefaultValTeams,
+ DefaultValThreads, IsOffloadEntry,
+ OutlinedFn, OutlinedFnID);
+
+ if (OutlinedFn != nullptr)
CGM.getTargetCodeGenInfo().setTargetAttributes(nullptr, OutlinedFn, CGM);
}
@@ -6808,10 +6430,8 @@ static llvm::Value *getNumThreads(CodeGenFunction &CGF, const CapturedStmt *CS,
}
if (isOpenMPSimdDirective(Dir->getDirectiveKind()))
return CGF.Builder.getInt32(1);
- return DefaultThreadLimitVal;
}
- return DefaultThreadLimitVal ? DefaultThreadLimitVal
- : CGF.Builder.getInt32(0);
+ return DefaultThreadLimitVal;
}
const Expr *CGOpenMPRuntime::getNumThreadsExprForTargetDirective(
@@ -6954,12 +6574,14 @@ llvm::Value *CGOpenMPRuntime::emitNumThreadsForTargetDirective(
return NumThreads;
const Stmt *Child = CGOpenMPRuntime::getSingleCompoundChild(
CGF.getContext(), CS->getCapturedStmt());
+ // TODO: The standard is not clear how to resolve two thread limit clauses,
+ // let's pick the teams one if it's present, otherwise the target one.
+ const auto *ThreadLimitClause = D.getSingleClause<OMPThreadLimitClause>();
if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
- if (Dir->hasClausesOfKind<OMPThreadLimitClause>()) {
+ if (const auto *TLC = Dir->getSingleClause<OMPThreadLimitClause>()) {
+ ThreadLimitClause = TLC;
CGOpenMPInnerExprInfo CGInfo(CGF, *CS);
CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo);
- const auto *ThreadLimitClause =
- Dir->getSingleClause<OMPThreadLimitClause>();
CodeGenFunction::LexicalScope Scope(
CGF, ThreadLimitClause->getThreadLimit()->getSourceRange());
if (const auto *PreInit =
@@ -6974,11 +6596,15 @@ llvm::Value *CGOpenMPRuntime::emitNumThreadsForTargetDirective(
}
}
}
- llvm::Value *ThreadLimit = CGF.EmitScalarExpr(
- ThreadLimitClause->getThreadLimit(), /*IgnoreResultAssign=*/true);
- ThreadLimitVal =
- Bld.CreateIntCast(ThreadLimit, CGF.Int32Ty, /*isSigned=*/false);
}
+ }
+ if (ThreadLimitClause) {
+ llvm::Value *ThreadLimit = CGF.EmitScalarExpr(
+ ThreadLimitClause->getThreadLimit(), /*IgnoreResultAssign=*/true);
+ ThreadLimitVal =
+ Bld.CreateIntCast(ThreadLimit, CGF.Int32Ty, /*isSigned=*/false);
+ }
+ if (const auto *Dir = dyn_cast_or_null<OMPExecutableDirective>(Child)) {
if (isOpenMPTeamsDirective(Dir->getDirectiveKind()) &&
!isOpenMPDistributeDirective(Dir->getDirectiveKind())) {
CS = Dir->getInnermostCapturedStmt();
@@ -7029,7 +6655,10 @@ llvm::Value *CGOpenMPRuntime::emitNumThreadsForTargetDirective(
ThreadLimitVal =
Bld.CreateIntCast(ThreadLimit, CGF.Int32Ty, /*isSigned=*/false);
}
- return getNumThreads(CGF, D.getInnermostCapturedStmt(), ThreadLimitVal);
+ if (llvm::Value *NumThreads =
+ getNumThreads(CGF, D.getInnermostCapturedStmt(), ThreadLimitVal))
+ return NumThreads;
+ return Bld.getInt32(0);
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_for_simd:
@@ -7164,67 +6793,13 @@ LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
// code for that information.
class MappableExprsHandler {
public:
- /// Values for bit flags used to specify the mapping type for
- /// offloading.
- enum OpenMPOffloadMappingFlags : uint64_t {
- /// No flags
- OMP_MAP_NONE = 0x0,
- /// Allocate memory on the device and move data from host to device.
- OMP_MAP_TO = 0x01,
- /// Allocate memory on the device and move data from device to host.
- OMP_MAP_FROM = 0x02,
- /// Always perform the requested mapping action on the element, even
- /// if it was already mapped before.
- OMP_MAP_ALWAYS = 0x04,
- /// Delete the element from the device environment, ignoring the
- /// current reference count associated with the element.
- OMP_MAP_DELETE = 0x08,
- /// The element being mapped is a pointer-pointee pair; both the
- /// pointer and the pointee should be mapped.
- OMP_MAP_PTR_AND_OBJ = 0x10,
- /// This flags signals that the base address of an entry should be
- /// passed to the target kernel as an argument.
- OMP_MAP_TARGET_PARAM = 0x20,
- /// Signal that the runtime library has to return the device pointer
- /// in the current position for the data being mapped. Used when we have the
- /// use_device_ptr or use_device_addr clause.
- OMP_MAP_RETURN_PARAM = 0x40,
- /// This flag signals that the reference being passed is a pointer to
- /// private data.
- OMP_MAP_PRIVATE = 0x80,
- /// Pass the element to the device by value.
- 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,
- /// 0x800 is reserved for compatibility with XLC.
- /// Produce a runtime error if the data is not already allocated.
- OMP_MAP_PRESENT = 0x1000,
- // Increment and decrement a separate reference counter so that the data
- // cannot be unmapped within the associated region. Thus, this flag is
- // intended to be used on 'target' and 'target data' directives because they
- // are inherently structured. It is not intended to be used on 'target
- // enter data' and 'target exit data' directives because they are inherently
- // dynamic.
- // This is an OpenMP extension for the sake of OpenACC support.
- OMP_MAP_OMPX_HOLD = 0x2000,
- /// Signal that the runtime library should use args as an array of
- /// descriptor_dim pointers and use args_size as dims. Used when we have
- /// non-contiguous list items in target update directive
- OMP_MAP_NON_CONTIG = 0x100000000000,
- /// 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)
+ for (uint64_t Remain =
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF);
+ !(Remain & 1); Remain = Remain >> 1)
Offset++;
return Offset;
}
@@ -7388,6 +6963,13 @@ private:
SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
DevPointersMap;
+ /// Map between device addr declarations and their expression components.
+ /// The key value for declarations in 'this' is null.
+ llvm::DenseMap<
+ const ValueDecl *,
+ SmallVector<OMPClauseMappableExprCommon::MappableExprComponentListRef, 4>>
+ HasDevAddrsMap;
+
/// Map between lambda declarations and their map type.
llvm::DenseMap<const ValueDecl *, const OMPMapClause *> LambdasMap;
@@ -7475,7 +7057,8 @@ private:
ArrayRef<OpenMPMotionModifierKind> MotionModifiers, bool IsImplicit,
bool AddPtrFlag, bool AddIsTargetParamFlag, bool IsNonContiguous) const {
OpenMPOffloadMappingFlags Bits =
- IsImplicit ? OMP_MAP_IMPLICIT : OMP_MAP_NONE;
+ IsImplicit ? OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT
+ : OpenMPOffloadMappingFlags::OMP_MAP_NONE;
switch (MapType) {
case OMPC_MAP_alloc:
case OMPC_MAP_release:
@@ -7485,35 +7068,36 @@ private:
// type modifiers.
break;
case OMPC_MAP_to:
- Bits |= OMP_MAP_TO;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TO;
break;
case OMPC_MAP_from:
- Bits |= OMP_MAP_FROM;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_FROM;
break;
case OMPC_MAP_tofrom:
- Bits |= OMP_MAP_TO | OMP_MAP_FROM;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ OpenMPOffloadMappingFlags::OMP_MAP_FROM;
break;
case OMPC_MAP_delete:
- Bits |= OMP_MAP_DELETE;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
break;
case OMPC_MAP_unknown:
llvm_unreachable("Unexpected map type!");
}
if (AddPtrFlag)
- Bits |= OMP_MAP_PTR_AND_OBJ;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
if (AddIsTargetParamFlag)
- Bits |= OMP_MAP_TARGET_PARAM;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_always))
- Bits |= OMP_MAP_ALWAYS;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_close))
- Bits |= OMP_MAP_CLOSE;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_CLOSE;
if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_present) ||
llvm::is_contained(MotionModifiers, OMPC_MOTION_MODIFIER_present))
- Bits |= OMP_MAP_PRESENT;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_ompx_hold))
- Bits |= OMP_MAP_OMPX_HOLD;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
if (IsNonContiguous)
- Bits |= OMP_MAP_NON_CONTIG;
+ Bits |= OpenMPOffloadMappingFlags::OMP_MAP_NON_CONTIG;
return Bits;
}
@@ -7570,7 +7154,7 @@ private:
const ValueDecl *Mapper = nullptr, bool ForDeviceAddr = false,
const ValueDecl *BaseDecl = nullptr, const Expr *MapExpr = nullptr,
ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
- OverlappedElements = llvm::None) const {
+ OverlappedElements = std::nullopt) const {
// The following summarizes what has to be generated for each map and the
// types below. The generated information is expressed in this order:
// base pointer, section pointer, size, flags
@@ -7780,10 +7364,11 @@ private:
BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(CGF);
if (const auto *VD =
dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) {
- if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ if (std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
if ((*Res == OMPDeclareTargetDeclAttr::MT_Link) ||
- (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory())) {
RequiresReference = true;
BP = CGF.CGM.getOpenMPRuntime().getAddrOfDeclareTargetVar(VD);
@@ -7998,7 +7583,7 @@ private:
std::swap(PartialStruct.PreliminaryMapData, CombinedInfo);
// Emit data for non-overlapped data.
OpenMPOffloadMappingFlags Flags =
- OMP_MAP_MEMBER_OF |
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
getMapTypeBits(MapType, MapModifiers, MotionModifiers, IsImplicit,
/*AddPtrFlag=*/false,
/*AddIsTargetParamFlag=*/false, IsNonContiguous);
@@ -8084,13 +7669,16 @@ private:
// If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well,
// then we reset the TO/FROM/ALWAYS/DELETE/CLOSE flags.
if (IsPointer || (IsMemberReference && Next != CE))
- Flags &= ~(OMP_MAP_TO | OMP_MAP_FROM | OMP_MAP_ALWAYS |
- OMP_MAP_DELETE | OMP_MAP_CLOSE);
+ Flags &= ~(OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ OpenMPOffloadMappingFlags::OMP_MAP_FROM |
+ OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS |
+ OpenMPOffloadMappingFlags::OMP_MAP_DELETE |
+ OpenMPOffloadMappingFlags::OMP_MAP_CLOSE);
if (ShouldBeMemberOf) {
// Set placeholder value MEMBER_OF=FFFF to indicate that the flag
// should be later updated with the correct value of MEMBER_OF.
- Flags |= OMP_MAP_MEMBER_OF;
+ Flags |= OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF;
// From now on, all subsequent PTR_AND_OBJ entries should not be
// marked as MEMBER_OF.
ShouldBeMemberOf = false;
@@ -8337,7 +7925,7 @@ private:
/// Return the adjusted map modifiers if the declaration a capture refers to
/// appears in a first-private clause. This is expected to be used only with
/// directives that start with 'target'.
- MappableExprsHandler::OpenMPOffloadMappingFlags
+ OpenMPOffloadMappingFlags
getMapModifiersForPrivateClauses(const CapturedStmt::Capture &Cap) const {
assert(Cap.capturesVariable() && "Expected capture by reference only!");
@@ -8346,22 +7934,22 @@ private:
// declaration is known as first-private in this handler.
if (FirstPrivateDecls.count(Cap.getCapturedVar())) {
if (Cap.getCapturedVar()->getType()->isAnyPointerType())
- return MappableExprsHandler::OMP_MAP_TO |
- MappableExprsHandler::OMP_MAP_PTR_AND_OBJ;
- return MappableExprsHandler::OMP_MAP_PRIVATE |
- MappableExprsHandler::OMP_MAP_TO;
+ return OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ;
+ return OpenMPOffloadMappingFlags::OMP_MAP_PRIVATE |
+ OpenMPOffloadMappingFlags::OMP_MAP_TO;
}
auto I = LambdasMap.find(Cap.getCapturedVar()->getCanonicalDecl());
if (I != LambdasMap.end())
// for map(to: lambda): using user specified map type.
return getMapTypeBits(
I->getSecond()->getMapType(), I->getSecond()->getMapTypeModifiers(),
- /*MotionModifiers=*/llvm::None, I->getSecond()->isImplicit(),
+ /*MotionModifiers=*/std::nullopt, I->getSecond()->isImplicit(),
/*AddPtrFlag=*/false,
/*AddIsTargetParamFlag=*/false,
/*isNonContiguous=*/false);
- return MappableExprsHandler::OMP_MAP_TO |
- MappableExprsHandler::OMP_MAP_FROM;
+ return OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ OpenMPOffloadMappingFlags::OMP_MAP_FROM;
}
static OpenMPOffloadMappingFlags getMemberOfFlag(unsigned Position) {
@@ -8375,13 +7963,16 @@ private:
// If the entry is PTR_AND_OBJ but has not been marked with the special
// placeholder value 0xFFFF in the MEMBER_OF field, then it should not be
// marked as MEMBER_OF.
- if ((Flags & OMP_MAP_PTR_AND_OBJ) &&
- ((Flags & OMP_MAP_MEMBER_OF) != OMP_MAP_MEMBER_OF))
+ if (static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ Flags & OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ) &&
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ (Flags & OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) !=
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF))
return;
// Reset the placeholder value to prepare the flag for the assignment of the
// proper MEMBER_OF value.
- Flags &= ~OMP_MAP_MEMBER_OF;
+ Flags &= ~OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF;
Flags |= MemberOfFlag;
}
@@ -8500,7 +8091,7 @@ private:
for (const auto L : C->component_lists()) {
const Expr *E = (C->getMapLoc().isValid()) ? *EI : nullptr;
InfoGen(std::get<0>(L), Kind, std::get<1>(L), C->getMapType(),
- C->getMapTypeModifiers(), llvm::None,
+ C->getMapTypeModifiers(), std::nullopt,
/*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L),
E);
++EI;
@@ -8516,7 +8107,7 @@ private:
Kind = Present;
const auto *EI = C->getVarRefs().begin();
for (const auto L : C->component_lists()) {
- InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_to, llvm::None,
+ InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_to, std::nullopt,
C->getMotionModifiers(), /*ReturnDevicePointer=*/false,
C->isImplicit(), std::get<2>(L), *EI);
++EI;
@@ -8532,56 +8123,101 @@ private:
Kind = Present;
const auto *EI = C->getVarRefs().begin();
for (const auto L : C->component_lists()) {
- InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_from, llvm::None,
- C->getMotionModifiers(), /*ReturnDevicePointer=*/false,
- C->isImplicit(), std::get<2>(L), *EI);
+ InfoGen(std::get<0>(L), Kind, std::get<1>(L), OMPC_MAP_from,
+ std::nullopt, C->getMotionModifiers(),
+ /*ReturnDevicePointer=*/false, C->isImplicit(), std::get<2>(L),
+ *EI);
++EI;
}
}
- // Look at the use_device_ptr clause information and mark the existing map
- // entries as such. If there is no map information for an entry in the
- // use_device_ptr list, we create one with map type 'alloc' and zero size
- // section. It is the user fault if that was not mapped before. If there is
- // no map information and the pointer is a struct member, then we defer the
- // emission of that entry until the whole struct has been processed.
+ // Look at the use_device_ptr and use_device_addr clauses information and
+ // mark the existing map entries as such. If there is no map information for
+ // an entry in the use_device_ptr and use_device_addr list, we create one
+ // with map type 'alloc' and zero size section. It is the user fault if that
+ // was not mapped before. If there is no map information and the pointer is
+ // a struct member, then we defer the emission of that entry until the whole
+ // struct has been processed.
llvm::MapVector<CanonicalDeclPtr<const Decl>,
SmallVector<DeferredDevicePtrEntryTy, 4>>
DeferredInfo;
- MapCombinedInfoTy UseDevicePtrCombinedInfo;
+ MapCombinedInfoTy UseDeviceDataCombinedInfo;
+
+ auto &&UseDeviceDataCombinedInfoGen =
+ [&UseDeviceDataCombinedInfo](const ValueDecl *VD, llvm::Value *Ptr,
+ CodeGenFunction &CGF) {
+ UseDeviceDataCombinedInfo.Exprs.push_back(VD);
+ UseDeviceDataCombinedInfo.BasePointers.emplace_back(Ptr, VD);
+ UseDeviceDataCombinedInfo.Pointers.push_back(Ptr);
+ UseDeviceDataCombinedInfo.Sizes.push_back(
+ llvm::Constant::getNullValue(CGF.Int64Ty));
+ UseDeviceDataCombinedInfo.Types.push_back(
+ OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM);
+ UseDeviceDataCombinedInfo.Mappers.push_back(nullptr);
+ };
- for (const auto *Cl : Clauses) {
- const auto *C = dyn_cast<OMPUseDevicePtrClause>(Cl);
- if (!C)
- continue;
- for (const auto L : C->component_lists()) {
- OMPClauseMappableExprCommon::MappableExprComponentListRef Components =
- std::get<1>(L);
- assert(!Components.empty() &&
- "Not expecting empty list of components!");
- const ValueDecl *VD = Components.back().getAssociatedDeclaration();
- VD = cast<ValueDecl>(VD->getCanonicalDecl());
- const Expr *IE = Components.back().getAssociatedExpression();
- // If the first component is a member expression, we have to look into
- // 'this', which maps to null in the map of map information. Otherwise
- // look directly for the information.
- auto It = Info.find(isa<MemberExpr>(IE) ? nullptr : VD);
-
- // We potentially have map information for this declaration already.
- // Look for the first set of components that refer to it.
- if (It != Info.end()) {
- bool Found = false;
- for (auto &Data : It->second) {
- auto *CI = llvm::find_if(Data, [VD](const MapInfo &MI) {
- return MI.Components.back().getAssociatedDeclaration() == VD;
- });
- // If we found a map entry, signal that the pointer has to be
- // returned and move on to the next declaration. Exclude cases where
- // the base pointer is mapped as array subscript, array section or
- // array shaping. The base address is passed as a pointer to base in
- // this case and cannot be used as a base for use_device_ptr list
- // item.
- if (CI != Data.end()) {
+ auto &&MapInfoGen =
+ [&DeferredInfo, &UseDeviceDataCombinedInfoGen,
+ &InfoGen](CodeGenFunction &CGF, const Expr *IE, const ValueDecl *VD,
+ OMPClauseMappableExprCommon::MappableExprComponentListRef
+ Components,
+ bool IsImplicit, bool IsDevAddr) {
+ // 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.
+ if (isa<MemberExpr>(IE)) {
+ // Insert the pointer into Info to be processed by
+ // generateInfoForComponentList. Because it is a member pointer
+ // without a pointee, no entry will be generated for it, therefore
+ // we need to generate one after the whole struct has been
+ // processed. Nonetheless, generateInfoForComponentList must be
+ // called to take the pointer into account for the calculation of
+ // the range of the partial struct.
+ InfoGen(nullptr, Other, Components, OMPC_MAP_unknown, std::nullopt,
+ std::nullopt, /*ReturnDevicePointer=*/false, IsImplicit,
+ nullptr, nullptr, IsDevAddr);
+ DeferredInfo[nullptr].emplace_back(IE, VD, IsDevAddr);
+ } else {
+ llvm::Value *Ptr;
+ if (IsDevAddr) {
+ if (IE->isGLValue())
+ Ptr = CGF.EmitLValue(IE).getPointer(CGF);
+ else
+ Ptr = CGF.EmitScalarExpr(IE);
+ } else {
+ Ptr = CGF.EmitLoadOfScalar(CGF.EmitLValue(IE), IE->getExprLoc());
+ }
+ UseDeviceDataCombinedInfoGen(VD, Ptr, CGF);
+ }
+ };
+
+ auto &&IsMapInfoExist = [&Info](CodeGenFunction &CGF, const ValueDecl *VD,
+ const Expr *IE, bool IsDevAddr) -> bool {
+ // We potentially have map information for this declaration already.
+ // Look for the first set of components that refer to it. If found,
+ // return true.
+ // If the first component is a member expression, we have to look into
+ // 'this', which maps to null in the map of map information. Otherwise
+ // look directly for the information.
+ auto It = Info.find(isa<MemberExpr>(IE) ? nullptr : VD);
+ if (It != Info.end()) {
+ bool Found = false;
+ for (auto &Data : It->second) {
+ auto *CI = llvm::find_if(Data, [VD](const MapInfo &MI) {
+ return MI.Components.back().getAssociatedDeclaration() == VD;
+ });
+ // If we found a map entry, signal that the pointer has to be
+ // returned and move on to the next declaration. Exclude cases where
+ // the base pointer is mapped as array subscript, array section or
+ // array shaping. The base address is passed as a pointer to base in
+ // this case and cannot be used as a base for use_device_ptr list
+ // item.
+ if (CI != Data.end()) {
+ if (IsDevAddr) {
+ CI->ReturnDevicePointer = true;
+ Found = true;
+ break;
+ } else {
auto PrevCI = std::next(CI->Components.rbegin());
const auto *VarD = dyn_cast<VarDecl>(VD);
if (CGF.CGM.getOpenMPRuntime().hasRequiresUnifiedSharedMemory() ||
@@ -8596,51 +8232,45 @@ private:
}
}
}
- if (Found)
- continue;
- }
-
- // 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.
- if (isa<MemberExpr>(IE)) {
- // Insert the pointer into Info to be processed by
- // generateInfoForComponentList. Because it is a member pointer
- // without a pointee, no entry will be generated for it, therefore
- // we need to generate one after the whole struct has been processed.
- // Nonetheless, generateInfoForComponentList must be called to take
- // the pointer into account for the calculation of the range of the
- // partial struct.
- InfoGen(nullptr, Other, Components, OMPC_MAP_unknown, llvm::None,
- llvm::None, /*ReturnDevicePointer=*/false, C->isImplicit(),
- nullptr);
- DeferredInfo[nullptr].emplace_back(IE, VD, /*ForDeviceAddr=*/false);
- } else {
- llvm::Value *Ptr =
- CGF.EmitLoadOfScalar(CGF.EmitLValue(IE), IE->getExprLoc());
- UseDevicePtrCombinedInfo.Exprs.push_back(VD);
- UseDevicePtrCombinedInfo.BasePointers.emplace_back(Ptr, VD);
- UseDevicePtrCombinedInfo.Pointers.push_back(Ptr);
- UseDevicePtrCombinedInfo.Sizes.push_back(
- llvm::Constant::getNullValue(CGF.Int64Ty));
- UseDevicePtrCombinedInfo.Types.push_back(OMP_MAP_RETURN_PARAM);
- UseDevicePtrCombinedInfo.Mappers.push_back(nullptr);
}
+ return Found;
}
- }
+ return false;
+ };
- // Look at the use_device_addr clause information and mark the existing map
+ // Look at the use_device_ptr clause information and mark the existing map
// entries as such. If there is no map information for an entry in the
- // use_device_addr list, we create one with map type 'alloc' and zero size
+ // use_device_ptr list, we create one with map type 'alloc' and zero size
// section. It is the user fault if that was not mapped before. If there is
// no map information and the pointer is a struct member, then we defer the
// emission of that entry until the whole struct has been processed.
+ for (const auto *Cl : Clauses) {
+ const auto *C = dyn_cast<OMPUseDevicePtrClause>(Cl);
+ if (!C)
+ continue;
+ for (const auto L : C->component_lists()) {
+ OMPClauseMappableExprCommon::MappableExprComponentListRef Components =
+ std::get<1>(L);
+ assert(!Components.empty() &&
+ "Not expecting empty list of components!");
+ const ValueDecl *VD = Components.back().getAssociatedDeclaration();
+ VD = cast<ValueDecl>(VD->getCanonicalDecl());
+ const Expr *IE = Components.back().getAssociatedExpression();
+ if (IsMapInfoExist(CGF, VD, IE, /*IsDevAddr=*/false))
+ continue;
+ MapInfoGen(CGF, IE, VD, Components, C->isImplicit(),
+ /*IsDevAddr=*/false);
+ }
+ }
+
llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>, 4> Processed;
for (const auto *Cl : Clauses) {
const auto *C = dyn_cast<OMPUseDeviceAddrClause>(Cl);
if (!C)
continue;
for (const auto L : C->component_lists()) {
+ OMPClauseMappableExprCommon::MappableExprComponentListRef Components =
+ std::get<1>(L);
assert(!std::get<1>(L).empty() &&
"Not expecting empty list of components!");
const ValueDecl *VD = std::get<1>(L).back().getAssociatedDeclaration();
@@ -8648,60 +8278,10 @@ private:
continue;
VD = cast<ValueDecl>(VD->getCanonicalDecl());
const Expr *IE = std::get<1>(L).back().getAssociatedExpression();
- // If the first component is a member expression, we have to look into
- // 'this', which maps to null in the map of map information. Otherwise
- // look directly for the information.
- auto It = Info.find(isa<MemberExpr>(IE) ? nullptr : VD);
-
- // We potentially have map information for this declaration already.
- // Look for the first set of components that refer to it.
- if (It != Info.end()) {
- bool Found = false;
- for (auto &Data : It->second) {
- auto *CI = llvm::find_if(Data, [VD](const MapInfo &MI) {
- return MI.Components.back().getAssociatedDeclaration() == VD;
- });
- // If we found a map entry, signal that the pointer has to be
- // returned and move on to the next declaration.
- if (CI != Data.end()) {
- CI->ReturnDevicePointer = true;
- Found = true;
- break;
- }
- }
- if (Found)
- continue;
- }
-
- // 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.
- if (isa<MemberExpr>(IE)) {
- // Insert the pointer into Info to be processed by
- // generateInfoForComponentList. Because it is a member pointer
- // without a pointee, no entry will be generated for it, therefore
- // we need to generate one after the whole struct has been processed.
- // Nonetheless, generateInfoForComponentList must be called to take
- // the pointer into account for the calculation of the range of the
- // partial struct.
- InfoGen(nullptr, Other, std::get<1>(L), OMPC_MAP_unknown, llvm::None,
- llvm::None, /*ReturnDevicePointer=*/false, C->isImplicit(),
- nullptr, nullptr, /*ForDeviceAddr=*/true);
- DeferredInfo[nullptr].emplace_back(IE, VD, /*ForDeviceAddr=*/true);
- } else {
- llvm::Value *Ptr;
- if (IE->isGLValue())
- Ptr = CGF.EmitLValue(IE).getPointer(CGF);
- else
- Ptr = CGF.EmitScalarExpr(IE);
- CombinedInfo.Exprs.push_back(VD);
- CombinedInfo.BasePointers.emplace_back(Ptr, VD);
- CombinedInfo.Pointers.push_back(Ptr);
- CombinedInfo.Sizes.push_back(
- llvm::Constant::getNullValue(CGF.Int64Ty));
- CombinedInfo.Types.push_back(OMP_MAP_RETURN_PARAM);
- CombinedInfo.Mappers.push_back(nullptr);
- }
+ if (IsMapInfoExist(CGF, VD, IE, /*IsDevAddr=*/true))
+ continue;
+ MapInfoGen(CGF, IE, VD, Components, C->isImplicit(),
+ /*IsDevAddr=*/true);
}
}
@@ -8738,7 +8318,8 @@ private:
CurInfo.BasePointers[CurrentBasePointersIdx].setDevicePtrDecl(
RelevantVD);
- CurInfo.Types[CurrentBasePointersIdx] |= OMP_MAP_RETURN_PARAM;
+ CurInfo.Types[CurrentBasePointersIdx] |=
+ OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
}
}
}
@@ -8759,7 +8340,9 @@ private:
// Entry is RETURN_PARAM. Also, set the placeholder value
// MEMBER_OF=FFFF so that the entry is later updated with the
// correct value of MEMBER_OF.
- CurInfo.Types.push_back(OMP_MAP_RETURN_PARAM | OMP_MAP_MEMBER_OF);
+ CurInfo.Types.push_back(
+ OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM |
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF);
} else {
BasePtr = this->CGF.EmitLValue(L.IE).getPointer(CGF);
Ptr = this->CGF.EmitLoadOfScalar(this->CGF.EmitLValue(L.IE),
@@ -8767,8 +8350,10 @@ private:
// Entry is PTR_AND_OBJ and RETURN_PARAM. Also, set the
// placeholder value MEMBER_OF=FFFF so that the entry is later
// updated with the correct value of MEMBER_OF.
- CurInfo.Types.push_back(OMP_MAP_PTR_AND_OBJ | OMP_MAP_RETURN_PARAM |
- OMP_MAP_MEMBER_OF);
+ CurInfo.Types.push_back(
+ OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
+ OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM |
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF);
}
CurInfo.Exprs.push_back(L.VD);
CurInfo.BasePointers.emplace_back(BasePtr, L.VD);
@@ -8790,7 +8375,7 @@ private:
CombinedInfo.append(CurInfo);
}
// Append data for use_device_ptr clauses.
- CombinedInfo.append(UseDevicePtrCombinedInfo);
+ CombinedInfo.append(UseDeviceDataCombinedInfo);
}
public:
@@ -8818,6 +8403,10 @@ public:
for (const auto *C : Dir.getClausesOfKind<OMPIsDevicePtrClause>())
for (auto L : C->component_lists())
DevPointersMap[std::get<0>(L)].push_back(std::get<1>(L));
+ // Extract device addr clause information.
+ for (const auto *C : Dir.getClausesOfKind<OMPHasDeviceAddrClause>())
+ for (auto L : C->component_lists())
+ HasDevAddrsMap[std::get<0>(L)].push_back(std::get<1>(L));
// Extract map information.
for (const auto *C : Dir.getClausesOfKind<OMPMapClause>()) {
if (C->getMapType() != OMPC_MAP_to)
@@ -8848,7 +8437,8 @@ public:
const ValueDecl *VD = nullptr,
bool NotTargetParams = true) const {
if (CurTypes.size() == 1 &&
- ((CurTypes.back() & OMP_MAP_MEMBER_OF) != OMP_MAP_MEMBER_OF) &&
+ ((CurTypes.back() & OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) !=
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF) &&
!PartialStruct.IsArraySection)
return;
Address LBAddr = PartialStruct.LowestElem.second;
@@ -8862,31 +8452,53 @@ public:
CombinedInfo.BasePointers.push_back(PartialStruct.Base.getPointer());
// Pointer is the address of the lowest element
llvm::Value *LB = LBAddr.getPointer();
- CombinedInfo.Pointers.push_back(LB);
+ const CXXMethodDecl *MD =
+ CGF.CurFuncDecl ? dyn_cast<CXXMethodDecl>(CGF.CurFuncDecl) : nullptr;
+ const CXXRecordDecl *RD = MD ? MD->getParent() : nullptr;
+ bool HasBaseClass = RD ? RD->getNumBases() > 0 : false;
// There should not be a mapper for a combined entry.
+ if (HasBaseClass) {
+ // OpenMP 5.2 148:21:
+ // If the target construct is within a class non-static member function,
+ // and a variable is an accessible data member of the object for which the
+ // non-static data member function is invoked, the variable is treated as
+ // if the this[:1] expression had appeared in a map clause with a map-type
+ // of tofrom.
+ // Emit this[:1]
+ CombinedInfo.Pointers.push_back(PartialStruct.Base.getPointer());
+ QualType Ty = MD->getThisType()->getPointeeType();
+ llvm::Value *Size =
+ CGF.Builder.CreateIntCast(CGF.getTypeSize(Ty), CGF.Int64Ty,
+ /*isSigned=*/true);
+ CombinedInfo.Sizes.push_back(Size);
+ } else {
+ CombinedInfo.Pointers.push_back(LB);
+ // Size is (addr of {highest+1} element) - (addr of lowest element)
+ llvm::Value *HB = HBAddr.getPointer();
+ llvm::Value *HAddr = CGF.Builder.CreateConstGEP1_32(
+ HBAddr.getElementType(), HB, /*Idx0=*/1);
+ llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy);
+ llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy);
+ llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CGF.Int8Ty, CHAddr, CLAddr);
+ llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.Int64Ty,
+ /*isSigned=*/false);
+ CombinedInfo.Sizes.push_back(Size);
+ }
CombinedInfo.Mappers.push_back(nullptr);
- // Size is (addr of {highest+1} element) - (addr of lowest element)
- llvm::Value *HB = HBAddr.getPointer();
- llvm::Value *HAddr =
- CGF.Builder.CreateConstGEP1_32(HBAddr.getElementType(), HB, /*Idx0=*/1);
- llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy);
- llvm::Value *CHAddr = CGF.Builder.CreatePointerCast(HAddr, CGF.VoidPtrTy);
- llvm::Value *Diff = CGF.Builder.CreatePtrDiff(CGF.Int8Ty, CHAddr, CLAddr);
- llvm::Value *Size = CGF.Builder.CreateIntCast(Diff, CGF.Int64Ty,
- /*isSigned=*/false);
- CombinedInfo.Sizes.push_back(Size);
// Map type is always TARGET_PARAM, if generate info for captures.
- CombinedInfo.Types.push_back(NotTargetParams ? OMP_MAP_NONE
- : OMP_MAP_TARGET_PARAM);
+ CombinedInfo.Types.push_back(
+ NotTargetParams ? OpenMPOffloadMappingFlags::OMP_MAP_NONE
+ : OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM);
// If any element has the present modifier, then make sure the runtime
// doesn't attempt to allocate the struct.
if (CurTypes.end() !=
llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) {
- return Type & OMP_MAP_PRESENT;
+ return static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ Type & OpenMPOffloadMappingFlags::OMP_MAP_PRESENT);
}))
- CombinedInfo.Types.back() |= OMP_MAP_PRESENT;
+ CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
// Remove TARGET_PARAM flag from the first element
- (*CurTypes.begin()) &= ~OMP_MAP_TARGET_PARAM;
+ (*CurTypes.begin()) &= ~OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
// If any element has the ompx_hold modifier, then make sure the runtime
// uses the hold reference count for the struct as a whole so that it won't
// be unmapped by an extra dynamic reference count decrement. Add it to all
@@ -8895,11 +8507,12 @@ public:
// individual elements.
if (CurTypes.end() !=
llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) {
- return Type & OMP_MAP_OMPX_HOLD;
+ return static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ Type & OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD);
})) {
- CombinedInfo.Types.back() |= OMP_MAP_OMPX_HOLD;
+ CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
for (auto &M : CurTypes)
- M |= OMP_MAP_OMPX_HOLD;
+ M |= OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
}
// All other current entries will be MEMBER_OF the combined entry
@@ -8947,7 +8560,7 @@ public:
Address VDAddr(Arg, CGF.ConvertTypeForMem(VDType),
CGF.getContext().getDeclAlign(VD));
LValue VDLVal = CGF.MakeAddrLValue(VDAddr, VDType);
- llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
FieldDecl *ThisCapture = nullptr;
RD->getCaptureFields(Captures, ThisCapture);
if (ThisCapture) {
@@ -8962,14 +8575,17 @@ public:
CombinedInfo.Sizes.push_back(
CGF.Builder.CreateIntCast(CGF.getTypeSize(CGF.getContext().VoidPtrTy),
CGF.Int64Ty, /*isSigned=*/true));
- CombinedInfo.Types.push_back(OMP_MAP_PTR_AND_OBJ | OMP_MAP_LITERAL |
- OMP_MAP_MEMBER_OF | OMP_MAP_IMPLICIT);
+ CombinedInfo.Types.push_back(
+ OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
+ OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
+ OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
CombinedInfo.Mappers.push_back(nullptr);
}
for (const LambdaCapture &LC : RD->captures()) {
if (!LC.capturesVariable())
continue;
- const VarDecl *VD = LC.getCapturedVar();
+ const VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
if (LC.getCaptureKind() != LCK_ByRef && !VD->getType()->isPointerType())
continue;
auto It = Captures.find(VD);
@@ -8995,8 +8611,11 @@ public:
CombinedInfo.Pointers.push_back(VarRVal.getScalarVal());
CombinedInfo.Sizes.push_back(llvm::ConstantInt::get(CGF.Int64Ty, 0));
}
- CombinedInfo.Types.push_back(OMP_MAP_PTR_AND_OBJ | OMP_MAP_LITERAL |
- OMP_MAP_MEMBER_OF | OMP_MAP_IMPLICIT);
+ CombinedInfo.Types.push_back(
+ OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
+ OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
+ OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
CombinedInfo.Mappers.push_back(nullptr);
}
}
@@ -9008,8 +8627,10 @@ public:
MapFlagsArrayTy &Types) const {
for (unsigned I = 0, E = Types.size(); I < E; ++I) {
// Set correct member_of idx for all implicit lambda captures.
- if (Types[I] != (OMP_MAP_PTR_AND_OBJ | OMP_MAP_LITERAL |
- OMP_MAP_MEMBER_OF | OMP_MAP_IMPLICIT))
+ if (Types[I] != (OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ |
+ OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
+ OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF |
+ OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT))
continue;
llvm::Value *BasePtr = LambdaPointers.lookup(*BasePointers[I]);
assert(BasePtr && "Unable to find base lambda address.");
@@ -9051,7 +8672,7 @@ public:
// If this declaration appears in a is_device_ptr clause we just have to
// pass the pointer by value. If it is a reference to a declaration, we just
// pass its value.
- if (DevPointersMap.count(VD)) {
+ if (VD && (DevPointersMap.count(VD) || HasDevAddrsMap.count(VD))) {
CombinedInfo.Exprs.push_back(VD);
CombinedInfo.BasePointers.emplace_back(Arg, VD);
CombinedInfo.Pointers.push_back(Arg);
@@ -9059,8 +8680,10 @@ public:
CGF.getTypeSize(CGF.getContext().VoidPtrTy), CGF.Int64Ty,
/*isSigned=*/true));
CombinedInfo.Types.push_back(
- (Cap->capturesVariable() ? OMP_MAP_TO : OMP_MAP_LITERAL) |
- OMP_MAP_TARGET_PARAM);
+ (Cap->capturesVariable()
+ ? OpenMPOffloadMappingFlags::OMP_MAP_TO
+ : OpenMPOffloadMappingFlags::OMP_MAP_LITERAL) |
+ OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM);
CombinedInfo.Mappers.push_back(nullptr);
return;
}
@@ -9070,6 +8693,21 @@ public:
OpenMPMapClauseKind, ArrayRef<OpenMPMapModifierKind>, bool,
const ValueDecl *, const Expr *>;
SmallVector<MapData, 4> DeclComponentLists;
+ // For member fields list in is_device_ptr, store it in
+ // DeclComponentLists for generating components info.
+ static const OpenMPMapModifierKind Unknown = OMPC_MAP_MODIFIER_unknown;
+ auto It = DevPointersMap.find(VD);
+ if (It != DevPointersMap.end())
+ for (const auto &MCL : It->second)
+ DeclComponentLists.emplace_back(MCL, OMPC_MAP_to, Unknown,
+ /*IsImpicit = */ true, nullptr,
+ nullptr);
+ auto I = HasDevAddrsMap.find(VD);
+ if (I != HasDevAddrsMap.end())
+ for (const auto &MCL : I->second)
+ DeclComponentLists.emplace_back(MCL, OMPC_MAP_tofrom, Unknown,
+ /*IsImpicit = */ true, nullptr,
+ nullptr);
assert(CurDir.is<const OMPExecutableDirective *>() &&
"Expect a executable directive");
const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
@@ -9123,7 +8761,7 @@ public:
std::tie(Components, MapType, MapModifiers, IsImplicit, Mapper, VarRef) =
L;
++Count;
- for (const MapData &L1 : makeArrayRef(DeclComponentLists).slice(Count)) {
+ for (const MapData &L1 : ArrayRef(DeclComponentLists).slice(Count)) {
OMPClauseMappableExprCommon::MappableExprComponentListRef Components1;
std::tie(Components1, MapType, MapModifiers, IsImplicit, Mapper,
VarRef) = L1;
@@ -9243,7 +8881,7 @@ public:
ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
OverlappedComponents = Pair.getSecond();
generateInfoForComponentList(
- MapType, MapModifiers, llvm::None, Components, CombinedInfo,
+ MapType, MapModifiers, std::nullopt, Components, CombinedInfo,
PartialStruct, IsFirstComponentList, IsImplicit, Mapper,
/*ForDeviceAddr=*/false, VD, VarRef, OverlappedComponents);
IsFirstComponentList = false;
@@ -9260,7 +8898,7 @@ public:
L;
auto It = OverlappedData.find(&L);
if (It == OverlappedData.end())
- generateInfoForComponentList(MapType, MapModifiers, llvm::None,
+ generateInfoForComponentList(MapType, MapModifiers, std::nullopt,
Components, CombinedInfo, PartialStruct,
IsFirstComponentList, IsImplicit, Mapper,
/*ForDeviceAddr=*/false, VD, VarRef);
@@ -9284,7 +8922,8 @@ public:
CGF.Builder.CreateIntCast(CGF.getTypeSize(PtrTy->getPointeeType()),
CGF.Int64Ty, /*isSigned=*/true));
// Default map type.
- CombinedInfo.Types.push_back(OMP_MAP_TO | OMP_MAP_FROM);
+ CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ OpenMPOffloadMappingFlags::OMP_MAP_FROM);
} else if (CI.capturesVariableByCopy()) {
const VarDecl *VD = CI.getCapturedVar();
CombinedInfo.Exprs.push_back(VD->getCanonicalDecl());
@@ -9293,13 +8932,14 @@ public:
if (!RI.getType()->isAnyPointerType()) {
// We have to signal to the runtime captures passed by value that are
// not pointers.
- CombinedInfo.Types.push_back(OMP_MAP_LITERAL);
+ CombinedInfo.Types.push_back(
+ OpenMPOffloadMappingFlags::OMP_MAP_LITERAL);
CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
CGF.getTypeSize(RI.getType()), CGF.Int64Ty, /*isSigned=*/true));
} else {
// Pointers are implicitly mapped with a zero size and no flags
// (other than first map that is added for all implicit maps).
- CombinedInfo.Types.push_back(OMP_MAP_NONE);
+ CombinedInfo.Types.push_back(OpenMPOffloadMappingFlags::OMP_MAP_NONE);
CombinedInfo.Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
}
auto I = FirstPrivateDecls.find(VD);
@@ -9331,11 +8971,12 @@ public:
IsImplicit = I->getSecond();
}
// Every default map produces a single argument which is a target parameter.
- CombinedInfo.Types.back() |= OMP_MAP_TARGET_PARAM;
+ CombinedInfo.Types.back() |=
+ OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
// Add flag stating this is an implicit map.
if (IsImplicit)
- CombinedInfo.Types.back() |= OMP_MAP_IMPLICIT;
+ CombinedInfo.Types.back() |= OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
// No user-defined mapper for default mapping.
CombinedInfo.Mappers.push_back(nullptr);
@@ -9404,7 +9045,7 @@ static void emitNonContiguousDescriptor(
DimsAddr, CGM.Int8PtrTy, CGM.Int8Ty);
llvm::Value *P = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.PointersArray, 0, I);
+ Info.RTArgs.PointersArray, 0, I);
Address PAddr(P, CGM.VoidPtrTy, CGF.getPointerAlign());
CGF.Builder.CreateStore(DAddr.getPointer(), PAddr);
++L;
@@ -9482,13 +9123,13 @@ static void emitOffloadingArrays(
Ctx.VoidPtrTy, PointerNumAP, nullptr, ArrayType::Normal,
/*IndexTypeQuals=*/0);
- Info.BasePointersArray =
+ Info.RTArgs.BasePointersArray =
CGF.CreateMemTemp(PointerArrayType, ".offload_baseptrs").getPointer();
- Info.PointersArray =
+ Info.RTArgs.PointersArray =
CGF.CreateMemTemp(PointerArrayType, ".offload_ptrs").getPointer();
Address MappersArray =
CGF.CreateMemTemp(PointerArrayType, ".offload_mappers");
- Info.MappersArray = MappersArray.getPointer();
+ Info.RTArgs.MappersArray = MappersArray.getPointer();
// If we don't have any VLA types or other types that require runtime
// evaluation, we can use a constant array for the map sizes, otherwise we
@@ -9501,8 +9142,10 @@ static void emitOffloadingArrays(
for (unsigned I = 0, E = CombinedInfo.Sizes.size(); I < E; ++I) {
if (auto *CI = dyn_cast<llvm::Constant>(CombinedInfo.Sizes[I])) {
if (!isa<llvm::ConstantExpr>(CI) && !isa<llvm::GlobalValue>(CI)) {
- if (IsNonContiguous && (CombinedInfo.Types[I] &
- MappableExprsHandler::OMP_MAP_NON_CONTIG))
+ if (IsNonContiguous &&
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ CombinedInfo.Types[I] &
+ OpenMPOffloadMappingFlags::OMP_MAP_NON_CONTIG))
ConstSizes[I] = llvm::ConstantInt::get(
CGF.Int64Ty, CombinedInfo.NonContigInfo.Dims[I]);
else
@@ -9517,7 +9160,7 @@ static void emitOffloadingArrays(
QualType SizeArrayType = Ctx.getConstantArrayType(
Int64Ty, PointerNumAP, nullptr, ArrayType::Normal,
/*IndexTypeQuals=*/0);
- Info.SizesArray =
+ Info.RTArgs.SizesArray =
CGF.CreateMemTemp(SizeArrayType, ".offload_sizes").getPointer();
} else {
auto *SizesArrayInit = llvm::ConstantArray::get(
@@ -9541,26 +9184,29 @@ static void emitOffloadingArrays(
CGM.getNaturalTypeAlignment(Ctx.getIntTypeForBitwidth(
/*DestWidth=*/64, /*Signed=*/false))),
CGF.getTypeSize(SizeArrayType));
- Info.SizesArray = Buffer.getPointer();
+ Info.RTArgs.SizesArray = Buffer.getPointer();
} else {
- Info.SizesArray = SizesArrayGbl;
+ Info.RTArgs.SizesArray = SizesArrayGbl;
}
}
// The map types are always constant so we don't need to generate code to
// fill arrays. Instead, we create an array constant.
- SmallVector<uint64_t, 4> Mapping(CombinedInfo.Types.size(), 0);
- llvm::copy(CombinedInfo.Types, Mapping.begin());
+ SmallVector<uint64_t, 4> Mapping;
+ for (auto mapFlag : CombinedInfo.Types)
+ Mapping.push_back(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ mapFlag));
std::string MaptypesName =
CGM.getOpenMPRuntime().getName({"offload_maptypes"});
auto *MapTypesArrayGbl =
OMPBuilder.createOffloadMaptypes(Mapping, MaptypesName);
- Info.MapTypesArray = MapTypesArrayGbl;
+ Info.RTArgs.MapTypesArray = MapTypesArrayGbl;
// The information types are only built if there is debug information
// requested.
if (CGM.getCodeGenOpts().getDebugInfo() == codegenoptions::NoDebugInfo) {
- Info.MapNamesArray = llvm::Constant::getNullValue(
+ Info.RTArgs.MapNamesArray = llvm::Constant::getNullValue(
llvm::Type::getInt8Ty(CGF.Builder.getContext())->getPointerTo());
} else {
auto fillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) {
@@ -9572,7 +9218,7 @@ static void emitOffloadingArrays(
CGM.getOpenMPRuntime().getName({"offload_mapnames"});
auto *MapNamesArrayGbl =
OMPBuilder.createOffloadMapnames(InfoMap, MapnamesName);
- Info.MapNamesArray = MapNamesArrayGbl;
+ Info.RTArgs.MapNamesArray = MapNamesArrayGbl;
}
// If there's a present map type modifier, it must not be applied to the end
@@ -9580,15 +9226,19 @@ static void emitOffloadingArrays(
if (Info.separateBeginEndCalls()) {
bool EndMapTypesDiffer = false;
for (uint64_t &Type : Mapping) {
- if (Type & MappableExprsHandler::OMP_MAP_PRESENT) {
- Type &= ~MappableExprsHandler::OMP_MAP_PRESENT;
+ if (Type &
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_PRESENT)) {
+ Type &=
+ ~static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_PRESENT);
EndMapTypesDiffer = true;
}
}
if (EndMapTypesDiffer) {
MapTypesArrayGbl =
OMPBuilder.createOffloadMaptypes(Mapping, MaptypesName);
- Info.MapTypesArrayEnd = MapTypesArrayGbl;
+ Info.RTArgs.MapTypesArrayEnd = MapTypesArrayGbl;
}
}
@@ -9596,7 +9246,7 @@ static void emitOffloadingArrays(
llvm::Value *BPVal = *CombinedInfo.BasePointers[I];
llvm::Value *BP = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.BasePointersArray, 0, I);
+ Info.RTArgs.BasePointersArray, 0, I);
BP = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
BP, BPVal->getType()->getPointerTo(/*AddrSpace=*/0));
Address BPAddr(BP, BPVal->getType(),
@@ -9611,7 +9261,7 @@ static void emitOffloadingArrays(
llvm::Value *PVal = CombinedInfo.Pointers[I];
llvm::Value *P = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.PointersArray, 0, I);
+ Info.RTArgs.PointersArray, 0, I);
P = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
P, PVal->getType()->getPointerTo(/*AddrSpace=*/0));
Address PAddr(P, PVal->getType(), Ctx.getTypeAlignInChars(Ctx.VoidPtrTy));
@@ -9620,7 +9270,7 @@ static void emitOffloadingArrays(
if (RuntimeSizes.test(I)) {
llvm::Value *S = CGF.Builder.CreateConstInBoundsGEP2_32(
llvm::ArrayType::get(CGM.Int64Ty, Info.NumberOfPtrs),
- Info.SizesArray,
+ Info.RTArgs.SizesArray,
/*Idx0=*/0,
/*Idx1=*/I);
Address SAddr(S, CGM.Int64Ty, Ctx.getTypeAlignInChars(Int64Ty));
@@ -9650,76 +9300,6 @@ static void emitOffloadingArrays(
emitNonContiguousDescriptor(CGF, CombinedInfo, Info);
}
-namespace {
-/// Additional arguments for emitOffloadingArraysArgument function.
-struct ArgumentsOptions {
- bool ForEndCall = false;
- ArgumentsOptions() = default;
- ArgumentsOptions(bool ForEndCall) : ForEndCall(ForEndCall) {}
-};
-} // namespace
-
-/// Emit the arguments to be passed to the runtime library based on the
-/// arrays of base pointers, pointers, sizes, map types, and mappers. If
-/// ForEndCall, emit map types to be passed for the end of the region instead of
-/// the beginning.
-static void emitOffloadingArraysArgument(
- CodeGenFunction &CGF, llvm::Value *&BasePointersArrayArg,
- llvm::Value *&PointersArrayArg, llvm::Value *&SizesArrayArg,
- llvm::Value *&MapTypesArrayArg, llvm::Value *&MapNamesArrayArg,
- llvm::Value *&MappersArrayArg, CGOpenMPRuntime::TargetDataInfo &Info,
- const ArgumentsOptions &Options = ArgumentsOptions()) {
- assert((!Options.ForEndCall || Info.separateBeginEndCalls()) &&
- "expected region end call to runtime only when end call is separate");
- CodeGenModule &CGM = CGF.CGM;
- if (Info.NumberOfPtrs) {
- BasePointersArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.BasePointersArray,
- /*Idx0=*/0, /*Idx1=*/0);
- PointersArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.PointersArray,
- /*Idx0=*/0,
- /*Idx1=*/0);
- SizesArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.Int64Ty, Info.NumberOfPtrs), Info.SizesArray,
- /*Idx0=*/0, /*Idx1=*/0);
- MapTypesArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.Int64Ty, Info.NumberOfPtrs),
- Options.ForEndCall && Info.MapTypesArrayEnd ? Info.MapTypesArrayEnd
- : Info.MapTypesArray,
- /*Idx0=*/0,
- /*Idx1=*/0);
-
- // Only emit the mapper information arrays if debug information is
- // requested.
- if (CGF.CGM.getCodeGenOpts().getDebugInfo() == codegenoptions::NoDebugInfo)
- MapNamesArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy);
- else
- MapNamesArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32(
- llvm::ArrayType::get(CGM.VoidPtrTy, Info.NumberOfPtrs),
- Info.MapNamesArray,
- /*Idx0=*/0,
- /*Idx1=*/0);
- // If there is no user-defined mapper, set the mapper array to nullptr to
- // avoid an unnecessary data privatization
- if (!Info.HasMapper)
- MappersArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy);
- else
- MappersArrayArg =
- CGF.Builder.CreatePointerCast(Info.MappersArray, CGM.VoidPtrPtrTy);
- } else {
- BasePointersArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy);
- PointersArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy);
- SizesArrayArg = llvm::ConstantPointerNull::get(CGM.Int64Ty->getPointerTo());
- MapTypesArrayArg =
- llvm::ConstantPointerNull::get(CGM.Int64Ty->getPointerTo());
- MapNamesArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy);
- MappersArrayArg = llvm::ConstantPointerNull::get(CGM.VoidPtrPtrTy);
- }
-}
-
/// Check for inner distribute directive.
static const OMPExecutableDirective *
getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
@@ -9999,7 +9579,9 @@ void CGOpenMPRuntime::emitUserDefinedMapper(const OMPDeclareMapperDecl *D,
: emitMappingInformation(MapperCGF, OMPBuilder, Info.Exprs[I]);
// Extract the MEMBER_OF field from the map type.
- llvm::Value *OriMapType = MapperCGF.Builder.getInt64(Info.Types[I]);
+ llvm::Value *OriMapType = MapperCGF.Builder.getInt64(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ Info.Types[I]));
llvm::Value *MemberMapType =
MapperCGF.Builder.CreateNUWAdd(OriMapType, ShiftedPreviousSize);
@@ -10017,8 +9599,10 @@ void CGOpenMPRuntime::emitUserDefinedMapper(const OMPDeclareMapperDecl *D,
// 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));
+ MapperCGF.Builder.getInt64(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ OpenMPOffloadMappingFlags::OMP_MAP_FROM)));
llvm::BasicBlock *AllocBB = MapperCGF.createBasicBlock("omp.type.alloc");
llvm::BasicBlock *AllocElseBB =
MapperCGF.createBasicBlock("omp.type.alloc.else");
@@ -10032,30 +9616,40 @@ void CGOpenMPRuntime::emitUserDefinedMapper(const OMPDeclareMapperDecl *D,
MapperCGF.EmitBlock(AllocBB);
llvm::Value *AllocMapType = MapperCGF.Builder.CreateAnd(
MemberMapType,
- MapperCGF.Builder.getInt64(~(MappableExprsHandler::OMP_MAP_TO |
- MappableExprsHandler::OMP_MAP_FROM)));
+ MapperCGF.Builder.getInt64(
+ ~static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ OpenMPOffloadMappingFlags::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.getInt64(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::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.getInt64(
+ ~static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::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.getInt64(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::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));
+ MapperCGF.Builder.getInt64(
+ ~static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_TO)));
// In case of tofrom, do nothing.
MapperCGF.EmitBlock(EndBB);
LastBB = EndBB;
@@ -10130,7 +9724,9 @@ void CGOpenMPRuntime::emitUDMapperArrayInitOrDel(
Size, MapperCGF.Builder.getInt64(1), "omp.arrayinit.isarray");
llvm::Value *DeleteBit = MapperCGF.Builder.CreateAnd(
MapType,
- MapperCGF.Builder.getInt64(MappableExprsHandler::OMP_MAP_DELETE));
+ MapperCGF.Builder.getInt64(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_DELETE)));
llvm::Value *DeleteCond;
llvm::Value *Cond;
if (IsInit) {
@@ -10139,7 +9735,9 @@ void CGOpenMPRuntime::emitUDMapperArrayInitOrDel(
// IsPtrAndObj?
llvm::Value *PtrAndObjBit = MapperCGF.Builder.CreateAnd(
MapType,
- MapperCGF.Builder.getInt64(MappableExprsHandler::OMP_MAP_PTR_AND_OBJ));
+ MapperCGF.Builder.getInt64(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ)));
PtrAndObjBit = MapperCGF.Builder.CreateIsNotNull(PtrAndObjBit);
BaseIsBegin = MapperCGF.Builder.CreateAnd(BaseIsBegin, PtrAndObjBit);
Cond = MapperCGF.Builder.CreateOr(IsArray, BaseIsBegin);
@@ -10162,11 +9760,15 @@ void CGOpenMPRuntime::emitUDMapperArrayInitOrDel(
// memory allocation/deletion purpose only.
llvm::Value *MapTypeArg = MapperCGF.Builder.CreateAnd(
MapType,
- MapperCGF.Builder.getInt64(~(MappableExprsHandler::OMP_MAP_TO |
- MappableExprsHandler::OMP_MAP_FROM)));
+ MapperCGF.Builder.getInt64(
+ ~static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ OpenMPOffloadMappingFlags::OMP_MAP_FROM)));
MapTypeArg = MapperCGF.Builder.CreateOr(
MapTypeArg,
- MapperCGF.Builder.getInt64(MappableExprsHandler::OMP_MAP_IMPLICIT));
+ MapperCGF.Builder.getInt64(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT)));
// Call the runtime API __tgt_push_mapper_component to fill up the runtime
// data structure.
@@ -10301,9 +9903,29 @@ void CGOpenMPRuntime::emitTargetCall(
llvm::Value *NumIterations =
emitTargetNumIterationsCall(CGF, D, SizeEmitter);
+ llvm::Value *DynCGroupMem = CGF.Builder.getInt32(0);
+ if (auto *DynMemClause = D.getSingleClause<OMPXDynCGroupMemClause>()) {
+ CodeGenFunction::RunCleanupsScope DynCGroupMemScope(CGF);
+ llvm::Value *DynCGroupMemVal = CGF.EmitScalarExpr(
+ DynMemClause->getSize(), /*IgnoreResultAssign=*/true);
+ DynCGroupMem = CGF.Builder.CreateIntCast(DynCGroupMemVal, CGF.Int32Ty,
+ /*isSigned=*/false);
+ }
+
+ llvm::Value *ZeroArray =
+ llvm::Constant::getNullValue(llvm::ArrayType::get(CGF.CGM.Int32Ty, 3));
+
+ bool HasNoWait = D.hasClausesOfKind<OMPNowaitClause>();
+ llvm::Value *Flags = CGF.Builder.getInt64(HasNoWait);
+
+ llvm::Value *NumTeams3D =
+ CGF.Builder.CreateInsertValue(ZeroArray, NumTeams, {0});
+ llvm::Value *NumThreads3D =
+ CGF.Builder.CreateInsertValue(ZeroArray, NumThreads, {0});
+
// Arguments for the target kernel.
SmallVector<llvm::Value *> KernelArgs{
- CGF.Builder.getInt32(/* Version */ 1),
+ CGF.Builder.getInt32(/* Version */ 2),
PointerNum,
InputInfo.BasePointersArray.getPointer(),
InputInfo.PointersArray.getPointer(),
@@ -10311,18 +9933,13 @@ void CGOpenMPRuntime::emitTargetCall(
MapTypesArray,
MapNamesArray,
InputInfo.MappersArray.getPointer(),
- NumIterations};
-
- // Arguments passed to the 'nowait' variant.
- SmallVector<llvm::Value *> NoWaitKernelArgs{
- CGF.Builder.getInt32(0),
- llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
- CGF.Builder.getInt32(0),
- llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
+ NumIterations,
+ Flags,
+ NumTeams3D,
+ NumThreads3D,
+ DynCGroupMem,
};
- bool HasNoWait = D.hasClausesOfKind<OMPNowaitClause>();
-
// The target region is an outlined function launched by the runtime
// via calls to __tgt_target_kernel().
//
@@ -10336,13 +9953,9 @@ void CGOpenMPRuntime::emitTargetCall(
// __tgt_target_teams() launches a GPU kernel with the requested number
// of teams and threads so no additional calls to the runtime are required.
// Check the error code and execute the host version if required.
- CGF.Builder.restoreIP(
- HasNoWait ? OMPBuilder.emitTargetKernel(
- CGF.Builder, Return, RTLoc, DeviceID, NumTeams,
- NumThreads, OutlinedFnID, KernelArgs, NoWaitKernelArgs)
- : OMPBuilder.emitTargetKernel(CGF.Builder, Return, RTLoc,
- DeviceID, NumTeams, NumThreads,
- OutlinedFnID, KernelArgs));
+ CGF.Builder.restoreIP(OMPBuilder.emitTargetKernel(
+ CGF.Builder, Return, RTLoc, DeviceID, NumTeams, NumThreads,
+ OutlinedFnID, KernelArgs));
llvm::BasicBlock *OffloadFailedBlock =
CGF.createBasicBlock("omp_offload.failed");
@@ -10392,9 +10005,10 @@ void CGOpenMPRuntime::emitTargetCall(
CurInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
CGF.getTypeSize(RI->getType()), CGF.Int64Ty, /*isSigned=*/true));
// Copy to the device as an argument. No need to retrieve it.
- CurInfo.Types.push_back(MappableExprsHandler::OMP_MAP_LITERAL |
- MappableExprsHandler::OMP_MAP_TARGET_PARAM |
- MappableExprsHandler::OMP_MAP_IMPLICIT);
+ CurInfo.Types.push_back(
+ OpenMPOffloadMappingFlags::OMP_MAP_LITERAL |
+ OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM |
+ OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
CurInfo.Mappers.push_back(nullptr);
} else {
// If we have any information in the map clause, we use it, otherwise we
@@ -10441,25 +10055,26 @@ void CGOpenMPRuntime::emitTargetCall(
// weren't referenced within the construct.
MEHandler.generateAllInfo(CombinedInfo, MappedVarSet);
- TargetDataInfo Info;
+ CGOpenMPRuntime::TargetDataInfo Info;
// Fill up the arrays and create the arguments.
emitOffloadingArrays(CGF, CombinedInfo, Info, OMPBuilder);
- emitOffloadingArraysArgument(
- CGF, Info.BasePointersArray, Info.PointersArray, Info.SizesArray,
- Info.MapTypesArray, Info.MapNamesArray, Info.MappersArray, Info,
- {/*ForEndCall=*/false});
+ bool EmitDebug =
+ CGF.CGM.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo;
+ OMPBuilder.emitOffloadingArraysArgument(CGF.Builder, Info.RTArgs, Info,
+ EmitDebug,
+ /*ForEndCall=*/false);
InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
- InputInfo.BasePointersArray =
- Address(Info.BasePointersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
- InputInfo.PointersArray =
- Address(Info.PointersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
+ InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray,
+ CGF.VoidPtrTy, CGM.getPointerAlign());
+ InputInfo.PointersArray = Address(Info.RTArgs.PointersArray, CGF.VoidPtrTy,
+ CGM.getPointerAlign());
InputInfo.SizesArray =
- Address(Info.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
+ Address(Info.RTArgs.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
InputInfo.MappersArray =
- Address(Info.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
- MapTypesArray = Info.MapTypesArray;
- MapNamesArray = Info.MapNamesArray;
+ Address(Info.RTArgs.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
+ MapTypesArray = Info.RTArgs.MapTypesArray;
+ MapNamesArray = Info.RTArgs.MapNamesArray;
if (RequiresOuterTask)
CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
else
@@ -10506,16 +10121,12 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
if (RequiresDeviceCodegen) {
const auto &E = *cast<OMPExecutableDirective>(S);
- unsigned DeviceID;
- unsigned FileID;
- unsigned Line;
- getTargetEntryUniqueInfo(CGM.getContext(), E.getBeginLoc(), DeviceID,
- FileID, Line);
+ auto EntryInfo =
+ getTargetEntryUniqueInfo(CGM.getContext(), E.getBeginLoc(), ParentName);
// Is this a target region that should not be emitted as an entry point? If
// so just signal we are done with this target region.
- if (!OffloadEntriesInfoManager.hasTargetRegionEntryInfo(DeviceID, FileID,
- ParentName, Line))
+ if (!OffloadEntriesInfoManager.hasTargetRegionEntryInfo(EntryInfo))
return;
switch (E.getDirectiveKind()) {
@@ -10645,7 +10256,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
}
static bool isAssumedToBeNotEmitted(const ValueDecl *VD, bool IsDevice) {
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(VD);
if (!DevTy)
return false;
@@ -10710,11 +10321,12 @@ bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) {
}
// Do not to emit variable if it is not marked as declare target.
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
cast<VarDecl>(GD.getDecl()));
if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link ||
- (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
HasRequiresUnifiedSharedMemory)) {
DeferredGlobalVariables.insert(cast<VarDecl>(GD.getDecl()));
return true;
@@ -10729,12 +10341,12 @@ void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD,
return;
// If we have host/nohost variables, they do not need to be registered.
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(VD);
if (DevTy && *DevTy != OMPDeclareTargetDeclAttr::DT_Any)
return;
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!Res) {
if (CGM.getLangOpts().OpenMPIsDevice) {
@@ -10746,20 +10358,22 @@ void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD,
return;
}
// Register declare target variables.
- OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind Flags;
+ llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryKind Flags;
StringRef VarName;
- CharUnits VarSize;
+ int64_t VarSize;
llvm::GlobalValue::LinkageTypes Linkage;
- if (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ if ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
!HasRequiresUnifiedSharedMemory) {
- Flags = OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryTo;
+ Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo;
VarName = CGM.getMangledName(VD);
if (VD->hasDefinition(CGM.getContext()) != VarDecl::DeclarationOnly) {
- VarSize = CGM.getContext().getTypeSizeInChars(VD->getType());
- assert(!VarSize.isZero() && "Expected non-zero size of the variable");
+ VarSize =
+ CGM.getContext().getTypeSizeInChars(VD->getType()).getQuantity();
+ assert(VarSize != 0 && "Expected non-zero size of the variable");
} else {
- VarSize = CharUnits::Zero();
+ VarSize = 0;
}
Linkage = CGM.getLLVMLinkageVarDefinition(VD, /*IsConstant=*/false);
// Temp solution to prevent optimizations of the internal variables.
@@ -10771,7 +10385,7 @@ void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD,
std::string RefName = getName({VarName, "ref"});
if (!CGM.GetGlobalValue(RefName)) {
llvm::Constant *AddrRef =
- getOrCreateInternalVariable(Addr->getType(), RefName);
+ OMPBuilder.getOrCreateInternalVariable(Addr->getType(), RefName);
auto *GVAddrRef = cast<llvm::GlobalVariable>(AddrRef);
GVAddrRef->setConstant(/*Val=*/true);
GVAddrRef->setLinkage(llvm::GlobalValue::InternalLinkage);
@@ -10781,13 +10395,14 @@ void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD,
}
} else {
assert(((*Res == OMPDeclareTargetDeclAttr::MT_Link) ||
- (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
HasRequiresUnifiedSharedMemory)) &&
"Declare target attribute must link or to with unified memory.");
if (*Res == OMPDeclareTargetDeclAttr::MT_Link)
- Flags = OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryLink;
+ Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink;
else
- Flags = OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryTo;
+ Flags = llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryTo;
if (CGM.getLangOpts().OpenMPIsDevice) {
VarName = Addr->getName();
@@ -10796,7 +10411,7 @@ void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD,
VarName = getAddrOfDeclareTargetVar(VD).getName();
Addr = cast<llvm::Constant>(getAddrOfDeclareTargetVar(VD).getPointer());
}
- VarSize = CGM.getPointerSize();
+ VarSize = CGM.getPointerSize().getQuantity();
Linkage = llvm::GlobalValue::WeakAnyLinkage;
}
@@ -10814,16 +10429,18 @@ bool CGOpenMPRuntime::emitTargetGlobal(GlobalDecl GD) {
void CGOpenMPRuntime::emitDeferredTargetDecls() const {
for (const VarDecl *VD : DeferredGlobalVariables) {
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!Res)
continue;
- if (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ if ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
!HasRequiresUnifiedSharedMemory) {
CGM.EmitGlobal(VD);
} else {
assert((*Res == OMPDeclareTargetDeclAttr::MT_Link ||
- (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
HasRequiresUnifiedSharedMemory)) &&
"Expected link clause or to clause with unified memory.");
(void)CGM.getOpenMPRuntime().getAddrOfDeclareTargetVar(VD);
@@ -10841,6 +10458,7 @@ void CGOpenMPRuntime::processRequiresDirective(const OMPRequiresDecl *D) {
for (const OMPClause *Clause : D->clauselists()) {
if (Clause->getClauseKind() == OMPC_unified_shared_memory) {
HasRequiresUnifiedSharedMemory = true;
+ OMPBuilder.Config.setHasRequiresUnifiedSharedMemory(true);
} else if (const auto *AC =
dyn_cast<OMPAtomicDefaultMemOrderClause>(Clause)) {
switch (AC->getAtomicDefaultMemOrderKind()) {
@@ -11025,7 +10643,8 @@ void CGOpenMPRuntime::emitNumTeamsClause(CodeGenFunction &CGF,
void CGOpenMPRuntime::emitTargetDataCalls(
CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
- const Expr *Device, const RegionCodeGenTy &CodeGen, TargetDataInfo &Info) {
+ const Expr *Device, const RegionCodeGenTy &CodeGen,
+ CGOpenMPRuntime::TargetDataInfo &Info) {
if (!CGF.HaveInsertPoint())
return;
@@ -11049,15 +10668,11 @@ void CGOpenMPRuntime::emitTargetDataCalls(
emitOffloadingArrays(CGF, CombinedInfo, Info, OMPBuilder,
/*IsNonContiguous=*/true);
- llvm::Value *BasePointersArrayArg = nullptr;
- llvm::Value *PointersArrayArg = nullptr;
- llvm::Value *SizesArrayArg = nullptr;
- llvm::Value *MapTypesArrayArg = nullptr;
- llvm::Value *MapNamesArrayArg = nullptr;
- llvm::Value *MappersArrayArg = nullptr;
- emitOffloadingArraysArgument(CGF, BasePointersArrayArg, PointersArrayArg,
- SizesArrayArg, MapTypesArrayArg,
- MapNamesArrayArg, MappersArrayArg, Info);
+ llvm::OpenMPIRBuilder::TargetDataRTArgs RTArgs;
+ bool EmitDebug =
+ CGF.CGM.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo;
+ OMPBuilder.emitOffloadingArraysArgument(CGF.Builder, RTArgs, Info,
+ EmitDebug);
// Emit device ID if any.
llvm::Value *DeviceID = nullptr;
@@ -11077,12 +10692,12 @@ void CGOpenMPRuntime::emitTargetDataCalls(
llvm::Value *OffloadingArgs[] = {RTLoc,
DeviceID,
PointerNum,
- BasePointersArrayArg,
- PointersArrayArg,
- SizesArrayArg,
- MapTypesArrayArg,
- MapNamesArrayArg,
- MappersArrayArg};
+ RTArgs.BasePointersArray,
+ RTArgs.PointersArray,
+ RTArgs.SizesArray,
+ RTArgs.MapTypesArray,
+ RTArgs.MapNamesArray,
+ RTArgs.MappersArray};
CGF.EmitRuntimeCall(
OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___tgt_target_data_begin_mapper),
@@ -11099,16 +10714,12 @@ void CGOpenMPRuntime::emitTargetDataCalls(
PrePostActionTy &) {
assert(Info.isValid() && "Invalid data environment closing arguments.");
- llvm::Value *BasePointersArrayArg = nullptr;
- llvm::Value *PointersArrayArg = nullptr;
- llvm::Value *SizesArrayArg = nullptr;
- llvm::Value *MapTypesArrayArg = nullptr;
- llvm::Value *MapNamesArrayArg = nullptr;
- llvm::Value *MappersArrayArg = nullptr;
- emitOffloadingArraysArgument(CGF, BasePointersArrayArg, PointersArrayArg,
- SizesArrayArg, MapTypesArrayArg,
- MapNamesArrayArg, MappersArrayArg, Info,
- {/*ForEndCall=*/true});
+ llvm::OpenMPIRBuilder::TargetDataRTArgs RTArgs;
+ bool EmitDebug =
+ CGF.CGM.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo;
+ OMPBuilder.emitOffloadingArraysArgument(CGF.Builder, RTArgs, Info,
+ EmitDebug,
+ /*ForEndCall=*/true);
// Emit device ID if any.
llvm::Value *DeviceID = nullptr;
@@ -11128,12 +10739,12 @@ void CGOpenMPRuntime::emitTargetDataCalls(
llvm::Value *OffloadingArgs[] = {RTLoc,
DeviceID,
PointerNum,
- BasePointersArrayArg,
- PointersArrayArg,
- SizesArrayArg,
- MapTypesArrayArg,
- MapNamesArrayArg,
- MappersArrayArg};
+ RTArgs.BasePointersArray,
+ RTArgs.PointersArray,
+ RTArgs.SizesArray,
+ RTArgs.MapTypesArray,
+ RTArgs.MapNamesArray,
+ RTArgs.MappersArray};
CGF.EmitRuntimeCall(
OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___tgt_target_data_end_mapper),
@@ -11322,27 +10933,28 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
MappableExprsHandler MEHandler(D, CGF);
MEHandler.generateAllInfo(CombinedInfo);
- TargetDataInfo Info;
+ CGOpenMPRuntime::TargetDataInfo Info;
// Fill up the arrays and create the arguments.
emitOffloadingArrays(CGF, CombinedInfo, Info, OMPBuilder,
/*IsNonContiguous=*/true);
bool RequiresOuterTask = D.hasClausesOfKind<OMPDependClause>() ||
D.hasClausesOfKind<OMPNowaitClause>();
- emitOffloadingArraysArgument(
- CGF, Info.BasePointersArray, Info.PointersArray, Info.SizesArray,
- Info.MapTypesArray, Info.MapNamesArray, Info.MappersArray, Info,
- {/*ForEndCall=*/false});
+ bool EmitDebug =
+ CGF.CGM.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo;
+ OMPBuilder.emitOffloadingArraysArgument(CGF.Builder, Info.RTArgs, Info,
+ EmitDebug,
+ /*ForEndCall=*/false);
InputInfo.NumberOfTargetItems = Info.NumberOfPtrs;
- InputInfo.BasePointersArray =
- Address(Info.BasePointersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
- InputInfo.PointersArray =
- Address(Info.PointersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
+ InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray,
+ CGF.VoidPtrTy, CGM.getPointerAlign());
+ InputInfo.PointersArray = Address(Info.RTArgs.PointersArray, CGF.VoidPtrTy,
+ CGM.getPointerAlign());
InputInfo.SizesArray =
- Address(Info.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
+ Address(Info.RTArgs.SizesArray, CGF.Int64Ty, CGM.getPointerAlign());
InputInfo.MappersArray =
- Address(Info.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
- MapTypesArray = Info.MapTypesArray;
- MapNamesArray = Info.MapNamesArray;
+ Address(Info.RTArgs.MappersArray, CGF.VoidPtrTy, CGM.getPointerAlign());
+ MapTypesArray = Info.RTArgs.MapTypesArray;
+ MapNamesArray = Info.RTArgs.MapNamesArray;
if (RequiresOuterTask)
CGF.EmitOMPTargetTaskBasedDirective(D, ThenGen, InputInfo);
else
@@ -11937,7 +11549,7 @@ void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD,
if (CGM.getTarget().hasFeature("sve"))
emitAArch64DeclareSimdFunction(CGM, FD, VLEN, ParamAttrs, State,
MangledName, 's', 128, Fn, ExprLoc);
- if (CGM.getTarget().hasFeature("neon"))
+ else if (CGM.getTarget().hasFeature("neon"))
emitAArch64DeclareSimdFunction(CGM, FD, VLEN, ParamAttrs, State,
MangledName, 'n', 128, Fn, ExprLoc);
}
@@ -12039,7 +11651,7 @@ void CGOpenMPRuntime::emitDoacrossInit(CodeGenFunction &CGF,
llvm::FunctionCallee FiniRTLFn = OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_doacross_fini);
CGF.EHStack.pushCleanup<DoacrossCleanupTy>(NormalAndEHCleanup, FiniRTLFn,
- llvm::makeArrayRef(FiniArgs));
+ llvm::ArrayRef(FiniArgs));
}
void CGOpenMPRuntime::emitDoacrossOrdered(CodeGenFunction &CGF,
@@ -12130,7 +11742,7 @@ static llvm::Value *getAllocatorVal(CodeGenFunction &CGF,
/// Return the alignment from an allocate directive if present.
static llvm::Value *getAlignmentValue(CodeGenModule &CGM, const VarDecl *VD) {
- llvm::Optional<CharUnits> AllocateAlignment = CGM.getOMPAllocateAlignment(VD);
+ std::optional<CharUnits> AllocateAlignment = CGM.getOMPAllocateAlignment(VD);
if (!AllocateAlignment)
return nullptr;
@@ -12570,15 +12182,15 @@ void CGOpenMPRuntime::emitLastprivateConditionalUpdate(CodeGenFunction &CGF,
// Last updated loop counter for the lastprivate conditional var.
// int<xx> last_iv = 0;
llvm::Type *LLIVTy = CGF.ConvertTypeForMem(IVLVal.getType());
- llvm::Constant *LastIV =
- getOrCreateInternalVariable(LLIVTy, getName({UniqueDeclName, "iv"}));
+ llvm::Constant *LastIV = OMPBuilder.getOrCreateInternalVariable(
+ LLIVTy, getName({UniqueDeclName, "iv"}));
cast<llvm::GlobalVariable>(LastIV)->setAlignment(
IVLVal.getAlignment().getAsAlign());
LValue LastIVLVal = CGF.MakeNaturalAlignAddrLValue(LastIV, IVLVal.getType());
// Last value of the lastprivate conditional.
// decltype(priv_a) last_a;
- llvm::GlobalVariable *Last = getOrCreateInternalVariable(
+ llvm::GlobalVariable *Last = OMPBuilder.getOrCreateInternalVariable(
CGF.ConvertTypeForMem(LVal.getType()), UniqueDeclName);
Last->setAlignment(LVal.getAlignment().getAsAlign());
LValue LastLVal = CGF.MakeAddrLValue(
@@ -13037,7 +12649,8 @@ void CGOpenMPSIMDRuntime::emitNumTeamsClause(CodeGenFunction &CGF,
void CGOpenMPSIMDRuntime::emitTargetDataCalls(
CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *IfCond,
- const Expr *Device, const RegionCodeGenTy &CodeGen, TargetDataInfo &Info) {
+ const Expr *Device, const RegionCodeGenTy &CodeGen,
+ CGOpenMPRuntime::TargetDataInfo &Info) {
llvm_unreachable("Not supported in SIMD-only mode");
}
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h
index b95aef68335e..e7c1a098c768 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -121,6 +121,7 @@ struct OMPTaskDataTy final {
bool Nogroup = false;
bool IsReductionWithTaskMod = false;
bool IsWorksharingReduction = false;
+ bool HasNowaitClause = false;
};
/// Class intended to support codegen of all kind of the reduction clauses.
@@ -306,21 +307,10 @@ public:
protected:
CodeGenModule &CGM;
- StringRef FirstSeparator, Separator;
/// An OpenMP-IR-Builder instance.
llvm::OpenMPIRBuilder OMPBuilder;
- /// Constructor allowing to redefine the name separator for the variables.
- explicit CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator,
- StringRef Separator);
-
- /// Creates offloading entry for the provided entry ID \a ID,
- /// address \a Addr, size \a Size, and flags \a Flags.
- virtual void createOffloadEntry(llvm::Constant *ID, llvm::Constant *Addr,
- uint64_t Size, int32_t Flags,
- llvm::GlobalValue::LinkageTypes Linkage);
-
/// Helper to emit outlined function for 'target' directive.
/// \param D Directive to emit.
/// \param ParentName Name of the function that encloses the target region.
@@ -339,9 +329,10 @@ protected:
/// Emits object of ident_t type with info for source location.
/// \param Flags Flags for OpenMP location.
+ /// \param EmitLoc emit source location with debug-info is off.
///
llvm::Value *emitUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
- unsigned Flags = 0);
+ unsigned Flags = 0, bool EmitLoc = false);
/// Emit the number of teams for a target directive. Inspect the num_teams
/// clause associated with a teams construct combined or closely nested
@@ -387,7 +378,7 @@ protected:
/// Emits \p Callee function call with arguments \p Args with location \p Loc.
void emitCall(CodeGenFunction &CGF, SourceLocation Loc,
llvm::FunctionCallee Callee,
- ArrayRef<llvm::Value *> Args = llvm::None) const;
+ ArrayRef<llvm::Value *> Args = std::nullopt) const;
/// Emits address of the word in a memory where current thread id is
/// stored.
@@ -419,8 +410,7 @@ protected:
///
llvm::Value *getCriticalRegionLock(StringRef CriticalName);
-private:
-
+protected:
/// Map for SourceLocation and OpenMP runtime library debug locations.
typedef llvm::DenseMap<SourceLocation, llvm::Value *> OpenMPDebugLocMapTy;
OpenMPDebugLocMapTy OpenMPDebugLocMap;
@@ -520,214 +510,7 @@ private:
QualType KmpDimTy;
/// Entity that registers the offloading constants that were emitted so
/// far.
- class OffloadEntriesInfoManagerTy {
- CodeGenModule &CGM;
-
- /// Number of entries registered so far.
- unsigned OffloadingEntriesNum = 0;
-
- public:
- /// Base class of the entries info.
- class OffloadEntryInfo {
- public:
- /// Kind of a given entry.
- enum OffloadingEntryInfoKinds : unsigned {
- /// Entry is a target region.
- OffloadingEntryInfoTargetRegion = 0,
- /// Entry is a declare target variable.
- OffloadingEntryInfoDeviceGlobalVar = 1,
- /// Invalid entry info.
- OffloadingEntryInfoInvalid = ~0u
- };
-
- protected:
- OffloadEntryInfo() = delete;
- explicit OffloadEntryInfo(OffloadingEntryInfoKinds Kind) : Kind(Kind) {}
- explicit OffloadEntryInfo(OffloadingEntryInfoKinds Kind, unsigned Order,
- uint32_t Flags)
- : Flags(Flags), Order(Order), Kind(Kind) {}
- ~OffloadEntryInfo() = default;
-
- public:
- bool isValid() const { return Order != ~0u; }
- unsigned getOrder() const { return Order; }
- OffloadingEntryInfoKinds getKind() const { return Kind; }
- uint32_t getFlags() const { return Flags; }
- void setFlags(uint32_t NewFlags) { Flags = NewFlags; }
- llvm::Constant *getAddress() const {
- return cast_or_null<llvm::Constant>(Addr);
- }
- void setAddress(llvm::Constant *V) {
- assert(!Addr.pointsToAliveValue() && "Address has been set before!");
- Addr = V;
- }
- static bool classof(const OffloadEntryInfo *Info) { return true; }
-
- private:
- /// Address of the entity that has to be mapped for offloading.
- llvm::WeakTrackingVH Addr;
-
- /// Flags associated with the device global.
- uint32_t Flags = 0u;
-
- /// Order this entry was emitted.
- unsigned Order = ~0u;
-
- OffloadingEntryInfoKinds Kind = OffloadingEntryInfoInvalid;
- };
-
- /// Return true if a there are no entries defined.
- bool empty() const;
- /// Return number of entries defined so far.
- unsigned size() const { return OffloadingEntriesNum; }
- OffloadEntriesInfoManagerTy(CodeGenModule &CGM) : CGM(CGM) {}
-
- //
- // Target region entries related.
- //
-
- /// Kind of the target registry entry.
- enum OMPTargetRegionEntryKind : uint32_t {
- /// Mark the entry as target region.
- OMPTargetRegionEntryTargetRegion = 0x0,
- /// Mark the entry as a global constructor.
- OMPTargetRegionEntryCtor = 0x02,
- /// Mark the entry as a global destructor.
- OMPTargetRegionEntryDtor = 0x04,
- };
-
- /// Target region entries info.
- class OffloadEntryInfoTargetRegion final : public OffloadEntryInfo {
- /// Address that can be used as the ID of the entry.
- llvm::Constant *ID = nullptr;
-
- public:
- OffloadEntryInfoTargetRegion()
- : OffloadEntryInfo(OffloadingEntryInfoTargetRegion) {}
- explicit OffloadEntryInfoTargetRegion(unsigned Order,
- llvm::Constant *Addr,
- llvm::Constant *ID,
- OMPTargetRegionEntryKind Flags)
- : OffloadEntryInfo(OffloadingEntryInfoTargetRegion, Order, Flags),
- ID(ID) {
- setAddress(Addr);
- }
-
- llvm::Constant *getID() const { return ID; }
- void setID(llvm::Constant *V) {
- assert(!ID && "ID has been set before!");
- ID = V;
- }
- static bool classof(const OffloadEntryInfo *Info) {
- return Info->getKind() == OffloadingEntryInfoTargetRegion;
- }
- };
-
- /// Initialize target region entry.
- void initializeTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- unsigned Order);
- /// Register target region entry.
- void registerTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- llvm::Constant *Addr, llvm::Constant *ID,
- OMPTargetRegionEntryKind Flags);
- /// Return true if a target region entry with the provided information
- /// exists.
- bool hasTargetRegionEntryInfo(unsigned DeviceID, unsigned FileID,
- StringRef ParentName, unsigned LineNum,
- bool IgnoreAddressId = false) const;
- /// brief Applies action \a Action on all registered entries.
- typedef llvm::function_ref<void(unsigned, unsigned, StringRef, unsigned,
- const OffloadEntryInfoTargetRegion &)>
- OffloadTargetRegionEntryInfoActTy;
- void actOnTargetRegionEntriesInfo(
- const OffloadTargetRegionEntryInfoActTy &Action);
-
- //
- // Device global variable entries related.
- //
-
- /// Kind of the global variable entry..
- enum OMPTargetGlobalVarEntryKind : uint32_t {
- /// Mark the entry as a to declare target.
- OMPTargetGlobalVarEntryTo = 0x0,
- /// Mark the entry as a to declare target link.
- OMPTargetGlobalVarEntryLink = 0x1,
- };
-
- /// Device global variable entries info.
- class OffloadEntryInfoDeviceGlobalVar final : public OffloadEntryInfo {
- /// Type of the global variable.
- CharUnits VarSize;
- llvm::GlobalValue::LinkageTypes Linkage;
-
- public:
- OffloadEntryInfoDeviceGlobalVar()
- : OffloadEntryInfo(OffloadingEntryInfoDeviceGlobalVar) {}
- explicit OffloadEntryInfoDeviceGlobalVar(unsigned Order,
- OMPTargetGlobalVarEntryKind Flags)
- : OffloadEntryInfo(OffloadingEntryInfoDeviceGlobalVar, Order, Flags) {}
- explicit OffloadEntryInfoDeviceGlobalVar(
- unsigned Order, llvm::Constant *Addr, CharUnits VarSize,
- OMPTargetGlobalVarEntryKind Flags,
- llvm::GlobalValue::LinkageTypes Linkage)
- : OffloadEntryInfo(OffloadingEntryInfoDeviceGlobalVar, Order, Flags),
- VarSize(VarSize), Linkage(Linkage) {
- setAddress(Addr);
- }
-
- CharUnits getVarSize() const { return VarSize; }
- void setVarSize(CharUnits Size) { VarSize = Size; }
- llvm::GlobalValue::LinkageTypes getLinkage() const { return Linkage; }
- void setLinkage(llvm::GlobalValue::LinkageTypes LT) { Linkage = LT; }
- static bool classof(const OffloadEntryInfo *Info) {
- return Info->getKind() == OffloadingEntryInfoDeviceGlobalVar;
- }
- };
-
- /// Initialize device global variable entry.
- void initializeDeviceGlobalVarEntryInfo(StringRef Name,
- OMPTargetGlobalVarEntryKind Flags,
- unsigned Order);
-
- /// Register device global variable entry.
- void
- registerDeviceGlobalVarEntryInfo(StringRef VarName, llvm::Constant *Addr,
- CharUnits VarSize,
- OMPTargetGlobalVarEntryKind Flags,
- llvm::GlobalValue::LinkageTypes Linkage);
- /// Checks if the variable with the given name has been registered already.
- bool hasDeviceGlobalVarEntryInfo(StringRef VarName) const {
- return OffloadEntriesDeviceGlobalVar.count(VarName) > 0;
- }
- /// Applies action \a Action on all registered entries.
- typedef llvm::function_ref<void(StringRef,
- const OffloadEntryInfoDeviceGlobalVar &)>
- OffloadDeviceGlobalVarEntryInfoActTy;
- void actOnDeviceGlobalVarEntriesInfo(
- const OffloadDeviceGlobalVarEntryInfoActTy &Action);
-
- private:
- // Storage for target region entries kind. The storage is to be indexed by
- // file ID, device ID, parent function name and line number.
- typedef llvm::DenseMap<unsigned, OffloadEntryInfoTargetRegion>
- OffloadEntriesTargetRegionPerLine;
- typedef llvm::StringMap<OffloadEntriesTargetRegionPerLine>
- OffloadEntriesTargetRegionPerParentName;
- typedef llvm::DenseMap<unsigned, OffloadEntriesTargetRegionPerParentName>
- OffloadEntriesTargetRegionPerFile;
- typedef llvm::DenseMap<unsigned, OffloadEntriesTargetRegionPerFile>
- OffloadEntriesTargetRegionPerDevice;
- typedef OffloadEntriesTargetRegionPerDevice OffloadEntriesTargetRegionTy;
- OffloadEntriesTargetRegionTy OffloadEntriesTargetRegion;
- /// Storage for device global variable entries kind. The storage is to be
- /// indexed by mangled name.
- typedef llvm::StringMap<OffloadEntryInfoDeviceGlobalVar>
- OffloadEntriesDeviceGlobalVarTy;
- OffloadEntriesDeviceGlobalVarTy OffloadEntriesDeviceGlobalVar;
- };
- OffloadEntriesInfoManagerTy OffloadEntriesInfoManager;
+ llvm::OffloadEntriesInfoManager OffloadEntriesInfoManager;
bool ShouldMarkAsGlobal = true;
/// List of the emitted declarations.
@@ -773,7 +556,7 @@ private:
/// metadata.
void loadOffloadInfoMetadata();
- /// Start scanning from statement \a S and and emit all target regions
+ /// Start scanning from statement \a S and emit all target regions
/// found along the way.
/// \param S Starting statement.
/// \param ParentName Name of the function declaration that is being scanned.
@@ -814,16 +597,6 @@ private:
/// \return Cache variable for the specified threadprivate.
llvm::Constant *getOrCreateThreadPrivateCache(const VarDecl *VD);
- /// Gets (if variable with the given name already exist) or creates
- /// internal global variable with the specified Name. The created variable has
- /// linkage CommonLinkage by default and is initialized by null value.
- /// \param Ty Type of the global variable. If it is exist already the type
- /// must be the same.
- /// \param Name Name of the variable.
- llvm::GlobalVariable *getOrCreateInternalVariable(llvm::Type *Ty,
- const llvm::Twine &Name,
- unsigned AddressSpace = 0);
-
/// Set of threadprivate variables with the generated initializer.
llvm::StringSet<> ThreadPrivateWithDefinition;
@@ -915,11 +688,13 @@ private:
Address DependenciesArray);
public:
- explicit CGOpenMPRuntime(CodeGenModule &CGM)
- : CGOpenMPRuntime(CGM, ".", ".") {}
+ explicit CGOpenMPRuntime(CodeGenModule &CGM);
virtual ~CGOpenMPRuntime() {}
virtual void clear();
+ /// Returns true if the current target is a GPU.
+ virtual bool isTargetCodegen() const { return false; }
+
/// Emits code for OpenMP 'if' clause using specified \a CodeGen
/// function. Here is the logic:
/// if (Cond) {
@@ -1048,6 +823,11 @@ public:
/// Emits code for a taskyield directive.
virtual void emitTaskyieldCall(CodeGenFunction &CGF, SourceLocation Loc);
+ /// Emit __kmpc_error call for error directive
+ /// extern void __kmpc_error(ident_t *loc, int severity, const char *message);
+ virtual void emitErrorCall(CodeGenFunction &CGF, SourceLocation Loc, Expr *ME,
+ bool IsFatal);
+
/// Emit a taskgroup region.
/// \param TaskgroupOpGen Generator for the statement associated with the
/// given taskgroup region.
@@ -1654,65 +1434,16 @@ public:
/// Struct that keeps all the relevant information that should be kept
/// throughout a 'target data' region.
- class TargetDataInfo {
- /// Set to true if device pointer information have to be obtained.
- bool RequiresDevicePointerInfo = false;
- /// Set to true if Clang emits separate runtime calls for the beginning and
- /// end of the region. These calls might have separate map type arrays.
- bool SeparateBeginEndCalls = false;
-
+ class TargetDataInfo : public llvm::OpenMPIRBuilder::TargetDataInfo {
public:
- /// The array of base pointer passed to the runtime library.
- llvm::Value *BasePointersArray = nullptr;
- /// The array of section pointers passed to the runtime library.
- llvm::Value *PointersArray = nullptr;
- /// The array of sizes passed to the runtime library.
- llvm::Value *SizesArray = nullptr;
- /// The array of map types passed to the runtime library for the beginning
- /// of the region or for the entire region if there are no separate map
- /// types for the region end.
- llvm::Value *MapTypesArray = nullptr;
- /// The array of map types passed to the runtime library for the end of the
- /// region, or nullptr if there are no separate map types for the region
- /// end.
- llvm::Value *MapTypesArrayEnd = nullptr;
- /// The array of user-defined mappers passed to the runtime library.
- llvm::Value *MappersArray = nullptr;
- /// The array of original declaration names of mapped pointers sent to the
- /// runtime library for debugging
- llvm::Value *MapNamesArray = nullptr;
- /// Indicate whether any user-defined mapper exists.
- bool HasMapper = false;
- /// The total number of pointers passed to the runtime library.
- unsigned NumberOfPtrs = 0u;
+ explicit TargetDataInfo() : llvm::OpenMPIRBuilder::TargetDataInfo() {}
+ explicit TargetDataInfo(bool RequiresDevicePointerInfo,
+ bool SeparateBeginEndCalls)
+ : llvm::OpenMPIRBuilder::TargetDataInfo(RequiresDevicePointerInfo,
+ SeparateBeginEndCalls) {}
/// Map between the a declaration of a capture and the corresponding base
/// pointer address where the runtime returns the device pointers.
llvm::DenseMap<const ValueDecl *, Address> CaptureDeviceAddrMap;
-
- explicit TargetDataInfo() {}
- explicit TargetDataInfo(bool RequiresDevicePointerInfo,
- bool SeparateBeginEndCalls)
- : RequiresDevicePointerInfo(RequiresDevicePointerInfo),
- SeparateBeginEndCalls(SeparateBeginEndCalls) {}
- /// Clear information about the data arrays.
- void clearArrayInfo() {
- BasePointersArray = nullptr;
- PointersArray = nullptr;
- SizesArray = nullptr;
- MapTypesArray = nullptr;
- MapTypesArrayEnd = nullptr;
- MapNamesArray = nullptr;
- MappersArray = nullptr;
- HasMapper = false;
- NumberOfPtrs = 0u;
- }
- /// Return true if the current target data information has valid arrays.
- bool isValid() {
- return BasePointersArray && PointersArray && SizesArray &&
- MapTypesArray && (!HasMapper || MappersArray) && NumberOfPtrs;
- }
- bool requiresDevicePointerInfo() { return RequiresDevicePointerInfo; }
- bool separateBeginEndCalls() { return SeparateBeginEndCalls; }
};
/// Emit the target data mapping code associated with \a D.
@@ -1727,7 +1458,7 @@ public:
const OMPExecutableDirective &D,
const Expr *IfCond, const Expr *Device,
const RegionCodeGenTy &CodeGen,
- TargetDataInfo &Info);
+ CGOpenMPRuntime::TargetDataInfo &Info);
/// Emit the data mapping/movement code associated with the directive
/// \a D that should be of the form 'target [{enter|exit} data | update]'.
@@ -1792,7 +1523,7 @@ public:
virtual void
emitOutlinedFunctionCall(CodeGenFunction &CGF, SourceLocation Loc,
llvm::FunctionCallee OutlinedFn,
- ArrayRef<llvm::Value *> Args = llvm::None) const;
+ ArrayRef<llvm::Value *> Args = std::nullopt) const;
/// Emits OpenMP-specific function prolog.
/// Required for device constructs.
@@ -2487,7 +2218,7 @@ public:
void emitTargetDataCalls(CodeGenFunction &CGF,
const OMPExecutableDirective &D, const Expr *IfCond,
const Expr *Device, const RegionCodeGenTy &CodeGen,
- TargetDataInfo &Info) override;
+ CGOpenMPRuntime::TargetDataInfo &Info) override;
/// Emit the data mapping/movement code associated with the directive
/// \a D that should be of the form 'target [{enter|exit} data | update]'.
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
index 6dea846f486f..e8c5f04db49f 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
@@ -15,6 +15,7 @@
#include "CodeGenFunction.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Cuda.h"
@@ -73,30 +74,15 @@ private:
CGOpenMPRuntimeGPU::ExecutionMode SavedExecMode =
CGOpenMPRuntimeGPU::EM_Unknown;
CGOpenMPRuntimeGPU::ExecutionMode &ExecMode;
- bool SavedRuntimeMode = false;
- bool *RuntimeMode = nullptr;
public:
- /// Constructor for Non-SPMD mode.
- ExecutionRuntimeModesRAII(CGOpenMPRuntimeGPU::ExecutionMode &ExecMode)
- : ExecMode(ExecMode) {
- SavedExecMode = ExecMode;
- ExecMode = CGOpenMPRuntimeGPU::EM_NonSPMD;
- }
- /// Constructor for SPMD mode.
ExecutionRuntimeModesRAII(CGOpenMPRuntimeGPU::ExecutionMode &ExecMode,
- bool &RuntimeMode, bool FullRuntimeMode)
- : ExecMode(ExecMode), RuntimeMode(&RuntimeMode) {
+ CGOpenMPRuntimeGPU::ExecutionMode EntryMode)
+ : ExecMode(ExecMode) {
SavedExecMode = ExecMode;
- SavedRuntimeMode = RuntimeMode;
- ExecMode = CGOpenMPRuntimeGPU::EM_SPMD;
- RuntimeMode = FullRuntimeMode;
- }
- ~ExecutionRuntimeModesRAII() {
- ExecMode = SavedExecMode;
- if (RuntimeMode)
- *RuntimeMode = SavedRuntimeMode;
+ ExecMode = EntryMode;
}
+ ~ExecutionRuntimeModesRAII() { ExecMode = SavedExecMode; }
};
/// GPU Configuration: This information can be derived from cuda registers,
@@ -109,9 +95,6 @@ enum MachineConfiguration : unsigned {
/// Global memory alignment for performance.
GlobalMemoryAlignment = 128,
-
- /// Maximal size of the shared memory buffer.
- SharedMemorySize = 128,
};
static const ValueDecl *getPrivateItem(const Expr *RefExpr) {
@@ -444,9 +427,8 @@ public:
markAsEscaped(VD);
if (isa<OMPCapturedExprDecl>(VD))
VisitValueDecl(VD);
- else if (const auto *VarD = dyn_cast<VarDecl>(VD))
- if (VarD->isInitCapture())
- VisitValueDecl(VD);
+ else if (VD->isInitCapture())
+ VisitValueDecl(VD);
}
void VisitUnaryOperator(const UnaryOperator *E) {
if (!E)
@@ -746,274 +728,13 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
"Unknown programming model for OpenMP directive on NVPTX target.");
}
-/// Check if the directive is loops based and has schedule clause at all or has
-/// static scheduling.
-static bool hasStaticScheduling(const OMPExecutableDirective &D) {
- assert(isOpenMPWorksharingDirective(D.getDirectiveKind()) &&
- isOpenMPLoopDirective(D.getDirectiveKind()) &&
- "Expected loop-based directive.");
- return !D.hasClausesOfKind<OMPOrderedClause>() &&
- (!D.hasClausesOfKind<OMPScheduleClause>() ||
- llvm::any_of(D.getClausesOfKind<OMPScheduleClause>(),
- [](const OMPScheduleClause *C) {
- return C->getScheduleKind() == OMPC_SCHEDULE_static;
- }));
-}
-
-/// Check for inner (nested) lightweight runtime construct, if any
-static bool hasNestedLightweightDirective(ASTContext &Ctx,
- const OMPExecutableDirective &D) {
- assert(supportsSPMDExecutionMode(Ctx, D) && "Expected SPMD mode directive.");
- const auto *CS = D.getInnermostCapturedStmt();
- const auto *Body =
- CS->getCapturedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true);
- const Stmt *ChildStmt = CGOpenMPRuntime::getSingleCompoundChild(Ctx, Body);
-
- if (const auto *NestedDir =
- dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
- OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
- switch (D.getDirectiveKind()) {
- case OMPD_target:
- if (isOpenMPParallelDirective(DKind) &&
- isOpenMPWorksharingDirective(DKind) && isOpenMPLoopDirective(DKind) &&
- hasStaticScheduling(*NestedDir))
- return true;
- if (DKind == OMPD_teams_distribute_simd || DKind == OMPD_simd)
- return true;
- if (DKind == OMPD_parallel) {
- Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = CGOpenMPRuntime::getSingleCompoundChild(Ctx, Body);
- if (const auto *NND =
- dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NND))
- return true;
- }
- } else if (DKind == OMPD_teams) {
- Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = CGOpenMPRuntime::getSingleCompoundChild(Ctx, Body);
- if (const auto *NND =
- dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPParallelDirective(DKind) &&
- isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NND))
- return true;
- if (DKind == OMPD_parallel) {
- Body = NND->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = CGOpenMPRuntime::getSingleCompoundChild(Ctx, Body);
- if (const auto *NND =
- dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NND))
- return true;
- }
- }
- }
- }
- return false;
- case OMPD_target_teams:
- if (isOpenMPParallelDirective(DKind) &&
- isOpenMPWorksharingDirective(DKind) && isOpenMPLoopDirective(DKind) &&
- hasStaticScheduling(*NestedDir))
- return true;
- if (DKind == OMPD_distribute_simd || DKind == OMPD_simd)
- return true;
- if (DKind == OMPD_parallel) {
- Body = NestedDir->getInnermostCapturedStmt()->IgnoreContainers(
- /*IgnoreCaptured=*/true);
- if (!Body)
- return false;
- ChildStmt = CGOpenMPRuntime::getSingleCompoundChild(Ctx, Body);
- if (const auto *NND =
- dyn_cast_or_null<OMPExecutableDirective>(ChildStmt)) {
- DKind = NND->getDirectiveKind();
- if (isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NND))
- return true;
- }
- }
- return false;
- case OMPD_target_parallel:
- if (DKind == OMPD_simd)
- return true;
- return isOpenMPWorksharingDirective(DKind) &&
- isOpenMPLoopDirective(DKind) && hasStaticScheduling(*NestedDir);
- case OMPD_target_teams_distribute:
- case OMPD_target_simd:
- case OMPD_target_parallel_for:
- case OMPD_target_parallel_for_simd:
- case OMPD_target_teams_distribute_simd:
- case OMPD_target_teams_distribute_parallel_for:
- case OMPD_target_teams_distribute_parallel_for_simd:
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_master:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_allocate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_depobj:
- case OMPD_scan:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_target_exit_data:
- case OMPD_target_enter_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_target_update:
- case OMPD_declare_simd:
- case OMPD_declare_variant:
- case OMPD_begin_declare_variant:
- case OMPD_end_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_parallel_master_taskloop_simd:
- case OMPD_requires:
- case OMPD_unknown:
- default:
- llvm_unreachable("Unexpected directive.");
- }
- }
-
- return false;
-}
-
-/// Checks if the construct supports lightweight runtime. It must be SPMD
-/// construct + inner loop-based construct with static scheduling.
-static bool supportsLightweightRuntime(ASTContext &Ctx,
- const OMPExecutableDirective &D) {
- if (!supportsSPMDExecutionMode(Ctx, D))
- return false;
- OpenMPDirectiveKind DirectiveKind = D.getDirectiveKind();
- switch (DirectiveKind) {
- case OMPD_target:
- case OMPD_target_teams:
- case OMPD_target_parallel:
- return hasNestedLightweightDirective(Ctx, D);
- 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:
- // (Last|First)-privates must be shared in parallel region.
- return hasStaticScheduling(D);
- case OMPD_target_simd:
- case OMPD_target_teams_distribute_simd:
- return true;
- case OMPD_target_teams_distribute:
- return false;
- case OMPD_parallel:
- case OMPD_for:
- case OMPD_parallel_for:
- case OMPD_parallel_master:
- case OMPD_parallel_sections:
- case OMPD_for_simd:
- case OMPD_parallel_for_simd:
- case OMPD_cancel:
- case OMPD_cancellation_point:
- case OMPD_ordered:
- case OMPD_threadprivate:
- case OMPD_allocate:
- case OMPD_task:
- case OMPD_simd:
- case OMPD_sections:
- case OMPD_section:
- case OMPD_single:
- case OMPD_master:
- case OMPD_critical:
- case OMPD_taskyield:
- case OMPD_barrier:
- case OMPD_taskwait:
- case OMPD_taskgroup:
- case OMPD_atomic:
- case OMPD_flush:
- case OMPD_depobj:
- case OMPD_scan:
- case OMPD_teams:
- case OMPD_target_data:
- case OMPD_target_exit_data:
- case OMPD_target_enter_data:
- case OMPD_distribute:
- case OMPD_distribute_simd:
- case OMPD_distribute_parallel_for:
- case OMPD_distribute_parallel_for_simd:
- case OMPD_teams_distribute:
- case OMPD_teams_distribute_simd:
- case OMPD_teams_distribute_parallel_for:
- case OMPD_teams_distribute_parallel_for_simd:
- case OMPD_target_update:
- case OMPD_declare_simd:
- case OMPD_declare_variant:
- case OMPD_begin_declare_variant:
- case OMPD_end_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_parallel_master_taskloop_simd:
- case OMPD_requires:
- case OMPD_unknown:
- default:
- break;
- }
- llvm_unreachable(
- "Unknown programming model for OpenMP directive on NVPTX target.");
-}
-
void CGOpenMPRuntimeGPU::emitNonSPMDKernel(const OMPExecutableDirective &D,
StringRef ParentName,
llvm::Function *&OutlinedFn,
llvm::Constant *&OutlinedFnID,
bool IsOffloadEntry,
const RegionCodeGenTy &CodeGen) {
- ExecutionRuntimeModesRAII ModeRAII(CurrentExecutionMode);
+ ExecutionRuntimeModesRAII ModeRAII(CurrentExecutionMode, EM_NonSPMD);
EntryFunctionState EST;
WrapperFunctionsMap.clear();
@@ -1048,8 +769,7 @@ void CGOpenMPRuntimeGPU::emitNonSPMDKernel(const OMPExecutableDirective &D,
void CGOpenMPRuntimeGPU::emitKernelInit(CodeGenFunction &CGF,
EntryFunctionState &EST, bool IsSPMD) {
CGBuilderTy &Bld = CGF.Builder;
- Bld.restoreIP(OMPBuilder.createTargetInit(Bld, IsSPMD, requiresFullRuntime()));
- IsInTargetMasterThreadRegion = IsSPMD;
+ Bld.restoreIP(OMPBuilder.createTargetInit(Bld, IsSPMD));
if (!IsSPMD)
emitGenericVarsProlog(CGF, EST.Loc);
}
@@ -1061,7 +781,7 @@ void CGOpenMPRuntimeGPU::emitKernelDeinit(CodeGenFunction &CGF,
emitGenericVarsEpilog(CGF);
CGBuilderTy &Bld = CGF.Builder;
- OMPBuilder.createTargetDeinit(Bld, IsSPMD, requiresFullRuntime());
+ OMPBuilder.createTargetDeinit(Bld, IsSPMD);
}
void CGOpenMPRuntimeGPU::emitSPMDKernel(const OMPExecutableDirective &D,
@@ -1070,10 +790,7 @@ void CGOpenMPRuntimeGPU::emitSPMDKernel(const OMPExecutableDirective &D,
llvm::Constant *&OutlinedFnID,
bool IsOffloadEntry,
const RegionCodeGenTy &CodeGen) {
- ExecutionRuntimeModesRAII ModeRAII(
- CurrentExecutionMode, RequiresFullRuntime,
- CGM.getLangOpts().OpenMPCUDAForceFullRuntime ||
- !supportsLightweightRuntime(CGM.getContext(), D));
+ ExecutionRuntimeModesRAII ModeRAII(CurrentExecutionMode, EM_SPMD);
EntryFunctionState EST;
// Emit target region as a standalone region.
@@ -1116,36 +833,10 @@ static void setPropertyExecutionMode(CodeGenModule &CGM, StringRef Name,
llvm::ConstantInt::get(CGM.Int8Ty, Mode ? OMP_TGT_EXEC_MODE_SPMD
: OMP_TGT_EXEC_MODE_GENERIC),
Twine(Name, "_exec_mode"));
+ GVMode->setVisibility(llvm::GlobalVariable::ProtectedVisibility);
CGM.addCompilerUsedGlobal(GVMode);
}
-void CGOpenMPRuntimeGPU::createOffloadEntry(llvm::Constant *ID,
- llvm::Constant *Addr,
- uint64_t Size, int32_t,
- llvm::GlobalValue::LinkageTypes) {
- // TODO: Add support for global variables on the device after declare target
- // support.
- llvm::Function *Fn = dyn_cast<llvm::Function>(Addr);
- if (!Fn)
- return;
-
- llvm::Module &M = CGM.getModule();
- llvm::LLVMContext &Ctx = CGM.getLLVMContext();
-
- // Get "nvvm.annotations" metadata node.
- llvm::NamedMDNode *MD = M.getOrInsertNamedMetadata("nvvm.annotations");
-
- llvm::Metadata *MDVals[] = {
- llvm::ConstantAsMetadata::get(Fn), llvm::MDString::get(Ctx, "kernel"),
- llvm::ConstantAsMetadata::get(
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), 1))};
- // Append metadata to nvvm.annotations.
- MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
-
- // Add a function attribute for the kernel.
- Fn->addFnAttr(llvm::Attribute::get(Ctx, "kernel"));
-}
-
void CGOpenMPRuntimeGPU::emitTargetOutlinedFunction(
const OMPExecutableDirective &D, StringRef ParentName,
llvm::Function *&OutlinedFn, llvm::Constant *&OutlinedFnID,
@@ -1166,39 +857,14 @@ void CGOpenMPRuntimeGPU::emitTargetOutlinedFunction(
setPropertyExecutionMode(CGM, OutlinedFn->getName(), Mode);
}
-namespace {
-LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
-/// Enum for accesseing the reserved_2 field of the ident_t struct.
-enum ModeFlagsTy : unsigned {
- /// Bit set to 1 when in SPMD mode.
- KMP_IDENT_SPMD_MODE = 0x01,
- /// Bit set to 1 when a simplified runtime is used.
- KMP_IDENT_SIMPLE_RT_MODE = 0x02,
- LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/KMP_IDENT_SIMPLE_RT_MODE)
-};
-
-/// Special mode Undefined. Is the combination of Non-SPMD mode + SimpleRuntime.
-static const ModeFlagsTy UndefinedMode =
- (~KMP_IDENT_SPMD_MODE) & KMP_IDENT_SIMPLE_RT_MODE;
-} // anonymous namespace
-
-unsigned CGOpenMPRuntimeGPU::getDefaultLocationReserved2Flags() const {
- switch (getExecutionMode()) {
- case EM_SPMD:
- if (requiresFullRuntime())
- return KMP_IDENT_SPMD_MODE & (~KMP_IDENT_SIMPLE_RT_MODE);
- return KMP_IDENT_SPMD_MODE | KMP_IDENT_SIMPLE_RT_MODE;
- case EM_NonSPMD:
- assert(requiresFullRuntime() && "Expected full runtime.");
- return (~KMP_IDENT_SPMD_MODE) & (~KMP_IDENT_SIMPLE_RT_MODE);
- case EM_Unknown:
- return UndefinedMode;
- }
- llvm_unreachable("Unknown flags are requested.");
-}
-
CGOpenMPRuntimeGPU::CGOpenMPRuntimeGPU(CodeGenModule &CGM)
- : CGOpenMPRuntime(CGM, "_", "$") {
+ : CGOpenMPRuntime(CGM) {
+ llvm::OpenMPIRBuilderConfig Config(CGM.getLangOpts().OpenMPIsDevice, true,
+ hasRequiresUnifiedSharedMemory(),
+ CGM.getLangOpts().OpenMPOffloadMandatory);
+ OMPBuilder.setConfig(Config);
+ OffloadEntriesInfoManager.setConfig(Config);
+
if (!CGM.getLangOpts().OpenMPIsDevice)
llvm_unreachable("OpenMP can only handle device code.");
@@ -1214,6 +880,8 @@ CGOpenMPRuntimeGPU::CGOpenMPRuntimeGPU(CodeGenModule &CGM)
"__omp_rtl_assume_threads_oversubscription");
OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPNoThreadState,
"__omp_rtl_assume_no_thread_state");
+ OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPNoNestedParallelism,
+ "__omp_rtl_assume_no_nested_parallelism");
}
void CGOpenMPRuntimeGPU::emitProcBindClause(CodeGenFunction &CGF,
@@ -1241,33 +909,13 @@ llvm::Function *CGOpenMPRuntimeGPU::emitParallelOutlinedFunction(
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
// Emit target region as a standalone region.
- class NVPTXPrePostActionTy : public PrePostActionTy {
- bool &IsInParallelRegion;
- bool PrevIsInParallelRegion;
-
- public:
- NVPTXPrePostActionTy(bool &IsInParallelRegion)
- : IsInParallelRegion(IsInParallelRegion) {}
- void Enter(CodeGenFunction &CGF) override {
- PrevIsInParallelRegion = IsInParallelRegion;
- IsInParallelRegion = true;
- }
- void Exit(CodeGenFunction &CGF) override {
- IsInParallelRegion = PrevIsInParallelRegion;
- }
- } Action(IsInParallelRegion);
- CodeGen.setAction(Action);
bool PrevIsInTTDRegion = IsInTTDRegion;
IsInTTDRegion = false;
- bool PrevIsInTargetMasterThreadRegion = IsInTargetMasterThreadRegion;
- IsInTargetMasterThreadRegion = false;
auto *OutlinedFun =
cast<llvm::Function>(CGOpenMPRuntime::emitParallelOutlinedFunction(
D, ThreadIDVar, InnermostKind, CodeGen));
- IsInTargetMasterThreadRegion = PrevIsInTargetMasterThreadRegion;
IsInTTDRegion = PrevIsInTTDRegion;
- if (getExecutionMode() != CGOpenMPRuntimeGPU::EM_SPMD &&
- !IsInParallelRegion) {
+ if (getExecutionMode() != CGOpenMPRuntimeGPU::EM_SPMD) {
llvm::Function *WrapperFun =
createParallelDataSharingWrapper(OutlinedFun, D);
WrapperFunctionsMap[OutlinedFun] = WrapperFun;
@@ -1330,7 +978,7 @@ llvm::Function *CGOpenMPRuntimeGPU::emitTeamsOutlinedFunction(
getDistributeLastprivateVars(CGM.getContext(), D, LastPrivatesReductions);
if (!LastPrivatesReductions.empty()) {
GlobalizedRD = ::buildRecordForGlobalizedVars(
- CGM.getContext(), llvm::None, LastPrivatesReductions,
+ CGM.getContext(), std::nullopt, LastPrivatesReductions,
MappedDeclsFields, WarpSize);
}
} else if (!LastPrivatesReductions.empty()) {
@@ -3307,7 +2955,7 @@ void CGOpenMPRuntimeGPU::emitReduction(
++Cnt;
}
const RecordDecl *TeamReductionRec = ::buildRecordForGlobalizedVars(
- CGM.getContext(), PrivatesReductions, llvm::None, VarFieldMap,
+ CGM.getContext(), PrivatesReductions, std::nullopt, VarFieldMap,
C.getLangOpts().OpenMPCUDAReductionBufNum);
TeamsReductions.push_back(TeamReductionRec);
if (!KernelTeamsReductionPtr) {
@@ -3379,7 +3027,7 @@ void CGOpenMPRuntimeGPU::emitReduction(
llvm::Value *EndArgs[] = {ThreadId};
RegionCodeGenTy RCG(CodeGen);
NVPTXActionTy Action(
- nullptr, llvm::None,
+ nullptr, std::nullopt,
OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_nvptx_end_reduce_nowait),
EndArgs);
@@ -3435,7 +3083,7 @@ CGOpenMPRuntimeGPU::getParameterAddress(CodeGenFunction &CGF,
const Type *NonQualTy = QC.strip(NativeParamType);
QualType NativePointeeTy = cast<ReferenceType>(NonQualTy)->getPointeeType();
unsigned NativePointeeAddrSpace =
- CGF.getContext().getTargetAddressSpace(NativePointeeTy);
+ CGF.getTypes().getTargetAddressSpace(NativePointeeTy);
QualType TargetTy = TargetParam->getType();
llvm::Value *TargetAddr = CGF.EmitLoadOfScalar(
LocalAddr, /*Volatile=*/false, TargetTy, SourceLocation());
@@ -3659,16 +3307,6 @@ void CGOpenMPRuntimeGPU::emitFunctionProlog(CodeGenFunction &CGF,
assert(VD->isCanonicalDecl() && "Expected canonical declaration");
Data.insert(std::make_pair(VD, MappedVarData()));
}
- if (!IsInTTDRegion && !NeedToDelayGlobalization && !IsInParallelRegion) {
- CheckVarsEscapingDeclContext VarChecker(CGF, llvm::None);
- VarChecker.Visit(Body);
- I->getSecond().SecondaryLocalVarData.emplace();
- DeclToAddrMapTy &Data = *I->getSecond().SecondaryLocalVarData;
- for (const ValueDecl *VD : VarChecker.getEscapedDecls()) {
- assert(VD->isCanonicalDecl() && "Expected canonical declaration");
- Data.insert(std::make_pair(VD, MappedVarData()));
- }
- }
if (!NeedToDelayGlobalization) {
emitGenericVarsProlog(CGF, D->getBeginLoc(), /*WithSPMDCheck=*/true);
struct GlobalizationScope final : EHScopeStack::Cleanup {
@@ -3810,7 +3448,7 @@ void CGOpenMPRuntimeGPU::adjustTargetSpecificDataForLambdas(
else
VDLVal = CGF.MakeAddrLValue(
VDAddr, VD->getType().getCanonicalType().getNonReferenceType());
- llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
FieldDecl *ThisCapture = nullptr;
RD->getCaptureFields(Captures, ThisCapture);
if (ThisCapture && CGF.CapturedStmtInfo->isCXXThisExprCaptured()) {
@@ -3822,13 +3460,15 @@ void CGOpenMPRuntimeGPU::adjustTargetSpecificDataForLambdas(
for (const LambdaCapture &LC : RD->captures()) {
if (LC.getCaptureKind() != LCK_ByRef)
continue;
- const VarDecl *VD = LC.getCapturedVar();
- if (!CS->capturesVariable(VD))
+ const ValueDecl *VD = LC.getCapturedVar();
+ // FIXME: For now VD is always a VarDecl because OpenMP does not support
+ // capturing structured bindings in lambdas yet.
+ if (!CS->capturesVariable(cast<VarDecl>(VD)))
continue;
auto It = Captures.find(VD);
assert(It != Captures.end() && "Found lambda capture without field.");
LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second);
- Address VDAddr = CGF.GetAddrOfLocalVar(VD);
+ Address VDAddr = CGF.GetAddrOfLocalVar(cast<VarDecl>(VD));
if (VD->getType().getCanonicalType()->isReferenceType())
VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr,
VD->getType().getCanonicalType())
@@ -3913,6 +3553,9 @@ void CGOpenMPRuntimeGPU::processRequiresDirective(
case CudaArch::SM_75:
case CudaArch::SM_80:
case CudaArch::SM_86:
+ case CudaArch::SM_87:
+ case CudaArch::SM_89:
+ case CudaArch::SM_90:
case CudaArch::GFX600:
case CudaArch::GFX601:
case CudaArch::GFX602:
@@ -4006,10 +3649,10 @@ llvm::Value *CGOpenMPRuntimeGPU::getGPUNumThreads(CodeGenFunction &CGF) {
llvm::Function *F = M->getFunction(LocSize);
if (!F) {
F = llvm::Function::Create(
- llvm::FunctionType::get(CGF.Int32Ty, llvm::None, false),
+ llvm::FunctionType::get(CGF.Int32Ty, std::nullopt, false),
llvm::GlobalVariable::ExternalLinkage, LocSize, &CGF.CGM.getModule());
}
- return Bld.CreateCall(F, llvm::None, "nvptx_num_threads");
+ return Bld.CreateCall(F, std::nullopt, "nvptx_num_threads");
}
llvm::Value *CGOpenMPRuntimeGPU::getGPUThreadID(CodeGenFunction &CGF) {
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h
index ff585efa3fce..75d140205773 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h
@@ -42,8 +42,6 @@ private:
ExecutionMode getExecutionMode() const;
- bool requiresFullRuntime() const { return RequiresFullRuntime; }
-
/// Get barrier to synchronize all threads in a block.
void syncCTAThreads(CodeGenFunction &CGF);
@@ -66,12 +64,6 @@ private:
// Base class overrides.
//
- /// Creates offloading entry for the provided entry ID \a ID,
- /// address \a Addr, size \a Size, and flags \a Flags.
- void createOffloadEntry(llvm::Constant *ID, llvm::Constant *Addr,
- uint64_t Size, int32_t Flags,
- llvm::GlobalValue::LinkageTypes Linkage) override;
-
/// Emit outlined function specialized for the Fork-Join
/// programming model for applicable target directives on the NVPTX device.
/// \param D Directive to emit.
@@ -161,16 +153,12 @@ protected:
/// Constant for NVPTX for better optimization.
bool isDefaultLocationConstant() const override { return true; }
- /// Returns additional flags that can be stored in reserved_2 field of the
- /// default location.
- /// For NVPTX target contains data about SPMD/Non-SPMD execution mode +
- /// Full/Lightweight runtime mode. Used for better optimization.
- unsigned getDefaultLocationReserved2Flags() const override;
-
public:
explicit CGOpenMPRuntimeGPU(CodeGenModule &CGM);
void clear() override;
+ bool isTargetCodegen() const override { return true; };
+
/// Declare generalized virtual functions which need to be defined
/// by all specializations of OpenMPGPURuntime Targets like AMDGCN
/// and NVPTX.
@@ -330,7 +318,7 @@ public:
/// translating these arguments to correct target-specific arguments.
void emitOutlinedFunctionCall(
CodeGenFunction &CGF, SourceLocation Loc, llvm::FunctionCallee OutlinedFn,
- ArrayRef<llvm::Value *> Args = llvm::None) const override;
+ ArrayRef<llvm::Value *> Args = std::nullopt) const override;
/// Emits OpenMP-specific function prolog.
/// Required for device constructs.
@@ -386,17 +374,9 @@ private:
/// to emit optimized code.
ExecutionMode CurrentExecutionMode = EM_Unknown;
- /// Check if the full runtime is required (default - yes).
- bool RequiresFullRuntime = true;
-
- /// true if we're emitting the code for the target region and next parallel
- /// region is L0 for sure.
- bool IsInTargetMasterThreadRegion = false;
/// true if currently emitting code for target/teams/distribute region, false
/// - otherwise.
bool IsInTTDRegion = false;
- /// true if we're definitely in the parallel region.
- bool IsInParallelRegion = false;
/// Map between an outlined function and its wrapper.
llvm::DenseMap<llvm::Function *, llvm::Function *> WrapperFunctionsMap;
@@ -421,12 +401,10 @@ private:
using EscapedParamsTy = llvm::SmallPtrSet<const Decl *, 4>;
struct FunctionData {
DeclToAddrMapTy LocalVarData;
- llvm::Optional<DeclToAddrMapTy> SecondaryLocalVarData = llvm::None;
EscapedParamsTy EscapedParameters;
llvm::SmallVector<const ValueDecl*, 4> EscapedVariableLengthDecls;
llvm::SmallVector<std::pair<llvm::Value *, llvm::Value *>, 4>
EscapedVariableLengthDeclsAddrs;
- llvm::Value *IsInSPMDModeFlag = nullptr;
std::unique_ptr<CodeGenFunction::OMPMapVars> MappedParams;
};
/// Maps the function to the list of the globalized variables with their
@@ -438,9 +416,6 @@ private:
/// reductions.
/// All the records are gathered into a union `union.type` is created.
llvm::SmallVector<const RecordDecl *, 4> TeamsReductions;
- /// Shared pointer for the global memory in the global memory buffer used for
- /// the given kernel.
- llvm::GlobalVariable *KernelStaticGlobalized = nullptr;
/// Pair of the Non-SPMD team and all reductions variables in this team
/// region.
std::pair<const Decl *, llvm::SmallVector<const ValueDecl *, 4>>
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 6f85bca8a201..596f0bd33204 100644
--- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -162,7 +162,7 @@ struct CGRecordLowering {
return CharUnits::fromQuantity(DataLayout.getTypeAllocSize(Type));
}
CharUnits getAlignment(llvm::Type *Type) {
- return CharUnits::fromQuantity(DataLayout.getABITypeAlignment(Type));
+ return CharUnits::fromQuantity(DataLayout.getABITypeAlign(Type));
}
bool isZeroInitializable(const FieldDecl *FD) {
return Types.isZeroInitializable(FD->getType());
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 05ab16668743..248ffb544014 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -32,6 +32,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/Support/SaveAndRestore.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -254,6 +255,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OMPTaskyieldDirectiveClass:
EmitOMPTaskyieldDirective(cast<OMPTaskyieldDirective>(*S));
break;
+ case Stmt::OMPErrorDirectiveClass:
+ EmitOMPErrorDirective(cast<OMPErrorDirective>(*S));
+ break;
case Stmt::OMPBarrierDirectiveClass:
EmitOMPBarrierDirective(cast<OMPBarrierDirective>(*S));
break;
@@ -571,9 +575,9 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) {
// Place the block after the current block, if possible, or else at
// the end of the function.
if (CurBB && CurBB->getParent())
- CurFn->getBasicBlockList().insertAfter(CurBB->getIterator(), BB);
+ CurFn->insert(std::next(CurBB->getIterator()), BB);
else
- CurFn->getBasicBlockList().push_back(BB);
+ CurFn->insert(CurFn->end(), BB);
Builder.SetInsertPoint(BB);
}
@@ -598,15 +602,14 @@ void CodeGenFunction::EmitBlockAfterUses(llvm::BasicBlock *block) {
bool inserted = false;
for (llvm::User *u : block->users()) {
if (llvm::Instruction *insn = dyn_cast<llvm::Instruction>(u)) {
- CurFn->getBasicBlockList().insertAfter(insn->getParent()->getIterator(),
- block);
+ CurFn->insert(std::next(insn->getParent()->getIterator()), block);
inserted = true;
break;
}
}
if (!inserted)
- CurFn->getBasicBlockList().push_back(block);
+ CurFn->insert(CurFn->end(), block);
Builder.SetInsertPoint(block);
}
@@ -718,11 +721,10 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
break;
}
}
- SaveAndRestore<bool> save_nomerge(InNoMergeAttributedStmt, nomerge);
- SaveAndRestore<bool> save_noinline(InNoInlineAttributedStmt, noinline);
- SaveAndRestore<bool> save_alwaysinline(InAlwaysInlineAttributedStmt,
- alwaysinline);
- SaveAndRestore<const CallExpr *> save_musttail(MustTailCall, musttail);
+ SaveAndRestore save_nomerge(InNoMergeAttributedStmt, nomerge);
+ SaveAndRestore save_noinline(InNoInlineAttributedStmt, noinline);
+ SaveAndRestore save_alwaysinline(InAlwaysInlineAttributedStmt, alwaysinline);
+ SaveAndRestore save_musttail(MustTailCall, musttail);
EmitStmt(S.getSubStmt(), S.getAttrs());
}
@@ -815,11 +817,20 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// Prefer the PGO based weights over the likelihood attribute.
// When the build isn't optimized the metadata isn't used, so don't generate
// it.
+ // Also, differentiate between disabled PGO and a never executed branch with
+ // PGO. Assuming PGO is in use:
+ // - we want to ignore the [[likely]] attribute if the branch is never
+ // executed,
+ // - assuming the profile is poor, preserving the attribute may still be
+ // beneficial.
+ // As an approximation, preserve the attribute only if both the branch and the
+ // parent context were not executed.
Stmt::Likelihood LH = Stmt::LH_None;
- uint64_t Count = getProfileCount(S.getThen());
- if (!Count && CGM.getCodeGenOpts().OptimizationLevel)
+ uint64_t ThenCount = getProfileCount(S.getThen());
+ if (!ThenCount && !getCurrentProfileCount() &&
+ CGM.getCodeGenOpts().OptimizationLevel)
LH = Stmt::getLikelihood(S.getThen(), S.getElse());
- EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, Count, LH);
+ EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, ThenCount, LH);
// Emit the 'then' code.
EmitBlock(ThenBlock);
@@ -1458,7 +1469,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S,
llvm::BasicBlock *FalseDest = CaseRangeBlock;
CaseRangeBlock = createBasicBlock("sw.caserange");
- CurFn->getBasicBlockList().push_back(CaseRangeBlock);
+ CurFn->insert(CurFn->end(), CaseRangeBlock);
Builder.SetInsertPoint(CaseRangeBlock);
// Emit range check.
@@ -1509,6 +1520,21 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S,
llvm::ConstantInt *CaseVal =
Builder.getInt(S.getLHS()->EvaluateKnownConstInt(getContext()));
+
+ // Emit debuginfo for the case value if it is an enum value.
+ const ConstantExpr *CE;
+ if (auto ICE = dyn_cast<ImplicitCastExpr>(S.getLHS()))
+ CE = dyn_cast<ConstantExpr>(ICE->getSubExpr());
+ else
+ CE = dyn_cast<ConstantExpr>(S.getLHS());
+ if (CE) {
+ if (auto DE = dyn_cast<DeclRefExpr>(CE->getSubExpr()))
+ if (CGDebugInfo *Dbg = getDebugInfo())
+ if (CGM.getCodeGenOpts().hasReducedDebugInfo())
+ Dbg->EmitGlobalVariable(DE->getDecl(),
+ APValue(llvm::APSInt(CaseVal->getValue())));
+ }
+
if (SwitchLikelihood)
SwitchLikelihood->push_back(Stmt::getLikelihood(Attrs));
@@ -1843,11 +1869,11 @@ static bool FindCaseStatementsForValue(const SwitchStmt &S,
FoundCase;
}
-static Optional<SmallVector<uint64_t, 16>>
+static std::optional<SmallVector<uint64_t, 16>>
getLikelihoodWeights(ArrayRef<Stmt::Likelihood> Likelihoods) {
// Are there enough branches to weight them?
if (Likelihoods.size() <= 1)
- return None;
+ return std::nullopt;
uint64_t NumUnlikely = 0;
uint64_t NumNone = 0;
@@ -1868,7 +1894,7 @@ getLikelihoodWeights(ArrayRef<Stmt::Likelihood> Likelihoods) {
// Is there a likelihood attribute used?
if (NumUnlikely == 0 && NumLikely == 0)
- return None;
+ return std::nullopt;
// When multiple cases share the same code they can be combined during
// optimization. In that case the weights of the branch will be the sum of
@@ -2050,7 +2076,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
} else if (SwitchLikelihood) {
assert(SwitchLikelihood->size() == 1 + SwitchInsn->getNumCases() &&
"switch likelihoods do not match switch cases");
- Optional<SmallVector<uint64_t, 16>> LHW =
+ std::optional<SmallVector<uint64_t, 16>> LHW =
getLikelihoodWeights(*SwitchLikelihood);
if (LHW) {
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
@@ -2256,9 +2282,9 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect,
// Attach readnone and readonly attributes.
if (!HasSideEffect) {
if (ReadNone)
- Result.addFnAttr(llvm::Attribute::ReadNone);
+ Result.setDoesNotAccessMemory();
else if (ReadOnly)
- Result.addFnAttr(llvm::Attribute::ReadOnly);
+ Result.setOnlyReadsMemory();
}
// Add elementtype attribute for indirect constraints.
@@ -2343,6 +2369,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
std::vector<llvm::Type *> ArgElemTypes;
std::vector<llvm::Value*> Args;
llvm::BitVector ResultTypeRequiresCast;
+ llvm::BitVector ResultRegIsFlagReg;
// Keep track of inout constraints.
std::string InOutConstraints;
@@ -2400,6 +2427,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
ResultRegQualTys.push_back(QTy);
ResultRegDests.push_back(Dest);
+ bool IsFlagReg = llvm::StringRef(OutputConstraint).startswith("{@cc");
+ ResultRegIsFlagReg.push_back(IsFlagReg);
+
llvm::Type *Ty = ConvertTypeForMem(QTy);
const bool RequiresCast = Info.allowsRegister() &&
(getTargetHooks().isScalarizableAsmOperand(*this, Ty) ||
@@ -2448,7 +2478,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
if (auto *VT = dyn_cast<llvm::VectorType>(ResultRegTypes.back()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
- VT->getPrimitiveSizeInBits().getKnownMinSize());
+ VT->getPrimitiveSizeInBits().getKnownMinValue());
} else {
Address DestAddr = Dest.getAddress(*this);
// Matrix types in memory are represented by arrays, but accessed through
@@ -2487,7 +2517,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
- VT->getPrimitiveSizeInBits().getKnownMinSize());
+ VT->getPrimitiveSizeInBits().getKnownMinValue());
// Only tie earlyclobber physregs.
if (Info.allowsRegister() && (GCCReg.empty() || Info.earlyClobber()))
InOutConstraints += llvm::utostr(i);
@@ -2577,7 +2607,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
- VT->getPrimitiveSizeInBits().getKnownMinSize());
+ VT->getPrimitiveSizeInBits().getKnownMinValue());
ArgTypes.push_back(Arg->getType());
ArgElemTypes.push_back(ArgElemType);
@@ -2717,10 +2747,21 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// ResultRegDests can be also populated by addReturnRegisterOutputs() above,
// in which case its size may grow.
assert(ResultTypeRequiresCast.size() <= ResultRegDests.size());
+ assert(ResultRegIsFlagReg.size() <= ResultRegDests.size());
for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
llvm::Value *Tmp = RegResults[i];
llvm::Type *TruncTy = ResultTruncRegTypes[i];
+ if ((i < ResultRegIsFlagReg.size()) && ResultRegIsFlagReg[i]) {
+ // Target must guarantee the Value `Tmp` here is lowered to a boolean
+ // value.
+ llvm::Constant *Two = llvm::ConstantInt::get(Tmp->getType(), 2);
+ llvm::Value *IsBooleanValue =
+ Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, Two);
+ llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
+ Builder.CreateCall(FnAssume, IsBooleanValue);
+ }
+
// If the result type of the LLVM IR asm doesn't match the result type of
// the expression, do the conversion.
if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index aa55cdaca5dc..6bc30ad0302e 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -34,6 +34,7 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/AtomicOrdering.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
using namespace llvm::omp;
@@ -74,7 +75,7 @@ class OMPLexicalScope : public CodeGenFunction::LexicalScope {
public:
OMPLexicalScope(
CodeGenFunction &CGF, const OMPExecutableDirective &S,
- const llvm::Optional<OpenMPDirectiveKind> CapturedRegion = llvm::None,
+ const std::optional<OpenMPDirectiveKind> CapturedRegion = std::nullopt,
const bool EmitPreInitStmt = true)
: CodeGenFunction::LexicalScope(CGF, S.getSourceRange()),
InlinedShareds(CGF) {
@@ -114,7 +115,7 @@ class OMPParallelScope final : public OMPLexicalScope {
public:
OMPParallelScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
- : OMPLexicalScope(CGF, S, /*CapturedRegion=*/llvm::None,
+ : OMPLexicalScope(CGF, S, /*CapturedRegion=*/std::nullopt,
EmitPreInitStmt(S)) {}
};
@@ -129,7 +130,7 @@ class OMPTeamsScope final : public OMPLexicalScope {
public:
OMPTeamsScope(CodeGenFunction &CGF, const OMPExecutableDirective &S)
- : OMPLexicalScope(CGF, S, /*CapturedRegion=*/llvm::None,
+ : OMPLexicalScope(CGF, S, /*CapturedRegion=*/std::nullopt,
EmitPreInitStmt(S)) {}
};
@@ -446,7 +447,7 @@ static llvm::Function *emitOutlinedFunctionPrologue(
FunctionDecl *DebugFunctionDecl = nullptr;
if (!FO.UIntPtrCastRequired) {
FunctionProtoType::ExtProtoInfo EPI;
- QualType FunctionTy = Ctx.getFunctionType(Ctx.VoidTy, llvm::None, EPI);
+ QualType FunctionTy = Ctx.getFunctionType(Ctx.VoidTy, std::nullopt, EPI);
DebugFunctionDecl = FunctionDecl::Create(
Ctx, Ctx.getTranslationUnitDecl(), FO.S->getBeginLoc(),
SourceLocation(), DeclarationName(), FunctionTy,
@@ -708,8 +709,9 @@ void CodeGenFunction::EmitOMPAggregateAssign(
llvm::Value *SrcBegin = SrcAddr.getPointer();
llvm::Value *DestBegin = DestAddr.getPointer();
// Cast from pointer to array type to pointer to single element.
- llvm::Value *DestEnd =
- Builder.CreateGEP(DestAddr.getElementType(), DestBegin, NumElements);
+ llvm::Value *DestEnd = Builder.CreateInBoundsGEP(DestAddr.getElementType(),
+ DestBegin, NumElements);
+
// The basic structure here is a while-do loop.
llvm::BasicBlock *BodyBB = createBasicBlock("omp.arraycpy.body");
llvm::BasicBlock *DoneBB = createBasicBlock("omp.arraycpy.done");
@@ -1347,6 +1349,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
case OMPD_parallel_for_simd:
case OMPD_task:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_taskgroup:
@@ -1593,6 +1596,19 @@ static void emitEmptyBoundParameters(CodeGenFunction &,
const OMPExecutableDirective &,
llvm::SmallVectorImpl<llvm::Value *> &) {}
+static void emitOMPCopyinClause(CodeGenFunction &CGF,
+ const OMPExecutableDirective &S) {
+ bool Copyins = CGF.EmitOMPCopyinClause(S);
+ if (Copyins) {
+ // Emit implicit barrier to synchronize threads and avoid data races on
+ // propagation master's thread values of threadprivate variables to local
+ // instances of that variables of all other implicit threads.
+ CGF.CGM.getOpenMPRuntime().emitBarrierCall(
+ CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
+ /*ForceSimpleCall=*/true);
+ }
+}
+
Address CodeGenFunction::OMPBuilderCBHelpers::getAddressOfLocalVariable(
CodeGenFunction &CGF, const VarDecl *VD) {
CodeGenModule &CGM = CGF.CGM;
@@ -1774,16 +1790,8 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope PrivateScope(CGF);
- bool Copyins = CGF.EmitOMPCopyinClause(S);
+ emitOMPCopyinClause(CGF, S);
(void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
- if (Copyins) {
- // Emit implicit barrier to synchronize threads and avoid data races on
- // propagation master's thread values of threadprivate variables to local
- // instances of that variables of all other implicit threads.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
- }
CGF.EmitOMPPrivateClause(S, PrivateScope);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
@@ -2582,8 +2590,9 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_simd);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
+ LoopScope.restoreMap();
+ CGF.EmitOMPLinearClauseFinal(S, [](CodeGenFunction &) { return nullptr; });
}
- CGF.EmitOMPLinearClauseFinal(S, [](CodeGenFunction &) { return nullptr; });
// Emit: if (PreCond) - end.
if (ContBlock) {
CGF.EmitBranch(ContBlock);
@@ -2594,8 +2603,9 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
static bool isSupportedByOpenMPIRBuilder(const OMPSimdDirective &S) {
// Check for unsupported clauses
for (OMPClause *C : S.clauses()) {
- // Currently only simdlen clause is supported
- if (!isa<OMPSimdlenClause>(C))
+ // Currently only order, simdlen and safelen clauses are supported
+ if (!(isa<OMPSimdlenClause>(C) || isa<OMPSafelenClause>(C) ||
+ isa<OMPOrderClause>(C) || isa<OMPAlignedClause>(C)))
return false;
}
@@ -2621,6 +2631,36 @@ static bool isSupportedByOpenMPIRBuilder(const OMPSimdDirective &S) {
}
return true;
}
+static llvm::MapVector<llvm::Value *, llvm::Value *>
+GetAlignedMapping(const OMPSimdDirective &S, CodeGenFunction &CGF) {
+ llvm::MapVector<llvm::Value *, llvm::Value *> AlignedVars;
+ for (const auto *Clause : S.getClausesOfKind<OMPAlignedClause>()) {
+ llvm::APInt ClauseAlignment(64, 0);
+ if (const Expr *AlignmentExpr = Clause->getAlignment()) {
+ auto *AlignmentCI =
+ cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
+ ClauseAlignment = AlignmentCI->getValue();
+ }
+ for (const Expr *E : Clause->varlists()) {
+ llvm::APInt Alignment(ClauseAlignment);
+ if (Alignment == 0) {
+ // OpenMP [2.8.1, Description]
+ // If no optional parameter is specified, implementation-defined default
+ // alignments for SIMD instructions on the target platforms are assumed.
+ Alignment =
+ CGF.getContext()
+ .toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign(
+ E->getType()->getPointeeType()))
+ .getQuantity();
+ }
+ assert((Alignment == 0 || Alignment.isPowerOf2()) &&
+ "alignment is not power of 2");
+ llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
+ AlignedVars[PtrValue] = CGF.Builder.getInt64(Alignment.getSExtValue());
+ }
+ }
+ return AlignedVars;
+}
void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
bool UseOMPIRBuilder =
@@ -2630,6 +2670,8 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
PrePostActionTy &) {
// Use the OpenMPIRBuilder if enabled.
if (UseOMPIRBuilder) {
+ llvm::MapVector<llvm::Value *, llvm::Value *> AlignedVars =
+ GetAlignedMapping(S, CGF);
// Emit the associated statement and get its loop representation.
const Stmt *Inner = S.getRawStmt();
llvm::CanonicalLoopInfo *CLI =
@@ -2646,7 +2688,24 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
Simdlen = Val;
}
- OMPBuilder.applySimd(CLI, Simdlen);
+ llvm::ConstantInt *Safelen = nullptr;
+ if (const auto *C = S.getSingleClause<OMPSafelenClause>()) {
+ RValue Len =
+ this->EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(),
+ /*ignoreResult=*/true);
+ auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
+ Safelen = Val;
+ }
+ llvm::omp::OrderKind Order = llvm::omp::OrderKind::OMP_ORDER_unknown;
+ if (const auto *C = S.getSingleClause<OMPOrderClause>()) {
+ if (C->getKind() == OpenMPOrderClauseKind ::OMPC_ORDER_concurrent) {
+ Order = llvm::omp::OrderKind::OMP_ORDER_concurrent;
+ }
+ }
+ // Add simd metadata to the collapsed loop. Do not generate
+ // another loop for if clause. Support for if clause is done earlier.
+ OMPBuilder.applySimd(CLI, AlignedVars,
+ /*IfCond*/ nullptr, Order, Simdlen, Safelen);
return;
}
};
@@ -3426,11 +3485,12 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(
EmitOMPLastprivateClauseFinal(
S, isOpenMPSimdDirective(S.getDirectiveKind()),
Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getBeginLoc())));
+ LoopScope.restoreMap();
+ EmitOMPLinearClauseFinal(S, [IL, &S](CodeGenFunction &CGF) {
+ return CGF.Builder.CreateIsNotNull(
+ CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
+ });
}
- EmitOMPLinearClauseFinal(S, [IL, &S](CodeGenFunction &CGF) {
- return CGF.Builder.CreateIsNotNull(
- CGF.EmitLoadOfScalar(IL, S.getBeginLoc()));
- });
DoacrossCleanupScope.ForceCleanup();
// We're now done with the loop, so jump to the continuation block.
if (ContBlock) {
@@ -4340,6 +4400,7 @@ void CodeGenFunction::EmitOMPParallelForDirective(
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
+ emitOMPCopyinClause(CGF, S);
(void)emitWorksharingDirective(CGF, S, S.hasCancel());
};
{
@@ -4373,6 +4434,7 @@ void CodeGenFunction::EmitOMPParallelForSimdDirective(
// directives: 'parallel' with 'for' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
+ emitOMPCopyinClause(CGF, S);
(void)emitWorksharingDirective(CGF, S, /*HasCancel=*/false);
};
{
@@ -4407,16 +4469,8 @@ void CodeGenFunction::EmitOMPParallelMasterDirective(
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
OMPPrivateScope PrivateScope(CGF);
- bool Copyins = CGF.EmitOMPCopyinClause(S);
+ emitOMPCopyinClause(CGF, S);
(void)CGF.EmitOMPFirstprivateClause(S, PrivateScope);
- if (Copyins) {
- // Emit implicit barrier to synchronize threads and avoid data races on
- // propagation master's thread values of threadprivate variables to local
- // instances of that variables of all other implicit threads.
- CGF.CGM.getOpenMPRuntime().emitBarrierCall(
- CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
- }
CGF.EmitOMPPrivateClause(S, PrivateScope);
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
(void)PrivateScope.Privatize();
@@ -4441,6 +4495,7 @@ void CodeGenFunction::EmitOMPParallelSectionsDirective(
// directives: 'parallel' with 'sections' directive.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
+ emitOMPCopyinClause(CGF, S);
CGF.EmitSections(S);
};
{
@@ -4892,7 +4947,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(
llvm::Function *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, Data.Tied,
Data.NumberOfParts);
- OMPLexicalScope Scope(*this, S, llvm::None,
+ OMPLexicalScope Scope(*this, S, std::nullopt,
!isOpenMPParallelDirective(S.getDirectiveKind()) &&
!isOpenMPSimdDirective(S.getDirectiveKind()));
TaskGen(*this, OutlinedFn, Data);
@@ -5192,6 +5247,16 @@ void CodeGenFunction::EmitOMPTaskyieldDirective(
CGM.getOpenMPRuntime().emitTaskyieldCall(*this, S.getBeginLoc());
}
+void CodeGenFunction::EmitOMPErrorDirective(const OMPErrorDirective &S) {
+ const OMPMessageClause *MC = S.getSingleClause<OMPMessageClause>();
+ Expr *ME = MC ? MC->getMessageString() : nullptr;
+ const OMPSeverityClause *SC = S.getSingleClause<OMPSeverityClause>();
+ bool IsFatal = false;
+ if (!SC || SC->getSeverityKind() == OMPC_SEVERITY_fatal)
+ IsFatal = true;
+ CGM.getOpenMPRuntime().emitErrorCall(*this, S.getBeginLoc(), ME, IsFatal);
+}
+
void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) {
CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_barrier);
}
@@ -5200,6 +5265,7 @@ void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) {
OMPTaskDataTy Data;
// Build list of dependences
buildDependences(S, Data);
+ Data.HasNowaitClause = S.hasClausesOfKind<OMPNowaitClause>();
CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data);
}
@@ -5263,9 +5329,9 @@ void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) {
*this,
[&S]() -> ArrayRef<const Expr *> {
if (const auto *FlushClause = S.getSingleClause<OMPFlushClause>())
- return llvm::makeArrayRef(FlushClause->varlist_begin(),
- FlushClause->varlist_end());
- return llvm::None;
+ return llvm::ArrayRef(FlushClause->varlist_begin(),
+ FlushClause->varlist_end());
+ return std::nullopt;
}(),
S.getBeginLoc(), AO);
}
@@ -5934,7 +6000,7 @@ static void emitOMPAtomicReadExpr(CodeGenFunction &CGF, llvm::AtomicOrdering AO,
case llvm::AtomicOrdering::Acquire:
case llvm::AtomicOrdering::AcquireRelease:
case llvm::AtomicOrdering::SequentiallyConsistent:
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc,
+ CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
llvm::AtomicOrdering::Acquire);
break;
case llvm::AtomicOrdering::Monotonic:
@@ -5963,7 +6029,7 @@ static void emitOMPAtomicWriteExpr(CodeGenFunction &CGF,
case llvm::AtomicOrdering::Release:
case llvm::AtomicOrdering::AcquireRelease:
case llvm::AtomicOrdering::SequentiallyConsistent:
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc,
+ CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
llvm::AtomicOrdering::Release);
break;
case llvm::AtomicOrdering::Acquire:
@@ -6154,7 +6220,7 @@ static void emitOMPAtomicUpdateExpr(CodeGenFunction &CGF,
case llvm::AtomicOrdering::Release:
case llvm::AtomicOrdering::AcquireRelease:
case llvm::AtomicOrdering::SequentiallyConsistent:
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc,
+ CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
llvm::AtomicOrdering::Release);
break;
case llvm::AtomicOrdering::Acquire:
@@ -6269,17 +6335,17 @@ static void emitOMPAtomicCaptureExpr(CodeGenFunction &CGF,
// operation is also an acquire flush.
switch (AO) {
case llvm::AtomicOrdering::Release:
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc,
+ CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
llvm::AtomicOrdering::Release);
break;
case llvm::AtomicOrdering::Acquire:
- CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc,
+ CGF.CGM.getOpenMPRuntime().emitFlush(CGF, std::nullopt, Loc,
llvm::AtomicOrdering::Acquire);
break;
case llvm::AtomicOrdering::AcquireRelease:
case llvm::AtomicOrdering::SequentiallyConsistent:
CGF.CGM.getOpenMPRuntime().emitFlush(
- CGF, llvm::None, Loc, llvm::AtomicOrdering::AcquireRelease);
+ CGF, std::nullopt, Loc, llvm::AtomicOrdering::AcquireRelease);
break;
case llvm::AtomicOrdering::Monotonic:
break;
@@ -6392,95 +6458,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
IsPostfixUpdate, IsFailOnly, Loc);
break;
}
- case OMPC_if:
- case OMPC_final:
- case OMPC_num_threads:
- case OMPC_private:
- case OMPC_firstprivate:
- case OMPC_lastprivate:
- case OMPC_reduction:
- case OMPC_task_reduction:
- case OMPC_in_reduction:
- case OMPC_safelen:
- case OMPC_simdlen:
- case OMPC_sizes:
- case OMPC_full:
- case OMPC_partial:
- case OMPC_allocator:
- case OMPC_allocate:
- case OMPC_collapse:
- case OMPC_default:
- case OMPC_seq_cst:
- case OMPC_acq_rel:
- case OMPC_acquire:
- case OMPC_release:
- case OMPC_relaxed:
- case OMPC_shared:
- case OMPC_linear:
- case OMPC_aligned:
- case OMPC_copyin:
- case OMPC_copyprivate:
- case OMPC_flush:
- case OMPC_depobj:
- case OMPC_proc_bind:
- case OMPC_schedule:
- case OMPC_ordered:
- case OMPC_nowait:
- case OMPC_untied:
- case OMPC_threadprivate:
- case OMPC_depend:
- case OMPC_mergeable:
- case OMPC_device:
- case OMPC_threads:
- case OMPC_simd:
- case OMPC_map:
- case OMPC_num_teams:
- case OMPC_thread_limit:
- case OMPC_priority:
- case OMPC_grainsize:
- case OMPC_nogroup:
- case OMPC_num_tasks:
- case OMPC_hint:
- case OMPC_dist_schedule:
- case OMPC_defaultmap:
- case OMPC_uniform:
- case OMPC_to:
- case OMPC_from:
- case OMPC_use_device_ptr:
- case OMPC_use_device_addr:
- case OMPC_is_device_ptr:
- case OMPC_has_device_addr:
- case OMPC_unified_address:
- case OMPC_unified_shared_memory:
- case OMPC_reverse_offload:
- case OMPC_dynamic_allocators:
- case OMPC_atomic_default_mem_order:
- case OMPC_device_type:
- case OMPC_match:
- case OMPC_nontemporal:
- case OMPC_order:
- case OMPC_destroy:
- case OMPC_detach:
- case OMPC_inclusive:
- case OMPC_exclusive:
- case OMPC_uses_allocators:
- case OMPC_affinity:
- case OMPC_init:
- case OMPC_inbranch:
- case OMPC_notinbranch:
- case OMPC_link:
- case OMPC_indirect:
- case OMPC_use:
- case OMPC_novariants:
- case OMPC_nocontext:
- case OMPC_filter:
- case OMPC_when:
- case OMPC_adjust_args:
- case OMPC_append_args:
- case OMPC_memory_order:
- case OMPC_bind:
- case OMPC_align:
- case OMPC_cancellation_construct_type:
+ default:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}
@@ -7658,6 +7636,7 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
(*LIP)->getType(), S.getBeginLoc())));
}
+ LoopScope.restoreMap();
CGF.EmitOMPLinearClauseFinal(S, [LIP, &S](CodeGenFunction &CGF) {
return CGF.Builder.CreateIsNotNull(
CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false,
@@ -7714,7 +7693,7 @@ void CodeGenFunction::EmitOMPMasterTaskLoopDirective(
};
auto LPCRegion =
CGOpenMPRuntime::LastprivateConditionalRAII::disable(*this, S);
- OMPLexicalScope Scope(*this, S, llvm::None, /*EmitPreInitStmt=*/false);
+ OMPLexicalScope Scope(*this, S, std::nullopt, /*EmitPreInitStmt=*/false);
CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
}
@@ -7792,7 +7771,19 @@ void CodeGenFunction::EmitOMPGenericLoopDirective(
const OMPGenericLoopDirective &S) {
// Unimplemented, just inline the underlying statement for now.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- CGF.EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
+ // Emit the loop iteration variable.
+ const Stmt *CS =
+ cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt();
+ const auto *ForS = dyn_cast<ForStmt>(CS);
+ if (ForS && !isa<DeclStmt>(ForS->getInit())) {
+ OMPPrivateScope LoopScope(CGF);
+ CGF.EmitOMPPrivateLoopCounters(S, LoopScope);
+ (void)LoopScope.Privatize();
+ CGF.EmitStmt(CS);
+ LoopScope.restoreMap();
+ } else {
+ CGF.EmitStmt(CS);
+ }
};
OMPLexicalScope Scope(*this, S, OMPD_unknown);
CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_loop, CodeGen);
diff --git a/clang/lib/CodeGen/CGVTT.cpp b/clang/lib/CodeGen/CGVTT.cpp
index ebac9196df02..d0c8e351626b 100644
--- a/clang/lib/CodeGen/CGVTT.cpp
+++ b/clang/lib/CodeGen/CGVTT.cpp
@@ -114,7 +114,7 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTT(const CXXRecordDecl *RD) {
llvm::ArrayType *ArrayType =
llvm::ArrayType::get(CGM.Int8PtrTy, Builder.getVTTComponents().size());
- unsigned Align = CGM.getDataLayout().getABITypeAlignment(CGM.Int8PtrTy);
+ llvm::Align Align = CGM.getDataLayout().getABITypeAlign(CGM.Int8PtrTy);
llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable(
Name, ArrayType, llvm::GlobalValue::ExternalLinkage, Align);
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index cdd40d2a6a2e..a0b5d9e4b096 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -128,7 +128,7 @@ static void resolveTopLevelMetadata(llvm::Function *Fn,
// Find all llvm.dbg.declare intrinsics and resolve the DILocalVariable nodes
// they are referencing.
- for (auto &BB : Fn->getBasicBlockList()) {
+ for (auto &BB : *Fn) {
for (auto &I : BB) {
if (auto *DII = dyn_cast<llvm::DbgVariableIntrinsic>(&I)) {
auto *DILocal = DII->getVariable();
@@ -664,6 +664,12 @@ void CodeGenVTables::addRelativeComponent(ConstantArrayBuilder &builder,
proxy->setVisibility(llvm::GlobalValue::HiddenVisibility);
proxy->setComdat(module.getOrInsertComdat(rttiProxyName));
}
+ // Do not instrument the rtti proxies with hwasan to avoid a duplicate
+ // symbol error. Aliases generated by hwasan will retain the same namebut
+ // the addresses they are set to may have different tags from different
+ // compilation units. We don't run into this without hwasan because the
+ // proxies are in comdat groups, but those aren't propagated to the alias.
+ RemoveHwasanMetadata(proxy);
}
target = proxy;
}
@@ -672,15 +678,23 @@ void CodeGenVTables::addRelativeComponent(ConstantArrayBuilder &builder,
/*position=*/vtableAddressPoint);
}
-bool CodeGenVTables::useRelativeLayout() const {
+static bool UseRelativeLayout(const CodeGenModule &CGM) {
return CGM.getTarget().getCXXABI().isItaniumFamily() &&
CGM.getItaniumVTableContext().isRelativeLayout();
}
+bool CodeGenVTables::useRelativeLayout() const {
+ return UseRelativeLayout(CGM);
+}
+
+llvm::Type *CodeGenModule::getVTableComponentType() const {
+ if (UseRelativeLayout(*this))
+ return Int32Ty;
+ return Int8PtrTy;
+}
+
llvm::Type *CodeGenVTables::getVTableComponentType() const {
- if (useRelativeLayout())
- return CGM.Int32Ty;
- return CGM.Int8PtrTy;
+ return CGM.getVTableComponentType();
}
static void AddPointerLayoutOffset(const CodeGenModule &CGM,
@@ -895,7 +909,7 @@ llvm::GlobalVariable *CodeGenVTables::GenerateConstructionVTable(
if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
Linkage = llvm::GlobalVariable::InternalLinkage;
- unsigned Align = CGM.getDataLayout().getABITypeAlignment(VTType);
+ llvm::Align Align = CGM.getDataLayout().getABITypeAlign(VTType);
// Create the variable that will hold the construction vtable.
llvm::GlobalVariable *VTable =
@@ -921,12 +935,33 @@ llvm::GlobalVariable *CodeGenVTables::GenerateConstructionVTable(
CGM.EmitVTableTypeMetadata(RD, VTable, *VTLayout.get());
- if (UsingRelativeLayout && !VTable->isDSOLocal())
- GenerateRelativeVTableAlias(VTable, OutName);
+ if (UsingRelativeLayout) {
+ RemoveHwasanMetadata(VTable);
+ if (!VTable->isDSOLocal())
+ GenerateRelativeVTableAlias(VTable, OutName);
+ }
return VTable;
}
+// Ensure this vtable is not instrumented by hwasan. That is, a global alias is
+// not generated for it. This is mainly used by the relative-vtables ABI where
+// vtables instead contain 32-bit offsets between the vtable and function
+// pointers. Hwasan is disabled for these vtables for now because the tag in a
+// vtable pointer may fail the overflow check when resolving 32-bit PLT
+// relocations. A future alternative for this would be finding which usages of
+// the vtable can continue to use the untagged hwasan value without any loss of
+// value in hwasan.
+void CodeGenVTables::RemoveHwasanMetadata(llvm::GlobalValue *GV) const {
+ if (CGM.getLangOpts().Sanitize.has(SanitizerKind::HWAddress)) {
+ llvm::GlobalValue::SanitizerMetadata Meta;
+ if (GV->hasSanitizerMetadata())
+ Meta = GV->getSanitizerMetadata();
+ Meta.NoHWAddress = true;
+ GV->setSanitizerMetadata(Meta);
+ }
+}
+
// If the VTable is not dso_local, then we will not be able to indicate that
// the VTable does not need a relocation and move into rodata. A frequent
// time this can occur is for classes that should be made public from a DSO
@@ -1254,8 +1289,7 @@ void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
if (!getCodeGenOpts().LTOUnit)
return;
- CharUnits PointerWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits ComponentWidth = GetTargetTypeStoreSize(getVTableComponentType());
typedef std::pair<const CXXRecordDecl *, unsigned> AddressPoint;
std::vector<AddressPoint> AddressPoints;
@@ -1293,7 +1327,7 @@ void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
ArrayRef<VTableComponent> Comps = VTLayout.vtable_components();
for (auto AP : AddressPoints) {
// Create type metadata for the address point.
- AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first);
+ AddVTableTypeMetadata(VTable, ComponentWidth * AP.second, AP.first);
// The class associated with each address point could also potentially be
// used for indirect calls via a member function pointer, so we need to
@@ -1306,7 +1340,7 @@ void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
Context.getMemberPointerType(
Comps[I].getFunctionDecl()->getType(),
Context.getRecordType(AP.first).getTypePtr()));
- VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD);
+ VTable->addTypeMetadata((ComponentWidth * I).getQuantity(), MD);
}
}
diff --git a/clang/lib/CodeGen/CGVTables.h b/clang/lib/CodeGen/CGVTables.h
index bdfc075ee305..e7b59d94f257 100644
--- a/clang/lib/CodeGen/CGVTables.h
+++ b/clang/lib/CodeGen/CGVTables.h
@@ -102,6 +102,10 @@ public:
return *cast<ItaniumVTableContext>(VTContext);
}
+ const ItaniumVTableContext &getItaniumVTableContext() const {
+ return *cast<ItaniumVTableContext>(VTContext);
+ }
+
MicrosoftVTableContext &getMicrosoftVTableContext() {
return *cast<MicrosoftVTableContext>(VTContext);
}
@@ -154,6 +158,9 @@ public:
/// when a vtable may not be dso_local.
void GenerateRelativeVTableAlias(llvm::GlobalVariable *VTable,
llvm::StringRef AliasNameRef);
+
+ /// Specify a global should not be instrumented with hwasan.
+ void RemoveHwasanMetadata(llvm::GlobalValue *GV) const;
};
} // end namespace CodeGen
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index 12c6b3f49c43..2b219267869e 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -49,6 +49,7 @@
#include "llvm/Transforms/IPO/Internalize.h"
#include <memory>
+#include <optional>
using namespace clang;
using namespace llvm;
@@ -422,7 +423,8 @@ namespace clang {
bool &BadDebugInfo, StringRef &Filename,
unsigned &Line, unsigned &Column) const;
- Optional<FullSourceLoc> getFunctionSourceLocation(const Function &F) const;
+ std::optional<FullSourceLoc>
+ getFunctionSourceLocation(const Function &F) const;
void DiagnosticHandlerImpl(const llvm::DiagnosticInfo &DI);
/// Specialized handler for InlineAsm diagnostic.
@@ -435,6 +437,11 @@ namespace clang {
/// \return True if the diagnostic has been successfully reported, false
/// otherwise.
bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D);
+ /// Specialized handler for ResourceLimit diagnostic.
+ /// \return True if the diagnostic has been successfully reported, false
+ /// otherwise.
+ bool ResourceLimitDiagHandler(const llvm::DiagnosticInfoResourceLimit &D);
+
/// Specialized handler for unsupported backend feature diagnostic.
void UnsupportedDiagHandler(const llvm::DiagnosticInfoUnsupported &D);
/// Specialized handlers for optimization remarks.
@@ -623,10 +630,23 @@ BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) {
if (!Loc)
return false;
- // FIXME: Shouldn't need to truncate to uint32_t
Diags.Report(*Loc, diag::warn_fe_frame_larger_than)
- << static_cast<uint32_t>(D.getStackSize())
- << static_cast<uint32_t>(D.getStackLimit())
+ << D.getStackSize()
+ << D.getStackLimit()
+ << llvm::demangle(D.getFunction().getName().str());
+ return true;
+}
+
+bool BackendConsumer::ResourceLimitDiagHandler(
+ const llvm::DiagnosticInfoResourceLimit &D) {
+ auto Loc = getFunctionSourceLocation(D.getFunction());
+ if (!Loc)
+ return false;
+ unsigned DiagID = diag::err_fe_backend_resource_limit;
+ ComputeDiagID(D.getSeverity(), backend_resource_limit, DiagID);
+
+ Diags.Report(*Loc, DiagID)
+ << D.getResourceName() << D.getResourceSize() << D.getResourceLimit()
<< llvm::demangle(D.getFunction().getName().str());
return true;
}
@@ -673,14 +693,14 @@ const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc(
return Loc;
}
-Optional<FullSourceLoc>
+std::optional<FullSourceLoc>
BackendConsumer::getFunctionSourceLocation(const Function &F) const {
auto Hash = llvm::hash_value(F.getName());
for (const auto &Pair : ManglingFullSourceLocs) {
if (Pair.first == Hash)
return Pair.second;
}
- return Optional<FullSourceLoc>();
+ return std::nullopt;
}
void BackendConsumer::UnsupportedDiagHandler(
@@ -874,6 +894,11 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
return;
ComputeDiagID(Severity, backend_frame_larger_than, DiagID);
break;
+ case llvm::DK_ResourceLimit:
+ if (ResourceLimitDiagHandler(cast<DiagnosticInfoResourceLimit>(DI)))
+ return;
+ ComputeDiagID(Severity, backend_resource_limit, DiagID);
+ break;
case DK_Linker:
ComputeDiagID(Severity, linking_module, DiagID);
break;
@@ -1078,6 +1103,8 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) {
CompilerInstance &CI = getCompilerInstance();
SourceManager &SM = CI.getSourceManager();
+ VMContext->setOpaquePointers(CI.getCodeGenOpts().OpaquePointers);
+
// For ThinLTO backend invocations, ensure that the context
// merges types based on ODR identifiers. We also need to read
// the correct module out of a multi-module bitcode file.
@@ -1157,7 +1184,7 @@ void CodeGenAction::ExecuteAction() {
SourceManager &SM = CI.getSourceManager();
FileID FID = SM.getMainFileID();
- Optional<MemoryBufferRef> MainFile = SM.getBufferOrNone(FID);
+ std::optional<MemoryBufferRef> MainFile = SM.getBufferOrNone(FID);
if (!MainFile)
return;
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 5012bd822bd3..8cbe2a540744 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -16,6 +16,7 @@
#include "CGCXXABI.h"
#include "CGCleanup.h"
#include "CGDebugInfo.h"
+#include "CGHLSLRuntime.h"
#include "CGOpenMPRuntime.h"
#include "CodeGenModule.h"
#include "CodeGenPGO.h"
@@ -45,6 +46,7 @@
#include "llvm/Support/CRC.h"
#include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -172,10 +174,11 @@ void CodeGenFunction::CGFPOptionsRAII::ConstructorHelper(FPOptions FPFeatures) {
mergeFnAttrValue("no-infs-fp-math", FPFeatures.getNoHonorInfs());
mergeFnAttrValue("no-nans-fp-math", FPFeatures.getNoHonorNaNs());
mergeFnAttrValue("no-signed-zeros-fp-math", FPFeatures.getNoSignedZero());
- mergeFnAttrValue("unsafe-fp-math", FPFeatures.getAllowFPReassociate() &&
- FPFeatures.getAllowReciprocal() &&
- FPFeatures.getAllowApproxFunc() &&
- FPFeatures.getNoSignedZero());
+ mergeFnAttrValue(
+ "unsafe-fp-math",
+ FPFeatures.getAllowFPReassociate() && FPFeatures.getAllowReciprocal() &&
+ FPFeatures.getAllowApproxFunc() && FPFeatures.getNoSignedZero() &&
+ FPFeatures.allowFPContractAcrossStatement());
}
CodeGenFunction::CGFPOptionsRAII::~CGFPOptionsRAII() {
@@ -317,8 +320,10 @@ llvm::DebugLoc CodeGenFunction::EmitReturnBlock() {
static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
if (!BB) return;
- if (!BB->use_empty())
- return CGF.CurFn->getBasicBlockList().push_back(BB);
+ if (!BB->use_empty()) {
+ CGF.CurFn->insert(CGF.CurFn->end(), BB);
+ return;
+ }
delete BB;
}
@@ -356,17 +361,18 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
bool HasOnlyLifetimeMarkers =
HasCleanups && EHStack.containsOnlyLifetimeMarkers(PrologueCleanupDepth);
bool EmitRetDbgLoc = !HasCleanups || HasOnlyLifetimeMarkers;
+
+ std::optional<ApplyDebugLocation> OAL;
if (HasCleanups) {
// Make sure the line table doesn't jump back into the body for
// the ret after it's been at EndLoc.
- Optional<ApplyDebugLocation> AL;
if (CGDebugInfo *DI = getDebugInfo()) {
if (OnlySimpleReturnStmts)
DI->EmitLocation(Builder, EndLoc);
else
// We may not have a valid end location. Try to apply it anyway, and
// fall back to an artificial location if needed.
- AL = ApplyDebugLocation::CreateDefaultArtificial(*this, EndLoc);
+ OAL = ApplyDebugLocation::CreateDefaultArtificial(*this, EndLoc);
}
PopCleanupBlocks(PrologueCleanupDepth);
@@ -477,13 +483,13 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
if (auto *VT = dyn_cast<llvm::VectorType>(A.getType()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
- VT->getPrimitiveSizeInBits().getKnownMinSize());
+ VT->getPrimitiveSizeInBits().getKnownMinValue());
// Update vector width based on return type.
if (auto *VT = dyn_cast<llvm::VectorType>(CurFn->getReturnType()))
LargestVectorWidth =
std::max((uint64_t)LargestVectorWidth,
- VT->getPrimitiveSizeInBits().getKnownMinSize());
+ VT->getPrimitiveSizeInBits().getKnownMinValue());
if (CurFnInfo->getMaxVectorWidth() > LargestVectorWidth)
LargestVectorWidth = CurFnInfo->getMaxVectorWidth();
@@ -495,10 +501,12 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// 4. Width of vector arguments and return types for this function.
// 5. Width of vector aguments and return types for functions called by this
// function.
- CurFn->addFnAttr("min-legal-vector-width", llvm::utostr(LargestVectorWidth));
+ if (getContext().getTargetInfo().getTriple().isX86())
+ CurFn->addFnAttr("min-legal-vector-width",
+ llvm::utostr(LargestVectorWidth));
// Add vscale_range attribute if appropriate.
- Optional<std::pair<unsigned, unsigned>> VScaleRange =
+ std::optional<std::pair<unsigned, unsigned>> VScaleRange =
getContext().getTargetInfo().getVScaleRange(getLangOpts());
if (VScaleRange) {
CurFn->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs(
@@ -699,7 +707,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
CurCodeDecl = D;
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
if (FD && FD->usesSEHTry())
- CurSEHParent = FD;
+ CurSEHParent = GD;
CurFuncDecl = (D ? D->getNonClosureContext() : nullptr);
FnRetTy = RetTy;
CurFn = Fn;
@@ -724,7 +732,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
const bool SanitizeBounds = SanOpts.hasOneOf(SanitizerKind::Bounds);
bool NoSanitizeCoverage = false;
- for (auto Attr : D->specific_attrs<NoSanitizeAttr>()) {
+ for (auto *Attr : D->specific_attrs<NoSanitizeAttr>()) {
// Apply the no_sanitize* attributes to SanOpts.
SanitizerMask mask = Attr->getMask();
SanOpts.Mask &= ~mask;
@@ -842,8 +850,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
auto FuncGroups = CGM.getCodeGenOpts().XRayTotalFunctionGroups;
if (FuncGroups > 1) {
- auto FuncName = llvm::makeArrayRef<uint8_t>(
- CurFn->getName().bytes_begin(), CurFn->getName().bytes_end());
+ auto FuncName = llvm::ArrayRef<uint8_t>(CurFn->getName().bytes_begin(),
+ CurFn->getName().bytes_end());
auto Group = crc32(FuncName) % FuncGroups;
if (Group != CGM.getCodeGenOpts().XRaySelectedFunctionGroup &&
!AlwaysXRayAttr)
@@ -851,9 +859,18 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}
}
- if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone)
- if (CGM.isFunctionBlockedFromProfileInstr(Fn, Loc))
+ if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone) {
+ switch (CGM.isFunctionBlockedFromProfileInstr(Fn, Loc)) {
+ case ProfileList::Skip:
+ Fn->addFnAttr(llvm::Attribute::SkipProfile);
+ break;
+ case ProfileList::Forbid:
Fn->addFnAttr(llvm::Attribute::NoProfile);
+ break;
+ case ProfileList::Allow:
+ break;
+ }
+ }
unsigned Count, Offset;
if (const auto *Attr =
@@ -874,7 +891,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// backends as they don't need it -- instructions on these architectures are
// always atomically patchable at runtime.
if (CGM.getCodeGenOpts().HotPatch &&
- getContext().getTargetInfo().getTriple().isX86())
+ getContext().getTargetInfo().getTriple().isX86() &&
+ getContext().getTargetInfo().getTriple().getEnvironment() !=
+ llvm::Triple::CODE16)
Fn->addFnAttr("patchable-function", "prologue-short-redirect");
// Add no-jump-tables value.
@@ -941,7 +960,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// If we're checking nullability, we need to know whether we can check the
// return value. Initialize the flag to 'true' and refine it in EmitParmDecl.
if (SanOpts.has(SanitizerKind::NullabilityReturn)) {
- auto Nullability = FnRetTy->getNullability(getContext());
+ auto Nullability = FnRetTy->getNullability();
if (Nullability && *Nullability == NullabilityKind::NonNull) {
if (!(SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) &&
CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>()))
@@ -1128,6 +1147,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
if (getLangOpts().OpenMP && CurCodeDecl)
CGM.getOpenMPRuntime().emitFunctionProlog(*this, CurCodeDecl);
+ // Handle emitting HLSL entry functions.
+ if (D && D->hasAttr<HLSLShaderAttr>())
+ CGM.getHLSLRuntime().emitEntryFunction(FD, Fn);
+
EmitFunctionProlog(*CurFnInfo, CurFn, Args);
if (isa_and_nonnull<CXXMethodDecl>(D) &&
@@ -1450,7 +1473,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
llvm::Value *IsFalse = Builder.getFalse();
EmitCheck(std::make_pair(IsFalse, SanitizerKind::Return),
SanitizerHandler::MissingReturn,
- EmitCheckSourceLocation(FD->getLocation()), None);
+ EmitCheckSourceLocation(FD->getLocation()), std::nullopt);
} else if (ShouldEmitUnreachable) {
if (CGM.getCodeGenOpts().OptimizationLevel == 0)
EmitTrapCall(llvm::Intrinsic::trap);
@@ -2214,7 +2237,6 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::ConstantMatrix:
case Type::Record:
case Type::Enum:
- case Type::Elaborated:
case Type::Using:
case Type::TemplateSpecialization:
case Type::ObjCTypeParam:
@@ -2224,6 +2246,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::BitInt:
llvm_unreachable("type class is never variably-modified!");
+ case Type::Elaborated:
+ type = cast<ElaboratedType>(ty)->getNamedType();
+ break;
+
case Type::Adjusted:
type = cast<AdjustedType>(ty)->getAdjustedType();
break;
@@ -2426,8 +2452,6 @@ void CodeGenFunction::emitAlignmentAssumption(llvm::Value *PtrValue,
SourceLocation AssumptionLoc,
llvm::Value *Alignment,
llvm::Value *OffsetValue) {
- if (auto *CE = dyn_cast<CastExpr>(E))
- E = CE->getSubExprAsWritten();
QualType Ty = E->getType();
SourceLocation Loc = E->getExprLoc();
@@ -2442,8 +2466,10 @@ llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Function *AnnotationFn,
const AnnotateAttr *Attr) {
SmallVector<llvm::Value *, 5> Args = {
AnnotatedVal,
- Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr), Int8PtrTy),
- Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location), Int8PtrTy),
+ Builder.CreateBitCast(CGM.EmitAnnotationString(AnnotationStr),
+ ConstGlobalsPtrTy),
+ Builder.CreateBitCast(CGM.EmitAnnotationUnit(Location),
+ ConstGlobalsPtrTy),
CGM.EmitAnnotationLineNo(Location),
};
if (Attr)
@@ -2455,9 +2481,12 @@ void CodeGenFunction::EmitVarAnnotations(const VarDecl *D, llvm::Value *V) {
assert(D->hasAttr<AnnotateAttr>() && "no annotate attribute");
// FIXME We create a new bitcast for every annotation because that's what
// llvm-gcc was doing.
+ unsigned AS = V->getType()->getPointerAddressSpace();
+ llvm::Type *I8PtrTy = Builder.getInt8PtrTy(AS);
for (const auto *I : D->specific_attrs<AnnotateAttr>())
- EmitAnnotationCall(CGM.getIntrinsic(llvm::Intrinsic::var_annotation),
- Builder.CreateBitCast(V, CGM.Int8PtrTy, V->getName()),
+ EmitAnnotationCall(CGM.getIntrinsic(llvm::Intrinsic::var_annotation,
+ {I8PtrTy, CGM.ConstGlobalsPtrTy}),
+ Builder.CreateBitCast(V, I8PtrTy, V->getName()),
I->getAnnotation(), D->getLocation(), I);
}
@@ -2470,8 +2499,8 @@ Address CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D,
unsigned AS = PTy ? PTy->getAddressSpace() : 0;
llvm::PointerType *IntrinTy =
llvm::PointerType::getWithSamePointeeType(CGM.Int8PtrTy, AS);
- llvm::Function *F =
- CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation, IntrinTy);
+ llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation,
+ {IntrinTy, CGM.ConstGlobalsPtrTy});
for (const auto *I : D->specific_attrs<AnnotateAttr>()) {
// FIXME Always emit the cast inst so we can differentiate between
@@ -2594,8 +2623,30 @@ void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) {
CGM.getSanStats().create(IRB, SSK);
}
-llvm::Value *
-CodeGenFunction::FormResolverCondition(const MultiVersionResolverOption &RO) {
+void CodeGenFunction::EmitKCFIOperandBundle(
+ const CGCallee &Callee, SmallVectorImpl<llvm::OperandBundleDef> &Bundles) {
+ const FunctionProtoType *FP =
+ Callee.getAbstractInfo().getCalleeFunctionProtoType();
+ if (FP)
+ Bundles.emplace_back("kcfi", CGM.CreateKCFITypeId(FP->desugar()));
+}
+
+llvm::Value *CodeGenFunction::FormAArch64ResolverCondition(
+ const MultiVersionResolverOption &RO) {
+ llvm::SmallVector<StringRef, 8> CondFeatures;
+ for (const StringRef &Feature : RO.Conditions.Features) {
+ // Form condition for features which are not yet enabled in target
+ if (!getContext().getTargetInfo().hasFeature(Feature))
+ CondFeatures.push_back(Feature);
+ }
+ if (!CondFeatures.empty()) {
+ return EmitAArch64CpuSupports(CondFeatures);
+ }
+ return nullptr;
+}
+
+llvm::Value *CodeGenFunction::FormX86ResolverCondition(
+ const MultiVersionResolverOption &RO) {
llvm::Value *Condition = nullptr;
if (!RO.Conditions.Architecture.empty())
@@ -2633,8 +2684,72 @@ static void CreateMultiVersionResolverReturn(CodeGenModule &CGM,
void CodeGenFunction::EmitMultiVersionResolver(
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
- assert(getContext().getTargetInfo().getTriple().isX86() &&
- "Only implemented for x86 targets");
+
+ llvm::Triple::ArchType ArchType =
+ getContext().getTargetInfo().getTriple().getArch();
+
+ switch (ArchType) {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ EmitX86MultiVersionResolver(Resolver, Options);
+ return;
+ case llvm::Triple::aarch64:
+ EmitAArch64MultiVersionResolver(Resolver, Options);
+ return;
+
+ default:
+ assert(false && "Only implemented for x86 and AArch64 targets");
+ }
+}
+
+void CodeGenFunction::EmitAArch64MultiVersionResolver(
+ llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
+ assert(!Options.empty() && "No multiversion resolver options found");
+ assert(Options.back().Conditions.Features.size() == 0 &&
+ "Default case must be last");
+ bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
+ assert(SupportsIFunc &&
+ "Multiversion resolver requires target IFUNC support");
+ bool AArch64CpuInitialized = false;
+ llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver);
+
+ for (const MultiVersionResolverOption &RO : Options) {
+ Builder.SetInsertPoint(CurBlock);
+ llvm::Value *Condition = FormAArch64ResolverCondition(RO);
+
+ // The 'default' or 'all features enabled' case.
+ if (!Condition) {
+ CreateMultiVersionResolverReturn(CGM, Resolver, Builder, RO.Function,
+ SupportsIFunc);
+ return;
+ }
+
+ if (!AArch64CpuInitialized) {
+ Builder.SetInsertPoint(CurBlock, CurBlock->begin());
+ EmitAArch64CpuInit();
+ AArch64CpuInitialized = true;
+ Builder.SetInsertPoint(CurBlock);
+ }
+
+ llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver);
+ CGBuilderTy RetBuilder(*this, RetBlock);
+ CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, RO.Function,
+ SupportsIFunc);
+ CurBlock = createBasicBlock("resolver_else", Resolver);
+ Builder.CreateCondBr(Condition, RetBlock, CurBlock);
+ }
+
+ // If no default, emit an unreachable.
+ Builder.SetInsertPoint(CurBlock);
+ llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
+ TrapCall->setDoesNotReturn();
+ TrapCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
+}
+
+void CodeGenFunction::EmitX86MultiVersionResolver(
+ llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
@@ -2645,7 +2760,7 @@ void CodeGenFunction::EmitMultiVersionResolver(
for (const MultiVersionResolverOption &RO : Options) {
Builder.SetInsertPoint(CurBlock);
- llvm::Value *Condition = FormResolverCondition(RO);
+ llvm::Value *Condition = FormX86ResolverCondition(RO);
// The 'default' or 'generic' case.
if (!Condition) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index fe0890f433e8..a535aa7c0410 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -41,6 +41,7 @@
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
+#include <optional>
namespace llvm {
class BasicBlock;
@@ -539,7 +540,7 @@ public:
/// potentially set the return value.
bool SawAsmBlock = false;
- const NamedDecl *CurSEHParent = nullptr;
+ GlobalDecl CurSEHParent;
/// True if the current function is an outlined SEH helper. This can be a
/// finally block or filter expression.
@@ -570,7 +571,7 @@ public:
return false;
// C++11 and later guarantees that a thread eventually will do one of the
- // following (6.9.2.3.1 in C++11):
+ // following (C++11 [intro.multithread]p24 and C++17 [intro.progress]p1):
// - terminate,
// - make a call to a library I/O function,
// - perform an access through a volatile glvalue, or
@@ -609,7 +610,7 @@ public:
const CodeGen::CGBlockInfo *BlockInfo = nullptr;
llvm::Value *BlockPointer = nullptr;
- llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
FieldDecl *LambdaThisCaptureField = nullptr;
/// A mapping from NRVO variables to the flags used to indicate
@@ -723,7 +724,7 @@ public:
FPOptions OldFPFeatures;
llvm::fp::ExceptionBehavior OldExcept;
llvm::RoundingMode OldRounding;
- Optional<CGBuilderTy::FastMathFlagGuard> FMFGuard;
+ std::optional<CGBuilderTy::FastMathFlagGuard> FMFGuard;
};
FPOptions CurFPFeatures;
@@ -1094,7 +1095,7 @@ public:
void ForceCleanup() {
RunCleanupsScope::ForceCleanup();
- MappedVars.restore(CGF);
+ restoreMap();
}
/// Exit scope - all the mapped variables are restored.
@@ -1108,6 +1109,11 @@ public:
VD = VD->getCanonicalDecl();
return !VD->isLocalVarDeclOrParm() && CGF.LocalDeclMap.count(VD) > 0;
}
+
+ /// Restore all mapped variables w/o clean up. This is usefully when we want
+ /// to reference the original variables but don't want the clean up because
+ /// that could emit lifetime end too early, causing backend issue #56913.
+ void restoreMap() { MappedVars.restore(CGF); }
};
/// Save/restore original map of previously emitted local vars in case when we
@@ -1522,7 +1528,8 @@ public:
/// If \p StepV is null, the default increment is 1.
void incrementProfileCounter(const Stmt *S, llvm::Value *StepV = nullptr) {
if (CGM.getCodeGenOpts().hasProfileClangInstr() &&
- !CurFn->hasFnAttribute(llvm::Attribute::NoProfile))
+ !CurFn->hasFnAttribute(llvm::Attribute::NoProfile) &&
+ !CurFn->hasFnAttribute(llvm::Attribute::SkipProfile))
PGO.emitCounterIncrement(Builder, S, StepV);
PGO.setCurrentStmt(S);
}
@@ -2015,7 +2022,7 @@ public:
return getInvokeDestImpl();
}
- bool currentFunctionUsesSEHTry() const { return CurSEHParent != nullptr; }
+ bool currentFunctionUsesSEHTry() const { return !!CurSEHParent; }
const TargetInfo &getTarget() const { return Target; }
llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
@@ -2225,7 +2232,7 @@ public:
/// Emit the unified return block, trying to avoid its emission when
/// possible.
/// \return The debug location of the user written return statement if the
- /// return block is is avoided.
+ /// return block is avoided.
llvm::DebugLoc EmitReturnBlock();
/// FinishFunction - Complete IR generation of the current function. It is
@@ -2878,7 +2885,7 @@ public:
AggValueSlot::Overlap_t Overlap,
SourceLocation Loc, bool NewPointerIsChecked);
- /// Emit assumption load for all bases. Requires to be be called only on
+ /// Emit assumption load for all bases. Requires to be called only on
/// most-derived class and not under construction of the object.
void EmitVTableAssumptionLoads(const CXXRecordDecl *ClassDecl, Address This);
@@ -3207,7 +3214,7 @@ public:
/// This function may clear the current insertion point; callers should use
/// EnsureInsertPoint if they wish to subsequently generate code without first
/// calling EmitBlock, EmitBranch, or EmitStmt.
- void EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs = None);
+ void EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs = std::nullopt);
/// EmitSimpleStmt - Try to emit a "simple" statement which does not
/// necessarily require an insertion point or debug information; typically
@@ -3235,10 +3242,10 @@ public:
void EmitIfStmt(const IfStmt &S);
void EmitWhileStmt(const WhileStmt &S,
- ArrayRef<const Attr *> Attrs = None);
- void EmitDoStmt(const DoStmt &S, ArrayRef<const Attr *> Attrs = None);
+ ArrayRef<const Attr *> Attrs = std::nullopt);
+ void EmitDoStmt(const DoStmt &S, ArrayRef<const Attr *> Attrs = std::nullopt);
void EmitForStmt(const ForStmt &S,
- ArrayRef<const Attr *> Attrs = None);
+ ArrayRef<const Attr *> Attrs = std::nullopt);
void EmitReturnStmt(const ReturnStmt &S);
void EmitDeclStmt(const DeclStmt &S);
void EmitBreakStmt(const BreakStmt &S);
@@ -3315,7 +3322,7 @@ public:
llvm::Value *ParentFP);
void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
- ArrayRef<const Attr *> Attrs = None);
+ ArrayRef<const Attr *> Attrs = std::nullopt);
/// Controls insertion of cancellation exit blocks in worksharing constructs.
class OMPCancelStackRAII {
@@ -3514,6 +3521,7 @@ public:
void EmitOMPParallelMasterDirective(const OMPParallelMasterDirective &S);
void EmitOMPTaskDirective(const OMPTaskDirective &S);
void EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S);
+ void EmitOMPErrorDirective(const OMPErrorDirective &S);
void EmitOMPBarrierDirective(const OMPBarrierDirective &S);
void EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S);
void EmitOMPTaskgroupDirective(const OMPTaskgroupDirective &S);
@@ -3967,6 +3975,8 @@ public:
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
+ llvm::Value *EmitIvarOffsetAsPointerDiff(const ObjCInterfaceDecl *Interface,
+ const ObjCIvarDecl *Ivar);
LValue EmitLValueForField(LValue Base, const FieldDecl* Field);
LValue EmitLValueForLambdaField(const FieldDecl *Field);
@@ -4194,6 +4204,12 @@ public:
llvm::Type *getEltType(const SVETypeFlags &TypeFlags);
llvm::ScalableVectorType *getSVEType(const SVETypeFlags &TypeFlags);
llvm::ScalableVectorType *getSVEPredType(const SVETypeFlags &TypeFlags);
+ llvm::Value *EmitSVETupleSetOrGet(const SVETypeFlags &TypeFlags,
+ llvm::Type *ReturnType,
+ ArrayRef<llvm::Value *> Ops);
+ llvm::Value *EmitSVETupleCreate(const SVETypeFlags &TypeFlags,
+ llvm::Type *ReturnType,
+ ArrayRef<llvm::Value *> Ops);
llvm::Value *EmitSVEAllTruePred(const SVETypeFlags &TypeFlags);
llvm::Value *EmitSVEDupX(llvm::Value *Scalar);
llvm::Value *EmitSVEDupX(llvm::Value *Scalar, llvm::Type *Ty);
@@ -4247,7 +4263,8 @@ public:
llvm::Value *EmitHexagonBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue);
- bool ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope,
+ llvm::Value *EmitLoongArchBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
+ void ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope,
llvm::AtomicOrdering &AO,
llvm::SyncScope::ID &SSID);
@@ -4403,6 +4420,11 @@ public:
/// EmitLoadOfComplex - Load a complex number from the specified l-value.
ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc);
+ ComplexPairTy EmitPromotedComplexExpr(const Expr *E, QualType PromotionType);
+ llvm::Value *EmitPromotedScalarExpr(const Expr *E, QualType PromotionType);
+ ComplexPairTy EmitPromotedValue(ComplexPairTy result, QualType PromotionType);
+ ComplexPairTy EmitUnPromotedValue(ComplexPairTy result, QualType PromotionType);
+
Address emitAddrOfRealComponent(Address complex, QualType complexType);
Address emitAddrOfImagComponent(Address complex, QualType complexType);
@@ -4600,6 +4622,9 @@ public:
/// passing to a runtime sanitizer handler.
llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
+ void EmitKCFIOperandBundle(const CGCallee &Callee,
+ SmallVectorImpl<llvm::OperandBundleDef> &Bundles);
+
/// Create a basic block that will either trap or call a handler function in
/// the UBSan runtime with the provided arguments, and create a conditional
/// branch to it.
@@ -4789,6 +4814,12 @@ public:
// last (if it exists).
void EmitMultiVersionResolver(llvm::Function *Resolver,
ArrayRef<MultiVersionResolverOption> Options);
+ void
+ EmitX86MultiVersionResolver(llvm::Function *Resolver,
+ ArrayRef<MultiVersionResolverOption> Options);
+ void
+ EmitAArch64MultiVersionResolver(llvm::Function *Resolver,
+ ArrayRef<MultiVersionResolverOption> Options);
private:
QualType getVarArgType(const Expr *Arg);
@@ -4807,7 +4838,11 @@ private:
llvm::Value *EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs);
llvm::Value *EmitX86CpuSupports(uint64_t Mask);
llvm::Value *EmitX86CpuInit();
- llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO);
+ llvm::Value *FormX86ResolverCondition(const MultiVersionResolverOption &RO);
+ llvm::Value *EmitAArch64CpuInit();
+ llvm::Value *
+ FormAArch64ResolverCondition(const MultiVersionResolverOption &RO);
+ llvm::Value *EmitAArch64CpuSupports(ArrayRef<StringRef> FeatureStrs);
};
@@ -4817,9 +4852,9 @@ DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) {
// Otherwise, we need an alloca.
auto align = CharUnits::fromQuantity(
- CGF.CGM.getDataLayout().getPrefTypeAlignment(value->getType()));
+ CGF.CGM.getDataLayout().getPrefTypeAlign(value->getType()));
Address alloca =
- CGF.CreateTempAlloca(value->getType(), align, "cond-cleanup.save");
+ CGF.CreateTempAlloca(value->getType(), align, "cond-cleanup.save");
CGF.Builder.CreateStore(value, alloca);
return saved_type(alloca.getPointer(), true);
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 4e8e120d89df..12d602fed693 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -47,6 +47,8 @@
#include "clang/CodeGen/BackendUtil.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
@@ -58,14 +60,16 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/ProfileSummary.h"
#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/ProfileData/SampleProf.h"
#include "llvm/Support/CRC.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MD5.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/X86TargetParser.h"
+#include "llvm/Support/xxhash.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
@@ -120,9 +124,10 @@ CodeGenModule::CodeGenModule(ASTContext &C,
BFloatTy = llvm::Type::getBFloatTy(LLVMContext);
FloatTy = llvm::Type::getFloatTy(LLVMContext);
DoubleTy = llvm::Type::getDoubleTy(LLVMContext);
- PointerWidthInBits = C.getTargetInfo().getPointerWidth(0);
+ PointerWidthInBits = C.getTargetInfo().getPointerWidth(LangAS::Default);
PointerAlignInBytes =
- C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(0)).getQuantity();
+ C.toCharUnitsFromBits(C.getTargetInfo().getPointerAlign(LangAS::Default))
+ .getQuantity();
SizeSizeInBytes =
C.toCharUnitsFromBits(C.getTargetInfo().getMaxPointerWidth()).getQuantity();
IntAlignInBytes =
@@ -137,6 +142,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
const llvm::DataLayout &DL = M.getDataLayout();
AllocaInt8PtrTy = Int8Ty->getPointerTo(DL.getAllocaAddrSpace());
GlobalsInt8PtrTy = Int8Ty->getPointerTo(DL.getDefaultGlobalsAddressSpace());
+ ConstGlobalsPtrTy = Int8Ty->getPointerTo(
+ C.getTargetAddressSpace(GetGlobalConstantAddressSpace()));
ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace();
// Build C++20 Module initializers.
@@ -179,15 +186,11 @@ CodeGenModule::CodeGenModule(ASTContext &C,
if (CodeGenOpts.hasProfileClangUse()) {
auto ReaderOrErr = llvm::IndexedInstrProfReader::create(
CodeGenOpts.ProfileInstrumentUsePath, CodeGenOpts.ProfileRemappingFile);
- if (auto E = ReaderOrErr.takeError()) {
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "Could not read profile %0: %1");
- llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) {
- getDiags().Report(DiagID) << CodeGenOpts.ProfileInstrumentUsePath
- << EI.message();
- });
- } else
- PGOReader = std::move(ReaderOrErr.get());
+ // We're checking for profile read errors in CompilerInvocation, so if
+ // there was an error it should've already been caught. If it hasn't been
+ // somehow, trip an assertion.
+ assert(ReaderOrErr);
+ PGOReader = std::move(ReaderOrErr.get());
}
// If coverage mapping generation is enabled, create the
@@ -205,22 +208,7 @@ CodeGenModule::CodeGenModule(ASTContext &C,
Path = Entry.second + Path.substr(Entry.first.size());
break;
}
- llvm::MD5 Md5;
- Md5.update(Path);
- llvm::MD5::MD5Result R;
- Md5.final(R);
- SmallString<32> Str;
- llvm::MD5::stringifyResult(R, Str);
- // Convert MD5hash to Decimal. Demangler suffixes can either contain
- // numbers or characters but not both.
- llvm::APInt IntHash(128, Str.str(), 16);
- // Prepend "__uniq" before the hash for tools like profilers to understand
- // that this symbol is of internal linkage type. The "__uniq" is the
- // pre-determined prefix that is used to tell tools that this symbol was
- // created with -funique-internal-linakge-symbols and the tools can strip or
- // keep the prefix as needed.
- ModuleNameHash = (Twine(".__uniq.") +
- Twine(toString(IntHash, /* Radix = */ 10, /* Signed = */false))).str();
+ ModuleNameHash = llvm::getUniqueInternalLinkagePostfix(Path);
}
}
@@ -521,7 +509,7 @@ static void setVisibilityFromDLLStorageClass(const clang::LangOptions &LO,
void CodeGenModule::Release() {
Module *Primary = getContext().getModuleForCodeGen();
- if (CXX20ModuleInits && Primary && !Primary->isModuleMapModule())
+ if (CXX20ModuleInits && Primary && !Primary->isHeaderLikeModule())
EmitModuleInitializers(Primary);
EmitDeferred();
DeferredDecls.insert(EmittedDeferredDecls.begin(),
@@ -531,6 +519,14 @@ void CodeGenModule::Release() {
applyGlobalValReplacements();
applyReplacements();
emitMultiVersionFunctions();
+
+ if (Context.getLangOpts().IncrementalExtensions &&
+ GlobalTopLevelStmtBlockInFlight.first) {
+ const TopLevelStmtDecl *TLSD = GlobalTopLevelStmtBlockInFlight.second;
+ GlobalTopLevelStmtBlockInFlight.first->FinishFunction(TLSD->getEndLoc());
+ GlobalTopLevelStmtBlockInFlight = {nullptr, nullptr};
+ }
+
if (CXX20ModuleInits && Primary && Primary->isInterfaceOrPartition())
EmitCXXModuleInitFunc(Primary);
else
@@ -560,6 +556,9 @@ void CodeGenModule::Release() {
if (PGOStats.hasDiagnostics())
PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName);
}
+ llvm::stable_sort(GlobalCtors, [](const Structor &L, const Structor &R) {
+ return L.LexOrder < R.LexOrder;
+ });
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
EmitGlobalAnnotations();
@@ -573,6 +572,8 @@ void CodeGenModule::Release() {
CodeGenFunction(*this).EmitCfiCheckFail();
CodeGenFunction(*this).EmitCfiCheckStub();
}
+ if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
+ finalizeKCFITypes();
emitAtAvailableLinkGuard();
if (Context.getTargetInfo().getTriple().isWasm())
EmitMainVoidAlias();
@@ -594,9 +595,8 @@ void CodeGenModule::Release() {
}
// Emit amdgpu_code_object_version module flag, which is code object version
// times 100.
- // ToDo: Enable module flag for all code object version when ROCm device
- // library is ready.
- if (getTarget().getTargetOpts().CodeObjectVersion == TargetOptions::COV_5) {
+ if (getTarget().getTargetOpts().CodeObjectVersion !=
+ TargetOptions::COV_None) {
getModule().addModuleFlag(llvm::Module::Error,
"amdgpu_code_object_version",
getTarget().getTargetOpts().CodeObjectVersion);
@@ -689,6 +689,10 @@ void CodeGenModule::Release() {
// Function ID tables for EH Continuation Guard.
getModule().addModuleFlag(llvm::Module::Warning, "ehcontguard", 1);
}
+ if (Context.getLangOpts().Kernel) {
+ // Note if we are compiling with /kernel.
+ getModule().addModuleFlag(llvm::Module::Warning, "ms-kernel", 1);
+ }
if (CodeGenOpts.OptimizationLevel > 0 && CodeGenOpts.StrictVTablePointers) {
// We don't support LTO with 2 with different StrictVTablePointers
// FIXME: we could support it by stripping all the information introduced
@@ -755,6 +759,15 @@ void CodeGenModule::Release() {
CodeGenOpts.SanitizeCfiCanonicalJumpTables);
}
+ if (LangOpts.Sanitize.has(SanitizerKind::KCFI)) {
+ getModule().addModuleFlag(llvm::Module::Override, "kcfi", 1);
+ // KCFI assumes patchable-function-prefix is the same for all indirectly
+ // called functions. Store the expected offset for code generation.
+ if (CodeGenOpts.PatchableFunctionEntryOffset)
+ getModule().addModuleFlag(llvm::Module::Override, "kcfi-offset",
+ CodeGenOpts.PatchableFunctionEntryOffset);
+ }
+
if (CodeGenOpts.CFProtectionReturn &&
Target.checkCFProtectionReturnSupported(getDiags())) {
// Indicate that we want to instrument return control flow protection.
@@ -769,12 +782,12 @@ void CodeGenModule::Release() {
1);
}
- if (CodeGenOpts.IBTSeal)
- getModule().addModuleFlag(llvm::Module::Min, "ibt-seal", 1);
-
if (CodeGenOpts.FunctionReturnThunks)
getModule().addModuleFlag(llvm::Module::Override, "function_return_thunk_extern", 1);
+ if (CodeGenOpts.IndirectBranchCSPrefix)
+ getModule().addModuleFlag(llvm::Module::Override, "indirect_branch_cs_prefix", 1);
+
// Add module metadata for return address signing (ignoring
// non-leaf/all) and stack tagging. These are actually turned on by function
// attributes, but we use module metadata to emit build attributes. This is
@@ -965,14 +978,9 @@ void CodeGenModule::EmitOpenCLMetadata() {
void CodeGenModule::EmitBackendOptionsMetadata(
const CodeGenOptions CodeGenOpts) {
- switch (getTriple().getArch()) {
- default:
- break;
- case llvm::Triple::riscv32:
- case llvm::Triple::riscv64:
+ if (getTriple().isRISCV()) {
getModule().addModuleFlag(llvm::Module::Error, "SmallDataLimit",
CodeGenOpts.SmallDataLimit);
- break;
}
}
@@ -1101,8 +1109,6 @@ llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) {
void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
const NamedDecl *D) const {
- if (GV->hasDLLImportStorageClass())
- return;
// Internal definitions always have default visibility.
if (GV->hasLocalLinkage()) {
GV->setVisibility(llvm::GlobalValue::DefaultVisibility);
@@ -1113,6 +1119,21 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
// Set visibility for definitions, and for declarations if requested globally
// or set explicitly.
LinkageInfo LV = D->getLinkageAndVisibility();
+ if (GV->hasDLLExportStorageClass() || GV->hasDLLImportStorageClass()) {
+ // Reject incompatible dlllstorage and visibility annotations.
+ if (!LV.isVisibilityExplicit())
+ return;
+ if (GV->hasDLLExportStorageClass()) {
+ if (LV.getVisibility() == HiddenVisibility)
+ getDiags().Report(D->getLocation(),
+ diag::err_hidden_visibility_dllexport);
+ } else if (LV.getVisibility() != DefaultVisibility) {
+ getDiags().Report(D->getLocation(),
+ diag::err_non_default_visibility_dllimport);
+ }
+ return;
+ }
+
if (LV.isVisibilityExplicit() || getLangOpts().SetVisibilityForExternDecls ||
!GV->isDeclarationForLinker())
GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
@@ -1320,6 +1341,20 @@ static void AppendCPUSpecificCPUDispatchMangling(const CodeGenModule &CGM,
Out << ".resolver";
}
+static void AppendTargetVersionMangling(const CodeGenModule &CGM,
+ const TargetVersionAttr *Attr,
+ raw_ostream &Out) {
+ if (Attr->isDefaultVersion())
+ return;
+ Out << "._";
+ llvm::SmallVector<StringRef, 8> Feats;
+ Attr->getFeatures(Feats);
+ for (const auto &Feat : Feats) {
+ Out << 'M';
+ Out << Feat;
+ }
+}
+
static void AppendTargetMangling(const CodeGenModule &CGM,
const TargetAttr *Attr, raw_ostream &Out) {
if (Attr->isDefaultVersion())
@@ -1327,21 +1362,21 @@ static void AppendTargetMangling(const CodeGenModule &CGM,
Out << '.';
const TargetInfo &Target = CGM.getTarget();
- ParsedTargetAttr Info =
- Attr->parse([&Target](StringRef LHS, StringRef RHS) {
- // Multiversioning doesn't allow "no-${feature}", so we can
- // only have "+" prefixes here.
- assert(LHS.startswith("+") && RHS.startswith("+") &&
- "Features should always have a prefix.");
- return Target.multiVersionSortPriority(LHS.substr(1)) >
- Target.multiVersionSortPriority(RHS.substr(1));
- });
+ ParsedTargetAttr Info = Target.parseTargetAttr(Attr->getFeaturesStr());
+ llvm::sort(Info.Features, [&Target](StringRef LHS, StringRef RHS) {
+ // Multiversioning doesn't allow "no-${feature}", so we can
+ // only have "+" prefixes here.
+ assert(LHS.startswith("+") && RHS.startswith("+") &&
+ "Features should always have a prefix.");
+ return Target.multiVersionSortPriority(LHS.substr(1)) >
+ Target.multiVersionSortPriority(RHS.substr(1));
+ });
bool IsFirst = true;
- if (!Info.Architecture.empty()) {
+ if (!Info.CPU.empty()) {
IsFirst = false;
- Out << "arch_" << Info.Architecture;
+ Out << "arch_" << Info.CPU;
}
for (StringRef Feat : Info.Features) {
@@ -1365,14 +1400,27 @@ static void AppendTargetClonesMangling(const CodeGenModule &CGM,
const TargetClonesAttr *Attr,
unsigned VersionIndex,
raw_ostream &Out) {
- Out << '.';
- StringRef FeatureStr = Attr->getFeatureStr(VersionIndex);
- if (FeatureStr.startswith("arch="))
- Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1);
- else
- Out << FeatureStr;
+ if (CGM.getTarget().getTriple().isAArch64()) {
+ StringRef FeatureStr = Attr->getFeatureStr(VersionIndex);
+ if (FeatureStr == "default")
+ return;
+ Out << "._";
+ SmallVector<StringRef, 8> Features;
+ FeatureStr.split(Features, "+");
+ for (auto &Feat : Features) {
+ Out << 'M';
+ Out << Feat;
+ }
+ } else {
+ Out << '.';
+ StringRef FeatureStr = Attr->getFeatureStr(VersionIndex);
+ if (FeatureStr.startswith("arch="))
+ Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1);
+ else
+ Out << FeatureStr;
- Out << '.' << Attr->getMangledIndex(VersionIndex);
+ Out << '.' << Attr->getMangledIndex(VersionIndex);
+ }
}
static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD,
@@ -1428,6 +1476,9 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD,
case MultiVersionKind::Target:
AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out);
break;
+ case MultiVersionKind::TargetVersion:
+ AppendTargetVersionMangling(CGM, FD->getAttr<TargetVersionAttr>(), Out);
+ break;
case MultiVersionKind::TargetClones:
AppendTargetClonesMangling(CGM, FD->getAttr<TargetClonesAttr>(),
GD.getMultiVersionIndex(), Out);
@@ -1581,9 +1632,10 @@ llvm::GlobalValue *CodeGenModule::GetGlobalValue(StringRef Name) {
/// AddGlobalCtor - Add a function to the list that will be called before
/// main() runs.
void CodeGenModule::AddGlobalCtor(llvm::Function *Ctor, int Priority,
+ unsigned LexOrder,
llvm::Constant *AssociatedData) {
// FIXME: Type coercion of void()* types.
- GlobalCtors.push_back(Structor(Priority, Ctor, AssociatedData));
+ GlobalCtors.push_back(Structor(Priority, LexOrder, Ctor, AssociatedData));
}
/// AddGlobalDtor - Add a function to the list that will be called
@@ -1597,7 +1649,7 @@ void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority,
}
// FIXME: Type coercion of void()* types.
- GlobalDtors.push_back(Structor(Priority, Dtor, nullptr));
+ GlobalDtors.push_back(Structor(Priority, ~0U, Dtor, nullptr));
}
void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
@@ -1633,7 +1685,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(llvm::None);
+ list->setAlignment(std::nullopt);
Fns.clear();
}
@@ -1666,6 +1718,20 @@ llvm::ConstantInt *CodeGenModule::CreateCrossDsoCfiTypeId(llvm::Metadata *MD) {
return llvm::ConstantInt::get(Int64Ty, llvm::MD5Hash(MDS->getString()));
}
+llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) {
+ if (auto *FnType = T->getAs<FunctionProtoType>())
+ T = getContext().getFunctionType(
+ FnType->getReturnType(), FnType->getParamTypes(),
+ FnType->getExtProtoInfo().withExceptionSpec(EST_None));
+
+ std::string OutName;
+ llvm::raw_string_ostream Out(OutName);
+ getCXXABI().getMangleContext().mangleTypeName(T, Out);
+
+ return llvm::ConstantInt::get(Int32Ty,
+ static_cast<uint32_t>(llvm::xxHash64(OutName)));
+}
+
void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD,
const CGFunctionInfo &Info,
llvm::Function *F, bool IsThunk) {
@@ -1765,7 +1831,7 @@ void CodeGenModule::GenKernelArgMetadata(llvm::Function *Fn,
// Get image and pipe access qualifier:
if (ty->isImageType() || ty->isPipeType()) {
const Decl *PDecl = parm;
- if (auto *TD = dyn_cast<TypedefType>(ty))
+ if (const auto *TD = ty->getAs<TypedefType>())
PDecl = TD->getDecl();
const OpenCLAccessAttr *A = PDecl->getAttr<OpenCLAccessAttr>();
if (A && A->isWriteOnly())
@@ -1935,7 +2001,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
llvm::Function *F) {
llvm::AttrBuilder B(F->getContext());
- if (CodeGenOpts.UnwindTables)
+ if ((!D || !D->hasAttr<NoUwtableAttr>()) && CodeGenOpts.UnwindTables)
B.addUWTableAttr(llvm::UWTableKind(CodeGenOpts.UnwindTables));
if (CodeGenOpts.StackClashProtector)
@@ -1944,14 +2010,17 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (!hasUnwindExceptions(LangOpts))
B.addAttribute(llvm::Attribute::NoUnwind);
- if (!D || !D->hasAttr<NoStackProtectorAttr>()) {
- if (LangOpts.getStackProtector() == LangOptions::SSPOn)
- B.addAttribute(llvm::Attribute::StackProtect);
- else if (LangOpts.getStackProtector() == LangOptions::SSPStrong)
- B.addAttribute(llvm::Attribute::StackProtectStrong);
- else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
- B.addAttribute(llvm::Attribute::StackProtectReq);
- }
+ if (D && D->hasAttr<NoStackProtectorAttr>())
+ ; // Do nothing.
+ else if (D && D->hasAttr<StrictGuardStackCheckAttr>() &&
+ LangOpts.getStackProtector() == LangOptions::SSPOn)
+ B.addAttribute(llvm::Attribute::StackProtectStrong);
+ else if (LangOpts.getStackProtector() == LangOptions::SSPOn)
+ B.addAttribute(llvm::Attribute::StackProtect);
+ else if (LangOpts.getStackProtector() == LangOptions::SSPStrong)
+ B.addAttribute(llvm::Attribute::StackProtectStrong);
+ else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
+ B.addAttribute(llvm::Attribute::StackProtectReq);
if (!D) {
// If we don't have a declaration to control inlining, the function isn't
@@ -2131,10 +2200,12 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
const auto *FD = dyn_cast_or_null<FunctionDecl>(GD.getDecl());
FD = FD ? FD->getMostRecentDecl() : FD;
const auto *TD = FD ? FD->getAttr<TargetAttr>() : nullptr;
+ const auto *TV = FD ? FD->getAttr<TargetVersionAttr>() : nullptr;
+ assert((!TD || !TV) && "both target_version and target specified");
const auto *SD = FD ? FD->getAttr<CPUSpecificAttr>() : nullptr;
const auto *TC = FD ? FD->getAttr<TargetClonesAttr>() : nullptr;
bool AddedAttr = false;
- if (TD || SD || TC) {
+ if (TD || TV || SD || TC) {
llvm::StringMap<bool> FeatureMap;
getContext().getFunctionFeatureMap(FeatureMap, GD);
@@ -2147,10 +2218,11 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
// get and parse the target attribute so we can get the cpu for
// the function.
if (TD) {
- ParsedTargetAttr ParsedAttr = TD->parse();
- if (!ParsedAttr.Architecture.empty() &&
- getTarget().isValidCPUName(ParsedAttr.Architecture)) {
- TargetCPU = ParsedAttr.Architecture;
+ ParsedTargetAttr ParsedAttr =
+ Target.parseTargetAttr(TD->getFeaturesStr());
+ if (!ParsedAttr.CPU.empty() &&
+ getTarget().isValidCPUName(ParsedAttr.CPU)) {
+ TargetCPU = ParsedAttr.CPU;
TuneCPU = ""; // Clear the tune CPU.
}
if (!ParsedAttr.Tune.empty() &&
@@ -2280,6 +2352,57 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
F->addTypeMetadata(0, llvm::ConstantAsMetadata::get(CrossDsoTypeId));
}
+void CodeGenModule::setKCFIType(const FunctionDecl *FD, llvm::Function *F) {
+ if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
+ return;
+
+ llvm::LLVMContext &Ctx = F->getContext();
+ llvm::MDBuilder MDB(Ctx);
+ F->setMetadata(llvm::LLVMContext::MD_kcfi_type,
+ llvm::MDNode::get(
+ Ctx, MDB.createConstant(CreateKCFITypeId(FD->getType()))));
+}
+
+static bool allowKCFIIdentifier(StringRef Name) {
+ // KCFI type identifier constants are only necessary for external assembly
+ // functions, which means it's safe to skip unusual names. Subset of
+ // MCAsmInfo::isAcceptableChar() and MCAsmInfoXCOFF::isAcceptableChar().
+ return llvm::all_of(Name, [](const char &C) {
+ return llvm::isAlnum(C) || C == '_' || C == '.';
+ });
+}
+
+void CodeGenModule::finalizeKCFITypes() {
+ llvm::Module &M = getModule();
+ for (auto &F : M.functions()) {
+ // Remove KCFI type metadata from non-address-taken local functions.
+ bool AddressTaken = F.hasAddressTaken();
+ if (!AddressTaken && F.hasLocalLinkage())
+ F.eraseMetadata(llvm::LLVMContext::MD_kcfi_type);
+
+ // Generate a constant with the expected KCFI type identifier for all
+ // address-taken function declarations to support annotating indirectly
+ // called assembly functions.
+ if (!AddressTaken || !F.isDeclaration())
+ continue;
+
+ const llvm::ConstantInt *Type;
+ if (const llvm::MDNode *MD = F.getMetadata(llvm::LLVMContext::MD_kcfi_type))
+ Type = llvm::mdconst::extract<llvm::ConstantInt>(MD->getOperand(0));
+ else
+ continue;
+
+ StringRef Name = F.getName();
+ if (!allowKCFIIdentifier(Name))
+ continue;
+
+ std::string Asm = (".weak __kcfi_typeid_" + Name + "\n.set __kcfi_typeid_" +
+ Name + ", " + Twine(Type->getZExtValue()) + "\n")
+ .str();
+ M.appendModuleInlineAsm(Asm);
+ }
+}
+
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
bool IsIncompleteFunction,
bool IsThunk) {
@@ -2362,9 +2485,15 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
!CodeGenOpts.SanitizeCfiCanonicalJumpTables)
CreateFunctionTypeMetadataForIcall(FD, F);
+ if (LangOpts.Sanitize.has(SanitizerKind::KCFI))
+ setKCFIType(FD, F);
+
if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
getOpenMPRuntime().emitDeclareSimdFunction(FD, F);
+ if (CodeGenOpts.InlineMaxStackSize != UINT_MAX)
+ F->addFnAttr("inline-max-stacksize", llvm::utostr(CodeGenOpts.InlineMaxStackSize));
+
if (const auto *CB = FD->getAttr<CallbackAttr>()) {
// Annotate the callback behavior as metadata:
// - The callback callee (as argument number).
@@ -2521,21 +2650,23 @@ void CodeGenModule::EmitModuleInitializers(clang::Module *Primary) {
// source, first Global Module Fragments, if present.
if (auto GMF = Primary->getGlobalModuleFragment()) {
for (Decl *D : getContext().getModuleInitializers(GMF)) {
- assert(D->getKind() == Decl::Var && "GMF initializer decl is not a var?");
+ if (isa<ImportDecl>(D))
+ continue;
+ assert(isa<VarDecl>(D) && "GMF initializer decl is not a var?");
EmitTopLevelDecl(D);
}
}
// Second any associated with the module, itself.
for (Decl *D : getContext().getModuleInitializers(Primary)) {
// Skip import decls, the inits for those are called explicitly.
- if (D->getKind() == Decl::Import)
+ if (isa<ImportDecl>(D))
continue;
EmitTopLevelDecl(D);
}
// Third any associated with the Privat eMOdule Fragment, if present.
if (auto PMF = Primary->getPrivateModuleFragment()) {
for (Decl *D : getContext().getModuleInitializers(PMF)) {
- assert(D->getKind() == Decl::Var && "PMF initializer decl is not a var?");
+ assert(isa<VarDecl>(D) && "PMF initializer decl is not a var?");
EmitTopLevelDecl(D);
}
}
@@ -2719,9 +2850,10 @@ llvm::Constant *CodeGenModule::EmitAnnotationString(StringRef Str) {
// Not found yet, create a new global.
llvm::Constant *s = llvm::ConstantDataArray::getString(getLLVMContext(), Str);
- auto *gv =
- new llvm::GlobalVariable(getModule(), s->getType(), true,
- llvm::GlobalValue::PrivateLinkage, s, ".str");
+ auto *gv = new llvm::GlobalVariable(
+ getModule(), s->getType(), true, llvm::GlobalValue::PrivateLinkage, s,
+ ".str", nullptr, llvm::GlobalValue::NotThreadLocal,
+ ConstGlobalsPtrTy->getAddressSpace());
gv->setSection(AnnotationSection);
gv->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
AStr = gv;
@@ -2747,7 +2879,7 @@ llvm::Constant *CodeGenModule::EmitAnnotationLineNo(SourceLocation L) {
llvm::Constant *CodeGenModule::EmitAnnotationArgs(const AnnotateAttr *Attr) {
ArrayRef<Expr *> Exprs = {Attr->args_begin(), Attr->args_size()};
if (Exprs.empty())
- return llvm::ConstantPointerNull::get(GlobalsInt8PtrTy);
+ return llvm::ConstantPointerNull::get(ConstGlobalsPtrTy);
llvm::FoldingSetNodeID ID;
for (Expr *E : Exprs) {
@@ -2797,8 +2929,8 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV,
// Create the ConstantStruct for the global annotation.
llvm::Constant *Fields[] = {
llvm::ConstantExpr::getBitCast(GVInGlobalsAS, GlobalsInt8PtrTy),
- llvm::ConstantExpr::getBitCast(AnnoGV, GlobalsInt8PtrTy),
- llvm::ConstantExpr::getBitCast(UnitGV, GlobalsInt8PtrTy),
+ llvm::ConstantExpr::getBitCast(AnnoGV, ConstGlobalsPtrTy),
+ llvm::ConstantExpr::getBitCast(UnitGV, ConstGlobalsPtrTy),
LineNoCst,
Args,
};
@@ -2890,46 +3022,44 @@ bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
return true;
}
-bool CodeGenModule::isFunctionBlockedByProfileList(llvm::Function *Fn,
- SourceLocation Loc) const {
+ProfileList::ExclusionType
+CodeGenModule::isFunctionBlockedByProfileList(llvm::Function *Fn,
+ SourceLocation Loc) const {
const auto &ProfileList = getContext().getProfileList();
// If the profile list is empty, then instrument everything.
if (ProfileList.isEmpty())
- return false;
+ return ProfileList::Allow;
CodeGenOptions::ProfileInstrKind Kind = getCodeGenOpts().getProfileInstr();
// First, check the function name.
- Optional<bool> V = ProfileList.isFunctionExcluded(Fn->getName(), Kind);
- if (V)
+ if (auto V = ProfileList.isFunctionExcluded(Fn->getName(), Kind))
return *V;
// Next, check the source location.
- if (Loc.isValid()) {
- Optional<bool> V = ProfileList.isLocationExcluded(Loc, Kind);
- if (V)
+ if (Loc.isValid())
+ if (auto V = ProfileList.isLocationExcluded(Loc, Kind))
return *V;
- }
// If location is unknown, this may be a compiler-generated function. Assume
// it's located in the main file.
auto &SM = Context.getSourceManager();
- if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
- Optional<bool> V = ProfileList.isFileExcluded(MainFile->getName(), Kind);
- if (V)
+ if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID()))
+ if (auto V = ProfileList.isFileExcluded(MainFile->getName(), Kind))
return *V;
- }
- return ProfileList.getDefault();
+ return ProfileList.getDefault(Kind);
}
-bool CodeGenModule::isFunctionBlockedFromProfileInstr(
- llvm::Function *Fn, SourceLocation Loc) const {
- if (isFunctionBlockedByProfileList(Fn, Loc))
- return true;
+ProfileList::ExclusionType
+CodeGenModule::isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
+ SourceLocation Loc) const {
+ auto V = isFunctionBlockedByProfileList(Fn, Loc);
+ if (V != ProfileList::Allow)
+ return V;
auto NumGroups = getCodeGenOpts().ProfileTotalFunctionGroups;
if (NumGroups > 1) {
auto Group = llvm::crc32(arrayRefFromStringRef(Fn->getName())) % NumGroups;
if (Group != getCodeGenOpts().ProfileSelectedFunctionGroup)
- return true;
+ return ProfileList::Skip;
}
- return false;
+ return ProfileList::Allow;
}
bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
@@ -2955,7 +3085,7 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
// we have if the level of the declare target attribute is -1. Note that we
// check somewhere else if we should emit this at all.
if (LangOpts.OpenMP >= 50 && !LangOpts.OpenMPSimd) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(Global);
if (!ActiveAttr || (*ActiveAttr)->getLevel() != (unsigned)-1)
return false;
@@ -3113,7 +3243,7 @@ ConstantAddress CodeGenModule::GetWeakRefReference(const ValueDecl *VD) {
// See if there is already something with the target's name in the module.
llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee());
if (Entry) {
- unsigned AS = getContext().getTargetAddressSpace(VD->getType());
+ unsigned AS = getTypes().getTargetAddressSpace(VD->getType());
auto Ptr = llvm::ConstantExpr::getBitCast(Entry, DeclTy->getPointerTo(AS));
return ConstantAddress(Ptr, DeclTy, Alignment);
}
@@ -3219,16 +3349,18 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
!Context.isMSStaticDataMemberInlineDefinition(VD)) {
if (LangOpts.OpenMP) {
// Emit declaration of the must-be-emitted declare target variable.
- if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ if (std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) {
bool UnifiedMemoryEnabled =
getOpenMPRuntime().hasRequiresUnifiedSharedMemory();
- if (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ if ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
!UnifiedMemoryEnabled) {
(void)GetAddrOfGlobalVar(VD);
} else {
assert(((*Res == OMPDeclareTargetDeclAttr::MT_Link) ||
- (*Res == OMPDeclareTargetDeclAttr::MT_To &&
+ ((*Res == OMPDeclareTargetDeclAttr::MT_To ||
+ *Res == OMPDeclareTargetDeclAttr::MT_Enter) &&
UnifiedMemoryEnabled)) &&
"Link clause or to clause with unified memory expected.");
(void)getOpenMPRuntime().getAddrOfDeclareTargetVar(VD);
@@ -3271,6 +3403,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// The value must be emitted, but cannot be emitted eagerly.
assert(!MayBeEmittedEagerly(Global));
addDeferredDeclToEmit(GD);
+ EmittedDeferredDecls[MangledName] = GD;
} else {
// Otherwise, remember that we saw a deferred decl with this name. The
// first use of the mangled name will cause it to move into
@@ -3526,12 +3659,18 @@ static unsigned
TargetMVPriority(const TargetInfo &TI,
const CodeGenFunction::MultiVersionResolverOption &RO) {
unsigned Priority = 0;
- for (StringRef Feat : RO.Conditions.Features)
+ unsigned NumFeatures = 0;
+ for (StringRef Feat : RO.Conditions.Features) {
Priority = std::max(Priority, TI.multiVersionSortPriority(Feat));
+ NumFeatures++;
+ }
if (!RO.Conditions.Architecture.empty())
Priority = std::max(
Priority, TI.multiVersionSortPriority(RO.Conditions.Architecture));
+
+ Priority += TI.multiVersionFeatureCost() * NumFeatures;
+
return Priority;
}
@@ -3576,13 +3715,19 @@ void CodeGenModule::emitMultiVersionFunctions() {
}
assert(Func && "This should have just been created");
}
-
- const auto *TA = CurFD->getAttr<TargetAttr>();
- llvm::SmallVector<StringRef, 8> Feats;
- TA->getAddedFeatures(Feats);
-
- Options.emplace_back(cast<llvm::Function>(Func),
- TA->getArchitecture(), Feats);
+ if (CurFD->getMultiVersionKind() == MultiVersionKind::Target) {
+ const auto *TA = CurFD->getAttr<TargetAttr>();
+ llvm::SmallVector<StringRef, 8> Feats;
+ TA->getAddedFeatures(Feats);
+ Options.emplace_back(cast<llvm::Function>(Func),
+ TA->getArchitecture(), Feats);
+ } else {
+ const auto *TVA = CurFD->getAttr<TargetVersionAttr>();
+ llvm::SmallVector<StringRef, 8> Feats;
+ TVA->getFeatures(Feats);
+ Options.emplace_back(cast<llvm::Function>(Func),
+ /*Architecture*/ "", Feats);
+ }
});
} else if (FD->isTargetClonesMultiVersion()) {
const auto *TC = FD->getAttr<TargetClonesAttr>();
@@ -3612,10 +3757,19 @@ void CodeGenModule::emitMultiVersionFunctions() {
StringRef Architecture;
llvm::SmallVector<StringRef, 1> Feature;
- if (Version.startswith("arch="))
- Architecture = Version.drop_front(sizeof("arch=") - 1);
- else if (Version != "default")
- Feature.push_back(Version);
+ if (getTarget().getTriple().isAArch64()) {
+ if (Version != "default") {
+ llvm::SmallVector<StringRef, 8> VerFeats;
+ Version.split(VerFeats, "+");
+ for (auto &CurFeat : VerFeats)
+ Feature.push_back(CurFeat.trim());
+ }
+ } else {
+ if (Version.startswith("arch="))
+ Architecture = Version.drop_front(sizeof("arch=") - 1);
+ else if (Version != "default")
+ Feature.push_back(Version);
+ }
Options.emplace_back(cast<llvm::Function>(Func), Architecture, Feature);
}
@@ -3675,7 +3829,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
if (getTarget().supportsIFunc()) {
ResolverType = llvm::FunctionType::get(
llvm::PointerType::get(DeclTy,
- Context.getTargetAddressSpace(FD->getType())),
+ getTypes().getTargetAddressSpace(FD->getType())),
false);
}
else {
@@ -3813,8 +3967,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
// cpu_dispatch will be emitted in this translation unit.
if (getTarget().supportsIFunc() && !FD->isCPUSpecificMultiVersion()) {
llvm::Type *ResolverType = llvm::FunctionType::get(
- llvm::PointerType::get(
- DeclTy, getContext().getTargetAddressSpace(FD->getType())),
+ llvm::PointerType::get(DeclTy,
+ getTypes().getTargetAddressSpace(FD->getType())),
false);
llvm::Constant *Resolver = GetOrCreateLLVMFunction(
MangledName + ".resolver", ResolverType, GlobalDecl{},
@@ -3917,7 +4071,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
// (If function is requested for a definition, we always need to create a new
// function, not just return a bitcast.)
if (!IsForDefinition)
- return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo());
+ return llvm::ConstantExpr::getBitCast(
+ Entry, Ty->getPointerTo(Entry->getAddressSpace()));
}
// This function doesn't have a complete type (for example, the return
@@ -3958,7 +4113,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
}
llvm::Constant *BC = llvm::ConstantExpr::getBitCast(
- F, Entry->getValueType()->getPointerTo());
+ F, Entry->getValueType()->getPointerTo(Entry->getAddressSpace()));
addGlobalValReplacement(Entry, BC);
}
@@ -3974,7 +4129,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
// All MSVC dtors other than the base dtor are linkonce_odr and delegate to
// each other bottoming out with the base dtor. Therefore we emit non-base
// dtors on usage, even if there is no dtor definition in the TU.
- if (D && isa<CXXDestructorDecl>(D) &&
+ if (isa_and_nonnull<CXXDestructorDecl>(D) &&
getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
GD.getDtorType()))
addDeferredDeclToEmit(GD);
@@ -3988,6 +4143,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
// DeferredDeclsToEmit list, and remove it from DeferredDecls (since we
// don't need it anymore).
addDeferredDeclToEmit(DDI->second);
+ EmittedDeferredDecls[DDI->first] = DDI->second;
DeferredDecls.erase(DDI);
// Otherwise, there are cases we have to worry about where we're
@@ -4021,8 +4177,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
return F;
}
- llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
- return llvm::ConstantExpr::getBitCast(F, PTy);
+ return llvm::ConstantExpr::getBitCast(F,
+ Ty->getPointerTo(F->getAddressSpace()));
}
/// GetAddrOfFunction - Return the address of the given function. If Ty is
@@ -4071,8 +4227,9 @@ llvm::Constant *CodeGenModule::GetFunctionStart(const ValueDecl *Decl) {
llvm::GlobalValue *F =
cast<llvm::GlobalValue>(GetAddrOfFunction(Decl)->stripPointerCasts());
- return llvm::ConstantExpr::getBitCast(llvm::NoCFIValue::get(F),
- llvm::Type::getInt8PtrTy(VMContext));
+ return llvm::ConstantExpr::getBitCast(
+ llvm::NoCFIValue::get(F),
+ llvm::Type::getInt8PtrTy(VMContext, F->getAddressSpace()));
}
static const FunctionDecl *
@@ -4269,6 +4426,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
// Move the potentially referenced deferred decl to the DeferredDeclsToEmit
// list, and remove it from DeferredDecls (since we don't need it anymore).
addDeferredDeclToEmit(DDI->second);
+ EmittedDeferredDecls[DDI->first] = DDI->second;
DeferredDecls.erase(DDI);
}
@@ -4408,7 +4566,7 @@ CodeGenModule::GetAddrOfGlobal(GlobalDecl GD, ForDefinition_t IsForDefinition) {
llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable(
StringRef Name, llvm::Type *Ty, llvm::GlobalValue::LinkageTypes Linkage,
- unsigned Alignment) {
+ llvm::Align Alignment) {
llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name);
llvm::GlobalVariable *OldGV = nullptr;
@@ -4444,7 +4602,7 @@ llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable(
!GV->hasAvailableExternallyLinkage())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
- GV->setAlignment(llvm::MaybeAlign(Alignment));
+ GV->setAlignment(Alignment);
return GV;
}
@@ -4673,13 +4831,19 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
llvm::TrackingVH<llvm::Constant> Init;
bool NeedsGlobalCtor = false;
+ // Whether the definition of the variable is available externally.
+ // If yes, we shouldn't emit the GloablCtor and GlobalDtor for the variable
+ // since this is the job for its original source.
+ bool IsDefinitionAvailableExternally =
+ getContext().GetGVALinkageForVariable(D) == GVA_AvailableExternally;
bool NeedsGlobalDtor =
+ !IsDefinitionAvailableExternally &&
D->needsDestruction(getContext()) == QualType::DK_cxx_destructor;
const VarDecl *InitDecl;
const Expr *InitExpr = D->getAnyInitializer(InitDecl);
- Optional<ConstantEmitter> emitter;
+ std::optional<ConstantEmitter> emitter;
// CUDA E.2.4.1 "__shared__ variables cannot have an initialization
// as part of their declaration." Sema has already checked for
@@ -4727,7 +4891,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
if (InitDecl->hasFlexibleArrayInit(getContext()))
ErrorUnsupported(D, "flexible array initializer");
Init = EmitNullConstant(T);
- NeedsGlobalCtor = true;
+
+ if (!IsDefinitionAvailableExternally)
+ NeedsGlobalCtor = true;
} else {
ErrorUnsupported(D, "static initializer");
Init = llvm::UndefValue::get(getTypes().ConvertType(T));
@@ -4837,7 +5003,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
CharUnits AlignVal = getContext().getDeclAlign(D);
// Check for alignment specifed in an 'omp allocate' directive.
- if (llvm::Optional<CharUnits> AlignValFromAllocate =
+ if (std::optional<CharUnits> AlignValFromAllocate =
getOMPAllocateAlignment(D))
AlignVal = *AlignValFromAllocate;
GV->setAlignment(AlignVal.getAsAlign());
@@ -5331,7 +5497,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
// Emit global alias debug information.
if (isa<VarDecl>(D))
if (CGDebugInfo *DI = getModuleDebugInfo())
- DI->EmitGlobalAlias(cast<llvm::GlobalValue>(GA->getAliasee()), GD);
+ DI->EmitGlobalAlias(cast<llvm::GlobalValue>(GA->getAliasee()->stripPointerCasts()), GD);
}
void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) {
@@ -5468,7 +5634,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
switch (CFRuntime) {
default: break;
- case LangOptions::CoreFoundationABI::Swift: LLVM_FALLTHROUGH;
+ case LangOptions::CoreFoundationABI::Swift: [[fallthrough]];
case LangOptions::CoreFoundationABI::Swift5_0:
CFConstantStringClassName =
Triple.isOSDarwin() ? "$s15SwiftFoundation19_NSCFConstantStringCN"
@@ -5546,7 +5712,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
// String pointer.
llvm::Constant *C = nullptr;
if (isUTF16) {
- auto Arr = llvm::makeArrayRef(
+ auto Arr = llvm::ArrayRef(
reinterpret_cast<uint16_t *>(const_cast<char *>(Entry.first().data())),
Entry.first().size() / 2);
C = llvm::ConstantDataArray::get(VMContext, Arr);
@@ -5891,7 +6057,7 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
LangAS AddrSpace =
VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace();
- Optional<ConstantEmitter> emitter;
+ std::optional<ConstantEmitter> emitter;
llvm::Constant *InitialValue = nullptr;
bool Constant = false;
llvm::Type *Type;
@@ -5929,10 +6095,13 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(),
/*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
if (emitter) emitter->finalize(GV);
- setGVProperties(GV, VD);
- if (GV->getDLLStorageClass() == llvm::GlobalVariable::DLLExportStorageClass)
- // The reference temporary should never be dllexport.
- GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
+ // Don't assign dllimport or dllexport to local linkage globals.
+ if (!llvm::GlobalValue::isLocalLinkage(Linkage)) {
+ setGVProperties(GV, VD);
+ if (GV->getDLLStorageClass() == llvm::GlobalVariable::DLLExportStorageClass)
+ // The reference temporary should never be dllexport.
+ GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
+ }
GV->setAlignment(Align.getAsAlign());
if (supportsCOMDAT() && GV->isWeakForLinker())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
@@ -6058,6 +6227,39 @@ void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
EmitDeclContext(LSD);
}
+void CodeGenModule::EmitTopLevelStmt(const TopLevelStmtDecl *D) {
+ std::unique_ptr<CodeGenFunction> &CurCGF =
+ GlobalTopLevelStmtBlockInFlight.first;
+
+ // We emitted a top-level stmt but after it there is initialization.
+ // Stop squashing the top-level stmts into a single function.
+ if (CurCGF && CXXGlobalInits.back() != CurCGF->CurFn) {
+ CurCGF->FinishFunction(D->getEndLoc());
+ CurCGF = nullptr;
+ }
+
+ if (!CurCGF) {
+ // void __stmts__N(void)
+ // FIXME: Ask the ABI name mangler to pick a name.
+ std::string Name = "__stmts__" + llvm::utostr(CXXGlobalInits.size());
+ FunctionArgList Args;
+ QualType RetTy = getContext().VoidTy;
+ const CGFunctionInfo &FnInfo =
+ getTypes().arrangeBuiltinFunctionDeclaration(RetTy, Args);
+ llvm::FunctionType *FnTy = getTypes().GetFunctionType(FnInfo);
+ llvm::Function *Fn = llvm::Function::Create(
+ FnTy, llvm::GlobalValue::InternalLinkage, Name, &getModule());
+
+ CurCGF.reset(new CodeGenFunction(*this));
+ GlobalTopLevelStmtBlockInFlight.second = D;
+ CurCGF->StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
+ D->getBeginLoc(), D->getBeginLoc());
+ CXXGlobalInits.push_back(Fn);
+ }
+
+ CurCGF->EmitStmt(D->getStmt());
+}
+
void CodeGenModule::EmitDeclContext(const DeclContext *DC) {
for (auto *I : DC->decls()) {
// Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope
@@ -6125,7 +6327,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
TSK_ExplicitInstantiationDefinition &&
Spec->hasDefinition())
DI->completeTemplateDefinition(*Spec);
- } LLVM_FALLTHROUGH;
+ } [[fallthrough]];
case Decl::CXXRecord: {
CXXRecordDecl *CRD = cast<CXXRecordDecl>(D);
if (CGDebugInfo *DI = getModuleDebugInfo()) {
@@ -6267,6 +6469,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}
+ case Decl::TopLevelStmt:
+ EmitTopLevelStmt(cast<TopLevelStmtDecl>(D));
+ break;
+
case Decl::Import: {
auto *Import = cast<ImportDecl>(D);
@@ -6363,6 +6569,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
DI->EmitAndRetainType(getContext().getEnumType(cast<EnumDecl>(D)));
break;
+ case Decl::HLSLBuffer:
+ getHLSLRuntime().addBuffer(cast<HLSLBufferDecl>(D));
+ break;
+
default:
// Make sure we handled everything we should, every other kind is a
// non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 5fbcc5ad1f5f..b3354657b237 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -36,6 +36,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
+#include <optional>
namespace llvm {
class Module;
@@ -282,12 +283,15 @@ class CodeGenModule : public CodeGenTypeCache {
public:
struct Structor {
- Structor() : Priority(0), Initializer(nullptr), AssociatedData(nullptr) {}
- Structor(int Priority, llvm::Constant *Initializer,
+ Structor()
+ : Priority(0), LexOrder(~0u), Initializer(nullptr),
+ AssociatedData(nullptr) {}
+ Structor(int Priority, unsigned LexOrder, llvm::Constant *Initializer,
llvm::Constant *AssociatedData)
- : Priority(Priority), Initializer(Initializer),
+ : Priority(Priority), LexOrder(LexOrder), Initializer(Initializer),
AssociatedData(AssociatedData) {}
int Priority;
+ unsigned LexOrder;
llvm::Constant *Initializer;
llvm::Constant *AssociatedData;
};
@@ -588,6 +592,11 @@ private:
llvm::DenseMap<const llvm::Constant *, llvm::GlobalVariable *> RTTIProxyMap;
+ // Helps squashing blocks of TopLevelStmtDecl into a single llvm::Function
+ // when used with -fincremental-extensions.
+ std::pair<std::unique_ptr<CodeGenFunction>, const TopLevelStmtDecl *>
+ GlobalTopLevelStmtBlockInFlight;
+
public:
CodeGenModule(ASTContext &C, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &headersearchopts,
@@ -712,7 +721,8 @@ public:
llvm::MDNode *getNoObjCARCExceptionsMetadata() {
if (!NoObjCARCExceptionsMetadata)
- NoObjCARCExceptionsMetadata = llvm::MDNode::get(getLLVMContext(), None);
+ NoObjCARCExceptionsMetadata =
+ llvm::MDNode::get(getLLVMContext(), std::nullopt);
return NoObjCARCExceptionsMetadata;
}
@@ -751,6 +761,10 @@ public:
return VTables.getItaniumVTableContext();
}
+ const ItaniumVTableContext &getItaniumVTableContext() const {
+ return VTables.getItaniumVTableContext();
+ }
+
MicrosoftVTableContext &getMicrosoftVTableContext() {
return VTables.getMicrosoftVTableContext();
}
@@ -867,7 +881,7 @@ public:
llvm::GlobalVariable *
CreateOrReplaceCXXRuntimeVariable(StringRef Name, llvm::Type *Ty,
llvm::GlobalValue::LinkageTypes Linkage,
- unsigned Alignment);
+ llvm::Align Alignment);
llvm::Function *CreateGlobalInitOrCleanUpFunction(
llvm::FunctionType *ty, const Twine &name, const CGFunctionInfo &FI,
@@ -1076,7 +1090,8 @@ public:
llvm::Constant *getBuiltinLibFunction(const FunctionDecl *FD,
unsigned BuiltinID);
- llvm::Function *getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys = None);
+ llvm::Function *getIntrinsic(unsigned IID,
+ ArrayRef<llvm::Type *> Tys = std::nullopt);
/// Emit code for a single top level declaration.
void EmitTopLevelDecl(Decl *D);
@@ -1351,13 +1366,14 @@ public:
/// \returns true if \p Fn at \p Loc should be excluded from profile
/// instrumentation by the SCL passed by \p -fprofile-list.
- bool isFunctionBlockedByProfileList(llvm::Function *Fn,
- SourceLocation Loc) const;
+ ProfileList::ExclusionType
+ isFunctionBlockedByProfileList(llvm::Function *Fn, SourceLocation Loc) const;
/// \returns true if \p Fn at \p Loc should be excluded from profile
/// instrumentation.
- bool isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
- SourceLocation Loc) const;
+ ProfileList::ExclusionType
+ isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
+ SourceLocation Loc) const;
SanitizerMetadata *getSanitizerMetadata() {
return SanitizerMD.get();
@@ -1406,7 +1422,7 @@ public:
void EmitOMPAllocateDecl(const OMPAllocateDecl *D);
/// Return the alignment specified in an allocate directive, if present.
- llvm::Optional<CharUnits> getOMPAllocateAlignment(const VarDecl *VD);
+ std::optional<CharUnits> getOMPAllocateAlignment(const VarDecl *VD);
/// Returns whether the given record has hidden LTO visibility and therefore
/// may participate in (single-module) CFI and whole-program vtable
@@ -1433,9 +1449,14 @@ public:
llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout);
+ llvm::Type *getVTableComponentType() const;
+
/// Generate a cross-DSO type identifier for MD.
llvm::ConstantInt *CreateCrossDsoCfiTypeId(llvm::Metadata *MD);
+ /// Generate a KCFI type identifier for T.
+ llvm::ConstantInt *CreateKCFITypeId(QualType T);
+
/// Create a metadata identifier for the given type. This may either be an
/// MDString (for external identifiers) or a distinct unnamed MDNode (for
/// internal identifiers).
@@ -1454,9 +1475,16 @@ public:
void CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
llvm::Function *F);
+ /// Set type metadata to the given function.
+ void setKCFIType(const FunctionDecl *FD, llvm::Function *F);
+
+ /// Emit KCFI type identifier constants and remove unused identifiers.
+ void finalizeKCFITypes();
+
/// Whether this function's return type has no side effects, and thus may
/// be trivially discarded if it is unused.
- bool MayDropFunctionReturn(const ASTContext &Context, QualType ReturnType);
+ bool MayDropFunctionReturn(const ASTContext &Context,
+ QualType ReturnType) const;
/// Returns whether this module needs the "all-vtables" type identifier.
bool NeedAllVtablesTypeId() const;
@@ -1577,6 +1605,7 @@ private:
void EmitDeclContext(const DeclContext *DC);
void EmitLinkageSpec(const LinkageSpecDecl *D);
+ void EmitTopLevelStmt(const TopLevelStmtDecl *D);
/// Emit the function that initializes C++ thread_local variables.
void EmitCXXThreadLocalInitFunc();
@@ -1601,6 +1630,7 @@ private:
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority = 65535,
+ unsigned LexOrder = ~0U,
llvm::Constant *AssociatedData = nullptr);
void AddGlobalDtor(llvm::Function *Dtor, int Priority = 65535,
bool IsDtorAttrFunc = false);
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 587bcef78ee5..15a3d74666ca 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -21,6 +21,7 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MD5.h"
+#include <optional>
static llvm::cl::opt<bool>
EnableValueProfiling("enable-value-profiling",
@@ -755,7 +756,7 @@ void PGOHash::combine(HashType Type) {
if (Count && Count % NumTypesPerWord == 0) {
using namespace llvm::support;
uint64_t Swapped = endian::byte_swap<uint64_t, little>(Working);
- MD5.update(llvm::makeArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));
+ MD5.update(llvm::ArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));
Working = 0;
}
@@ -781,7 +782,7 @@ uint64_t PGOHash::finalize() {
} else {
using namespace llvm::support;
uint64_t Swapped = endian::byte_swap<uint64_t, little>(Working);
- MD5.update(llvm::makeArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));
+ MD5.update(llvm::ArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));
}
}
@@ -822,6 +823,8 @@ void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) {
CGM.ClearUnusedCoverageMapping(D);
if (Fn->hasFnAttribute(llvm::Attribute::NoProfile))
return;
+ if (Fn->hasFnAttribute(llvm::Attribute::SkipProfile))
+ return;
setFuncName(Fn);
@@ -963,11 +966,11 @@ void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, const Stmt *S,
Builder.getInt32(Counter), StepV};
if (!StepV)
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment),
- makeArrayRef(Args, 4));
+ ArrayRef(Args, 4));
else
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_increment_step),
- makeArrayRef(Args));
+ ArrayRef(Args));
}
void CodeGenPGO::setValueProfilingFlag(llvm::Module &M) {
@@ -1114,7 +1117,7 @@ CodeGenFunction::createProfileWeightsForLoop(const Stmt *Cond,
uint64_t LoopCount) const {
if (!PGO.haveRegionCounts())
return nullptr;
- Optional<uint64_t> CondCount = PGO.getStmtCount(Cond);
+ std::optional<uint64_t> CondCount = PGO.getStmtCount(Cond);
if (!CondCount || *CondCount == 0)
return nullptr;
return createProfileWeights(LoopCount,
diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h
index f740692ac205..66c93cba4bb0 100644
--- a/clang/lib/CodeGen/CodeGenPGO.h
+++ b/clang/lib/CodeGen/CodeGenPGO.h
@@ -19,6 +19,7 @@
#include "llvm/ProfileData/InstrProfReader.h"
#include <array>
#include <memory>
+#include <optional>
namespace clang {
namespace CodeGen {
@@ -59,12 +60,12 @@ public:
/// Check if an execution count is known for a given statement. If so, return
/// true and put the value in Count; else return false.
- Optional<uint64_t> getStmtCount(const Stmt *S) const {
+ std::optional<uint64_t> getStmtCount(const Stmt *S) const {
if (!StmtCountMap)
- return None;
+ return std::nullopt;
auto I = StmtCountMap->find(S);
if (I == StmtCountMap->end())
- return None;
+ return std::nullopt;
return I->second;
}
diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp
index 0cb63fbbe9e5..395ed7b1d703 100644
--- a/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/clang/lib/CodeGen/CodeGenTBAA.cpp
@@ -338,7 +338,7 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) {
using TBAAStructField = llvm::MDBuilder::TBAAStructField;
SmallVector<TBAAStructField, 4> Fields;
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- // Handle C++ base classes. Non-virtual bases can treated a a kind of
+ // Handle C++ base classes. Non-virtual bases can treated a kind of
// field. Virtual bases are more complex and omitted, but avoid an
// incomplete view for NewStructPathTBAA.
if (CodeGenOpts.NewStructPathTBAA && CXXRD->getNumVBases() != 0)
diff --git a/clang/lib/CodeGen/CodeGenTypeCache.h b/clang/lib/CodeGen/CodeGenTypeCache.h
index 577f88367a3a..e848dc3b449c 100644
--- a/clang/lib/CodeGen/CodeGenTypeCache.h
+++ b/clang/lib/CodeGen/CodeGenTypeCache.h
@@ -75,6 +75,9 @@ struct CodeGenTypeCache {
llvm::PointerType *GlobalsInt8PtrTy;
};
+ /// void* in the address space for constant globals
+ llvm::PointerType *ConstGlobalsPtrTy;
+
/// The size and alignment of the builtin C type 'int'. This comes
/// up enough in various ABI lowering tasks to be worth pre-computing.
union {
diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp
index fcce424747f1..abbf71daf1d5 100644
--- a/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/clang/lib/CodeGen/CodeGenTypes.cpp
@@ -67,7 +67,7 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
if (RD->getDeclContext())
RD->printQualifiedName(OS, Policy);
else
- RD->printName(OS);
+ RD->printName(OS, Policy);
} else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) {
// FIXME: We should not have to check for a null decl context here.
// Right now we do it because the implicit Obj-C decls don't have one.
@@ -655,7 +655,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
const ReferenceType *RTy = cast<ReferenceType>(Ty);
QualType ETy = RTy->getPointeeType();
llvm::Type *PointeeType = ConvertTypeForMem(ETy);
- unsigned AS = Context.getTargetAddressSpace(ETy);
+ unsigned AS = getTargetAddressSpace(ETy);
ResultType = llvm::PointerType::get(PointeeType, AS);
break;
}
@@ -665,7 +665,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
llvm::Type *PointeeType = ConvertTypeForMem(ETy);
if (PointeeType->isVoidTy())
PointeeType = llvm::Type::getInt8Ty(getLLVMContext());
- unsigned AS = Context.getTargetAddressSpace(ETy);
+ unsigned AS = getTargetAddressSpace(ETy);
ResultType = llvm::PointerType::get(PointeeType, AS);
break;
}
@@ -772,10 +772,10 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// Block pointers lower to function type. For function type,
// getTargetAddressSpace() returns default address space for
// function pointer i.e. program address space. Therefore, for block
- // pointers, it is important to pass qualifiers when calling
- // getTargetAddressSpace(), to ensure that we get the address space
- // for data pointers and not function pointers.
- unsigned AS = Context.getTargetAddressSpace(FTy.getQualifiers());
+ // pointers, it is important to pass the pointee AST address space when
+ // calling getTargetAddressSpace(), to ensure that we get the LLVM IR
+ // address space for data pointers and not function pointers.
+ unsigned AS = Context.getTargetAddressSpace(FTy.getAddressSpace());
ResultType = llvm::PointerType::get(PointeeType, AS);
break;
}
@@ -807,8 +807,8 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
ResultType,
llvm::ArrayType::get(CGM.Int8Ty, (atomicSize - valueSize) / 8)
};
- ResultType = llvm::StructType::get(getLLVMContext(),
- llvm::makeArrayRef(elts));
+ ResultType =
+ llvm::StructType::get(getLLVMContext(), llvm::ArrayRef(elts));
}
break;
}
@@ -958,3 +958,13 @@ bool CodeGenTypes::isZeroInitializable(QualType T) {
bool CodeGenTypes::isZeroInitializable(const RecordDecl *RD) {
return getCGRecordLayout(RD).isZeroInitializable();
}
+
+unsigned CodeGenTypes::getTargetAddressSpace(QualType T) const {
+ // Return the address space for the type. If the type is a
+ // function type without an address space qualifier, the
+ // program address space is used. Otherwise, the target picks
+ // the best address space based on the type information
+ return T->isFunctionType() && !T.hasAddressSpace()
+ ? getDataLayout().getProgramAddressSpace()
+ : getContext().getTargetAddressSpace(T.getAddressSpace());
+}
diff --git a/clang/lib/CodeGen/CodeGenTypes.h b/clang/lib/CodeGen/CodeGenTypes.h
index cd20563cbf75..e76fda95513f 100644
--- a/clang/lib/CodeGen/CodeGenTypes.h
+++ b/clang/lib/CodeGen/CodeGenTypes.h
@@ -109,6 +109,7 @@ public:
const llvm::DataLayout &getDataLayout() const {
return TheModule.getDataLayout();
}
+ CodeGenModule &getCGM() const { return CGM; }
ASTContext &getContext() const { return Context; }
const ABIInfo &getABIInfo() const { return TheABIInfo; }
const TargetInfo &getTarget() const { return Target; }
@@ -305,7 +306,7 @@ public: // These are internal details of CGT that shouldn't be used externally.
bool isRecordBeingLaidOut(const Type *Ty) const {
return RecordsBeingLaidOut.count(Ty);
}
-
+ unsigned getTargetAddressSpace(QualType T) const;
};
} // end namespace CodeGen
diff --git a/clang/lib/CodeGen/ConstantEmitter.h b/clang/lib/CodeGen/ConstantEmitter.h
index 188b82e56f53..1a7a181ca7f0 100644
--- a/clang/lib/CodeGen/ConstantEmitter.h
+++ b/clang/lib/CodeGen/ConstantEmitter.h
@@ -67,6 +67,9 @@ public:
return Abstract;
}
+ bool isInConstantContext() const { return InConstantContext; }
+ void setInConstantContext(bool var) { InConstantContext = var; }
+
/// Try to emit the initiaizer of the given declaration as an abstract
/// constant. If this succeeds, the emission must be finalized.
llvm::Constant *tryEmitForInitializer(const VarDecl &D);
diff --git a/clang/lib/CodeGen/ConstantInitBuilder.cpp b/clang/lib/CodeGen/ConstantInitBuilder.cpp
index 06d3e44f01b1..3cf69f3b6415 100644
--- a/clang/lib/CodeGen/ConstantInitBuilder.cpp
+++ b/clang/lib/CodeGen/ConstantInitBuilder.cpp
@@ -209,8 +209,7 @@ ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {
// Advance the offset past that field.
auto &layout = Builder.CGM.getDataLayout();
if (!Packed)
- offset = offset.alignTo(CharUnits::fromQuantity(
- layout.getABITypeAlignment(type)));
+ offset = offset.alignTo(CharUnits::fromQuantity(layout.getABITypeAlign(type)));
offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
CachedOffsetEnd = Builder.Buffer.size();
@@ -249,8 +248,8 @@ CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
"cannot compute offset when a placeholder is present");
llvm::Type *elementType = element->getType();
if (!Packed)
- offset = offset.alignTo(CharUnits::fromQuantity(
- layout.getABITypeAlignment(elementType)));
+ offset = offset.alignTo(
+ CharUnits::fromQuantity(layout.getABITypeAlign(elementType)));
offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
} while (++cacheEnd != end);
}
@@ -268,7 +267,7 @@ llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
assert((Begin < buffer.size() ||
(Begin == buffer.size() && eltTy))
&& "didn't add any array elements without element type");
- auto elts = llvm::makeArrayRef(buffer).slice(Begin);
+ auto elts = llvm::ArrayRef(buffer).slice(Begin);
if (!eltTy) eltTy = elts[0]->getType();
auto type = llvm::ArrayType::get(eltTy, elts.size());
auto constant = llvm::ConstantArray::get(type, elts);
@@ -281,7 +280,7 @@ ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
markFinished();
auto &buffer = getBuffer();
- auto elts = llvm::makeArrayRef(buffer).slice(Begin);
+ auto elts = llvm::ArrayRef(buffer).slice(Begin);
if (ty == nullptr && elts.empty())
ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 0fe084b628da..101cd6a67b49 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -17,7 +17,6 @@
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
@@ -26,6 +25,7 @@
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include <optional>
// This selects the coverage mapping format defined when `InstrProfData.inc`
// is textually included.
@@ -97,27 +97,29 @@ class SourceMappingRegion {
Counter Count;
/// Secondary Counter used for Branch Regions for "False" branches.
- Optional<Counter> FalseCount;
+ std::optional<Counter> FalseCount;
/// The region's starting location.
- Optional<SourceLocation> LocStart;
+ std::optional<SourceLocation> LocStart;
/// The region's ending location.
- Optional<SourceLocation> LocEnd;
+ std::optional<SourceLocation> LocEnd;
/// Whether this region is a gap region. The count from a gap region is set
/// as the line execution count if there are no other regions on the line.
bool GapRegion;
public:
- SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart,
- Optional<SourceLocation> LocEnd, bool GapRegion = false)
+ SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
+ std::optional<SourceLocation> LocEnd,
+ bool GapRegion = false)
: Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
}
- SourceMappingRegion(Counter Count, Optional<Counter> FalseCount,
- Optional<SourceLocation> LocStart,
- Optional<SourceLocation> LocEnd, bool GapRegion = false)
+ SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
+ std::optional<SourceLocation> LocStart,
+ std::optional<SourceLocation> LocEnd,
+ bool GapRegion = false)
: Count(Count), FalseCount(FalseCount), LocStart(LocStart),
LocEnd(LocEnd), GapRegion(GapRegion) {}
@@ -325,24 +327,24 @@ public:
/// Get the coverage mapping file ID for \c Loc.
///
- /// If such file id doesn't exist, return None.
- Optional<unsigned> getCoverageFileID(SourceLocation Loc) {
+ /// If such file id doesn't exist, return std::nullopt.
+ std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
if (Mapping != FileIDMapping.end())
return Mapping->second.first;
- return None;
+ return std::nullopt;
}
/// This shrinks the skipped range if it spans a line that contains a
/// non-comment token. If shrinking the skipped range would make it empty,
- /// this returns None.
+ /// this returns std::nullopt.
/// Note this function can potentially be expensive because
/// getSpellingLineNumber uses getLineNumber, which is expensive.
- Optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
- SourceLocation LocStart,
- SourceLocation LocEnd,
- SourceLocation PrevTokLoc,
- SourceLocation NextTokLoc) {
+ std::optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
+ SourceLocation LocStart,
+ SourceLocation LocEnd,
+ SourceLocation PrevTokLoc,
+ SourceLocation NextTokLoc) {
SpellingRegion SR{SM, LocStart, LocEnd};
SR.ColumnStart = 1;
if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
@@ -355,7 +357,7 @@ public:
}
if (SR.isInSourceOrder())
return SR;
- return None;
+ return std::nullopt;
}
/// Gather all the regions that were skipped by the preprocessor
@@ -385,7 +387,7 @@ public:
auto CovFileID = getCoverageFileID(LocStart);
if (!CovFileID)
continue;
- Optional<SpellingRegion> SR;
+ std::optional<SpellingRegion> SR;
if (I.isComment())
SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
I.NextTokLoc);
@@ -527,7 +529,7 @@ struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
if (MappingRegions.empty())
return;
- CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);
+ CoverageMappingWriter Writer(FileIDMapping, std::nullopt, MappingRegions);
Writer.write(OS);
}
};
@@ -583,9 +585,10 @@ struct CounterCoverageMappingBuilder
///
/// Returns the index on the stack where the region was pushed. This can be
/// used with popRegions to exit a "scope", ending the region that was pushed.
- size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None,
- Optional<SourceLocation> EndLoc = None,
- Optional<Counter> FalseCount = None) {
+ size_t pushRegion(Counter Count,
+ std::optional<SourceLocation> StartLoc = std::nullopt,
+ std::optional<SourceLocation> EndLoc = std::nullopt,
+ std::optional<Counter> FalseCount = std::nullopt) {
if (StartLoc && !FalseCount) {
MostRecentLocation = *StartLoc;
@@ -810,7 +813,7 @@ struct CounterCoverageMappingBuilder
}
llvm::SmallSet<SourceLocation, 8> StartLocs;
- Optional<Counter> ParentCounter;
+ std::optional<Counter> ParentCounter;
for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
if (!I.hasStartLoc())
continue;
@@ -878,8 +881,8 @@ struct CounterCoverageMappingBuilder
}
/// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
- Optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
- SourceLocation BeforeLoc) {
+ std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
+ SourceLocation BeforeLoc) {
// If AfterLoc is in function-like macro, use the right parenthesis
// location.
if (AfterLoc.isMacroID()) {
@@ -917,10 +920,10 @@ struct CounterCoverageMappingBuilder
// If the start and end locations of the gap are both within the same macro
// file, the range may not be in source order.
if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
- return None;
+ return std::nullopt;
if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
!SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
- return None;
+ return std::nullopt;
return {{AfterLoc, BeforeLoc}};
}
@@ -1377,19 +1380,23 @@ struct CounterCoverageMappingBuilder
// Extend into the condition before we propagate through it below - this is
// needed to handle macros that generate the "if" but not the condition.
- extendRegion(S->getCond());
+ if (!S->isConsteval())
+ extendRegion(S->getCond());
Counter ParentCount = getRegion().getCounter();
Counter ThenCount = getRegionCounter(S);
- // Emitting a counter for the condition makes it easier to interpret the
- // counter for the body when looking at the coverage.
- propagateCounts(ParentCount, S->getCond());
+ if (!S->isConsteval()) {
+ // Emitting a counter for the condition makes it easier to interpret the
+ // counter for the body when looking at the coverage.
+ propagateCounts(ParentCount, S->getCond());
- // The 'then' count applies to the area immediately after the condition.
- auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
- if (Gap)
- fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
+ // The 'then' count applies to the area immediately after the condition.
+ std::optional<SourceRange> Gap =
+ findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
+ if (Gap)
+ fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
+ }
extendRegion(S->getThen());
Counter OutCount = propagateCounts(ThenCount, S->getThen());
@@ -1398,9 +1405,9 @@ struct CounterCoverageMappingBuilder
if (const Stmt *Else = S->getElse()) {
bool ThenHasTerminateStmt = HasTerminateStmt;
HasTerminateStmt = false;
-
// The 'else' count applies to the area immediately after the 'then'.
- Gap = findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
+ std::optional<SourceRange> Gap =
+ findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
if (Gap)
fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
extendRegion(Else);
@@ -1416,9 +1423,11 @@ struct CounterCoverageMappingBuilder
GapRegionCounter = OutCount;
}
- // Create Branch Region around condition.
- createBranchRegion(S->getCond(), ThenCount,
- subtractCounters(ParentCount, ThenCount));
+ if (!S->isConsteval()) {
+ // Create Branch Region around condition.
+ createBranchRegion(S->getCond(), ThenCount,
+ subtractCounters(ParentCount, ThenCount));
+ }
}
void VisitCXXTryStmt(const CXXTryStmt *S) {
@@ -1623,7 +1632,7 @@ void CoverageMappingModuleGen::emitFunctionMappingRecord(
#include "llvm/ProfileData/InstrProfData.inc"
};
auto *FunctionRecordTy =
- llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
+ llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
/*isPacked=*/true);
// Create the function record constant.
@@ -1631,8 +1640,8 @@ void CoverageMappingModuleGen::emitFunctionMappingRecord(
llvm::Constant *FunctionRecordVals[] = {
#include "llvm/ProfileData/InstrProfData.inc"
};
- auto *FuncRecordConstant = llvm::ConstantStruct::get(
- FunctionRecordTy, makeArrayRef(FunctionRecordVals));
+ auto *FuncRecordConstant =
+ llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
// Create the function record global.
auto *FuncRecord = new llvm::GlobalVariable(
@@ -1676,7 +1685,7 @@ void CoverageMappingModuleGen::addFunctionMappingRecord(
auto I = Entry.second;
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
}
- ArrayRef<std::string> FilenameRefs = llvm::makeArrayRef(FilenameStrs);
+ ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(FilenameStrs);
RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
Expressions, Regions);
if (Reader.read())
@@ -1722,20 +1731,19 @@ void CoverageMappingModuleGen::emit() {
#include "llvm/ProfileData/InstrProfData.inc"
};
auto CovDataHeaderTy =
- llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
+ llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes));
llvm::Constant *CovDataHeaderVals[] = {
#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
#include "llvm/ProfileData/InstrProfData.inc"
};
- auto CovDataHeaderVal = llvm::ConstantStruct::get(
- CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
+ auto CovDataHeaderVal =
+ llvm::ConstantStruct::get(CovDataHeaderTy, ArrayRef(CovDataHeaderVals));
// Create the coverage data record
llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
- auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
+ auto CovDataTy = llvm::StructType::get(Ctx, ArrayRef(CovDataTypes));
llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
- auto CovDataVal =
- llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
+ auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, ArrayRef(TUDataVals));
auto CovData = new llvm::GlobalVariable(
CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
CovDataVal, llvm::getCoverageMappingVarName());
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index fc2ff15a6acd..18403036e700 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -433,11 +433,7 @@ public:
ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true,
/*UseARMGuardVarABI=*/true) {}
- bool HasThisReturn(GlobalDecl GD) const override {
- return (isa<CXXConstructorDecl>(GD.getDecl()) || (
- isa<CXXDestructorDecl>(GD.getDecl()) &&
- GD.getDtorType() != Dtor_Deleting));
- }
+ bool constructorsAndDestructorsReturnThis() const override { return true; }
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV,
QualType ResTy) override;
@@ -468,11 +464,7 @@ public:
: ItaniumCXXABI(CGM) {}
private:
- bool HasThisReturn(GlobalDecl GD) const override {
- return isa<CXXConstructorDecl>(GD.getDecl()) ||
- (isa<CXXDestructorDecl>(GD.getDecl()) &&
- GD.getDtorType() != Dtor_Deleting);
- }
+ bool constructorsAndDestructorsReturnThis() const override { return true; }
};
class WebAssemblyCXXABI final : public ItaniumCXXABI {
@@ -486,11 +478,7 @@ public:
llvm::Value *Exn) override;
private:
- bool HasThisReturn(GlobalDecl GD) const override {
- return isa<CXXConstructorDecl>(GD.getDecl()) ||
- (isa<CXXDestructorDecl>(GD.getDecl()) &&
- GD.getDtorType() != Dtor_Deleting);
- }
+ bool constructorsAndDestructorsReturnThis() const override { return true; }
bool canCallMismatchedFunctionType() const override { return false; }
};
@@ -1014,7 +1002,7 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
} else {
const ASTContext &Context = getContext();
CharUnits PointerWidth = Context.toCharUnitsFromBits(
- Context.getTargetInfo().getPointerWidth(0));
+ Context.getTargetInfo().getPointerWidth(LangAS::Default));
VTableOffset = Index * PointerWidth.getQuantity();
}
@@ -1262,7 +1250,7 @@ void ItaniumCXXABI::emitRethrow(CodeGenFunction &CGF, bool isNoReturn) {
llvm::FunctionCallee Fn = CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
if (isNoReturn)
- CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, None);
+ CGF.EmitNoreturnRuntimeCallOrInvoke(Fn, std::nullopt);
else
CGF.EmitRuntimeCallOrInvoke(Fn);
}
@@ -1337,8 +1325,9 @@ static llvm::FunctionCallee getItaniumDynamicCastFn(CodeGenFunction &CGF) {
llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
// Mark the function as nounwind readonly.
- llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
- llvm::Attribute::ReadOnly };
+ llvm::AttrBuilder FuncAttrs(CGF.getLLVMContext());
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+ FuncAttrs.addMemoryAttr(llvm::MemoryEffects::readOnly());
llvm::AttributeList Attrs = llvm::AttributeList::get(
CGF.getLLVMContext(), llvm::AttributeList::FunctionIndex, FuncAttrs);
@@ -1769,8 +1758,11 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
}
}
- if (VTContext.isRelativeLayout() && !VTable->isDSOLocal())
- CGVT.GenerateRelativeVTableAlias(VTable, VTable->getName());
+ if (VTContext.isRelativeLayout()) {
+ CGVT.RemoveHwasanMetadata(VTable);
+ if (!VTable->isDSOLocal())
+ CGVT.GenerateRelativeVTableAlias(VTable, VTable->getName());
+ }
}
bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
@@ -1887,11 +1879,11 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
// values are read.
unsigned PAlign = CGM.getItaniumVTableContext().isRelativeLayout()
? 32
- : CGM.getTarget().getPointerAlign(0);
+ : CGM.getTarget().getPointerAlign(LangAS::Default);
VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
Name, VTableType, llvm::GlobalValue::ExternalLinkage,
- getContext().toCharUnitsFromBits(PAlign).getQuantity());
+ getContext().toCharUnitsFromBits(PAlign).getAsAlign());
VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
// In MS C++ if you have a class with virtual functions in which you are using
@@ -1932,7 +1924,9 @@ CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) {
VFunc = CGF.EmitVTableTypeCheckedLoad(
MethodDecl->getParent(), VTable, TyPtr,
- VTableIndex * CGM.getContext().getTargetInfo().getPointerWidth(0) / 8);
+ VTableIndex *
+ CGM.getContext().getTargetInfo().getPointerWidth(LangAS::Default) /
+ 8);
} else {
CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc);
@@ -2374,8 +2368,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
guardAlignment = CGF.getSizeAlign();
} else {
guardTy = CGF.Int64Ty;
- guardAlignment = CharUnits::fromQuantity(
- CGM.getDataLayout().getABITypeAlignment(guardTy));
+ guardAlignment =
+ CharUnits::fromQuantity(CGM.getDataLayout().getABITypeAlign(guardTy));
}
}
llvm::PointerType *guardPtrTy = guardTy->getPointerTo(
@@ -2393,13 +2387,15 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
}
// Create the guard variable with a zero-initializer.
- // Just absorb linkage and visibility from the guarded variable.
+ // Just absorb linkage, visibility and dll storage class from the guarded
+ // variable.
guard = new llvm::GlobalVariable(CGM.getModule(), guardTy,
false, var->getLinkage(),
llvm::ConstantInt::get(guardTy, 0),
guardName.str());
guard->setDSOLocal(var->isDSOLocal());
guard->setVisibility(var->getVisibility());
+ guard->setDLLStorageClass(var->getDLLStorageClass());
// If the variable is thread-local, so is its guard variable.
guard->setThreadLocalMode(var->getThreadLocalMode());
guard->setAlignment(guardAlignment.getAsAlign());
@@ -2437,54 +2433,76 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// __cxa_guard_release (&obj_guard);
// }
// }
-
- // Load the first byte of the guard variable.
- llvm::LoadInst *LI =
- Builder.CreateLoad(Builder.CreateElementBitCast(guardAddr, CGM.Int8Ty));
-
- // Itanium ABI:
- // An implementation supporting thread-safety on multiprocessor
- // systems must also guarantee that references to the initialized
- // object do not occur before the load of the initialization flag.
//
- // In LLVM, we do this by marking the load Acquire.
- if (threadsafe)
- LI->setAtomic(llvm::AtomicOrdering::Acquire);
+ // If threadsafe statics are enabled, but we don't have inline atomics, just
+ // call __cxa_guard_acquire unconditionally. The "inline" check isn't
+ // actually inline, and the user might not expect calls to __atomic libcalls.
- // For ARM, we should only check the first bit, rather than the entire byte:
- //
- // ARM C++ ABI 3.2.3.1:
- // To support the potential use of initialization guard variables
- // as semaphores that are the target of ARM SWP and LDREX/STREX
- // synchronizing instructions we define a static initialization
- // guard variable to be a 4-byte aligned, 4-byte word with the
- // following inline access protocol.
- // #define INITIALIZED 1
- // if ((obj_guard & INITIALIZED) != INITIALIZED) {
- // if (__cxa_guard_acquire(&obj_guard))
- // ...
- // }
- //
- // and similarly for ARM64:
- //
- // ARM64 C++ ABI 3.2.2:
- // This ABI instead only specifies the value bit 0 of the static guard
- // variable; all other bits are platform defined. Bit 0 shall be 0 when the
- // variable is not initialized and 1 when it is.
- llvm::Value *V =
- (UseARMGuardVarABI && !useInt8GuardVariable)
- ? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1))
- : LI;
- llvm::Value *NeedsInit = Builder.CreateIsNull(V, "guard.uninitialized");
-
- llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
+ unsigned MaxInlineWidthInBits = CGF.getTarget().getMaxAtomicInlineWidth();
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
+ if (!threadsafe || MaxInlineWidthInBits) {
+ // Load the first byte of the guard variable.
+ llvm::LoadInst *LI =
+ Builder.CreateLoad(Builder.CreateElementBitCast(guardAddr, CGM.Int8Ty));
+
+ // Itanium ABI:
+ // An implementation supporting thread-safety on multiprocessor
+ // systems must also guarantee that references to the initialized
+ // object do not occur before the load of the initialization flag.
+ //
+ // In LLVM, we do this by marking the load Acquire.
+ if (threadsafe)
+ LI->setAtomic(llvm::AtomicOrdering::Acquire);
+
+ // For ARM, we should only check the first bit, rather than the entire byte:
+ //
+ // ARM C++ ABI 3.2.3.1:
+ // To support the potential use of initialization guard variables
+ // as semaphores that are the target of ARM SWP and LDREX/STREX
+ // synchronizing instructions we define a static initialization
+ // guard variable to be a 4-byte aligned, 4-byte word with the
+ // following inline access protocol.
+ // #define INITIALIZED 1
+ // if ((obj_guard & INITIALIZED) != INITIALIZED) {
+ // if (__cxa_guard_acquire(&obj_guard))
+ // ...
+ // }
+ //
+ // and similarly for ARM64:
+ //
+ // ARM64 C++ ABI 3.2.2:
+ // This ABI instead only specifies the value bit 0 of the static guard
+ // variable; all other bits are platform defined. Bit 0 shall be 0 when the
+ // variable is not initialized and 1 when it is.
+ llvm::Value *V =
+ (UseARMGuardVarABI && !useInt8GuardVariable)
+ ? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1))
+ : LI;
+ llvm::Value *NeedsInit = Builder.CreateIsNull(V, "guard.uninitialized");
+
+ llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
+
+ // Check if the first byte of the guard variable is zero.
+ CGF.EmitCXXGuardedInitBranch(NeedsInit, InitCheckBlock, EndBlock,
+ CodeGenFunction::GuardKind::VariableGuard, &D);
+
+ CGF.EmitBlock(InitCheckBlock);
+ }
- // Check if the first byte of the guard variable is zero.
- CGF.EmitCXXGuardedInitBranch(NeedsInit, InitCheckBlock, EndBlock,
- CodeGenFunction::GuardKind::VariableGuard, &D);
-
- CGF.EmitBlock(InitCheckBlock);
+ // The semantics of dynamic initialization of variables with static or thread
+ // storage duration depends on whether they are declared at block-scope. The
+ // initialization of such variables at block-scope can be aborted with an
+ // exception and later retried (per C++20 [stmt.dcl]p4), and recursive entry
+ // to their initialization has undefined behavior (also per C++20
+ // [stmt.dcl]p4). For such variables declared at non-block scope, exceptions
+ // lead to termination (per C++20 [except.terminate]p1), and recursive
+ // references to the variables are governed only by the lifetime rules (per
+ // C++20 [class.cdtor]p2), which means such references are perfectly fine as
+ // long as they avoid touching memory. As a result, block-scope variables must
+ // not be marked as initialized until after initialization completes (unless
+ // the mark is reverted following an exception), but non-block-scope variables
+ // must be marked prior to initialization so that recursive accesses during
+ // initialization do not restart initialization.
// Variables used when coping with thread-safe statics and exceptions.
if (threadsafe) {
@@ -2501,6 +2519,12 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, guard);
CGF.EmitBlock(InitBlock);
+ } else if (!D.isLocalVarDecl()) {
+ // For non-local variables, store 1 into the first byte of the guard
+ // variable before the object initialization begins so that references
+ // to the variable during initialization don't restart initialization.
+ Builder.CreateStore(llvm::ConstantInt::get(CGM.Int8Ty, 1),
+ Builder.CreateElementBitCast(guardAddr, CGM.Int8Ty));
}
// Emit the initializer and add a global destructor if appropriate.
@@ -2513,9 +2537,10 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// Call __cxa_guard_release. This cannot throw.
CGF.EmitNounwindRuntimeCall(getGuardReleaseFn(CGM, guardPtrTy),
guardAddr.getPointer());
- } else {
- // Store 1 into the first byte of the guard variable after initialization is
- // complete.
+ } else if (D.isLocalVarDecl()) {
+ // For local variables, store 1 into the first byte of the guard variable
+ // after the object initialization completes so that initialization is
+ // retried if initialization is interrupted by an exception.
Builder.CreateStore(llvm::ConstantInt::get(CGM.Int8Ty, 1),
Builder.CreateElementBitCast(guardAddr, CGM.Int8Ty));
}
@@ -2687,7 +2712,7 @@ void CodeGenModule::registerGlobalDtorsWithAtExit() {
}
CGF.FinishFunction();
- AddGlobalCtor(GlobalInitFn, Priority, nullptr);
+ AddGlobalCtor(GlobalInitFn, Priority);
}
if (getCXXABI().useSinitAndSterm())
@@ -2988,14 +3013,16 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
// For a reference, the result of the wrapper function is a pointer to
// the referenced object.
- llvm::Value *Val = Var;
+ llvm::Value *Val = Builder.CreateThreadLocalAddress(Var);
+
if (VD->getType()->isReferenceType()) {
CharUnits Align = CGM.getContext().getDeclAlign(VD);
- Val = Builder.CreateAlignedLoad(Var->getValueType(), Var, Align);
+ Val = Builder.CreateAlignedLoad(Var->getValueType(), Val, Align);
}
if (Val->getType() != Wrapper->getReturnType())
Val = Builder.CreatePointerBitCastOrAddrSpaceCast(
Val, Wrapper->getReturnType(), "");
+
Builder.CreateRet(Val);
}
}
@@ -3154,7 +3181,7 @@ llvm::GlobalVariable *ItaniumRTTIBuilder::GetAddrOfTypeName(
auto Align = CGM.getContext().getTypeAlignInChars(CGM.getContext().CharTy);
llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable(
- Name, Init->getType(), Linkage, Align.getQuantity());
+ Name, Init->getType(), Linkage, Align.getAsAlign());
GV->setInitializer(Init);
@@ -3540,7 +3567,7 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
}
assert(isa<ObjCInterfaceType>(Ty));
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::ObjCInterface:
if (cast<ObjCInterfaceType>(Ty)->getDecl()->getSuperClass()) {
@@ -3852,8 +3879,8 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
if (CGM.supportsCOMDAT() && GV->isWeakForLinker())
GV->setComdat(M.getOrInsertComdat(GV->getName()));
- CharUnits Align =
- CGM.getContext().toCharUnitsFromBits(CGM.getTarget().getPointerAlign(0));
+ CharUnits Align = CGM.getContext().toCharUnitsFromBits(
+ CGM.getTarget().getPointerAlign(LangAS::Default));
GV->setAlignment(Align.getAsAlign());
// The Itanium ABI specifies that type_info objects must be globally
@@ -4031,7 +4058,8 @@ void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
// LLP64 platforms.
QualType OffsetFlagsTy = CGM.getContext().LongTy;
const TargetInfo &TI = CGM.getContext().getTargetInfo();
- if (TI.getTriple().isOSCygMing() && TI.getPointerWidth(0) > TI.getLongWidth())
+ if (TI.getTriple().isOSCygMing() &&
+ TI.getPointerWidth(LangAS::Default) > TI.getLongWidth())
OffsetFlagsTy = CGM.getContext().LongLongTy;
llvm::Type *OffsetFlagsLTy =
CGM.getTypes().ConvertType(OffsetFlagsTy);
@@ -4513,7 +4541,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
switch (CatchType.getQualifiers().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
CastExn = CGF.EmitARCRetainNonBlock(CastExn);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
@@ -4650,13 +4678,16 @@ void ItaniumCXXABI::emitBeginCatch(CodeGenFunction &CGF,
/// void @__clang_call_terminate(i8* %exn) nounwind noreturn
/// This code is used only in C++.
static llvm::FunctionCallee getClangCallTerminateFn(CodeGenModule &CGM) {
- llvm::FunctionType *fnTy =
- llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*isVarArg=*/false);
+ ASTContext &C = CGM.getContext();
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeBuiltinFunctionDeclaration(
+ C.VoidTy, {C.getPointerType(C.CharTy)});
+ llvm::FunctionType *fnTy = CGM.getTypes().GetFunctionType(FI);
llvm::FunctionCallee fnRef = CGM.CreateRuntimeFunction(
fnTy, "__clang_call_terminate", llvm::AttributeList(), /*Local=*/true);
llvm::Function *fn =
cast<llvm::Function>(fnRef.getCallee()->stripPointerCasts());
if (fn->empty()) {
+ CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, fn, /*IsThunk=*/false);
fn->setDoesNotThrow();
fn->setDoesNotReturn();
diff --git a/clang/lib/CodeGen/MacroPPCallbacks.cpp b/clang/lib/CodeGen/MacroPPCallbacks.cpp
index 2f09fd2b6c15..8589869f6e2f 100644
--- a/clang/lib/CodeGen/MacroPPCallbacks.cpp
+++ b/clang/lib/CodeGen/MacroPPCallbacks.cpp
@@ -120,7 +120,7 @@ void MacroPPCallbacks::FileEntered(SourceLocation Loc) {
if (PP.getSourceManager().isWrittenInCommandLineFile(Loc))
return;
updateStatusToNextScope();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CommandLineIncludeScope:
EnteredCommandLineIncludeFiles++;
break;
@@ -167,7 +167,7 @@ void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
void MacroPPCallbacks::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
- bool IsAngled, CharSourceRange FilenameRange, Optional<FileEntryRef> File,
+ bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
diff --git a/clang/lib/CodeGen/MacroPPCallbacks.h b/clang/lib/CodeGen/MacroPPCallbacks.h
index 01041b16e4b7..5af177d0c3fa 100644
--- a/clang/lib/CodeGen/MacroPPCallbacks.h
+++ b/clang/lib/CodeGen/MacroPPCallbacks.h
@@ -101,7 +101,7 @@ public:
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
- Optional<FileEntryRef> File, StringRef SearchPath,
+ OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) override;
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index f0c45654f8d9..ae785cce09f9 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -289,7 +289,7 @@ public:
CodeGenFunction::VPtr Vptr) override;
/// Don't initialize vptrs if dynamic class
- /// is marked with with the 'novtable' attribute.
+ /// is marked with the 'novtable' attribute.
bool doStructorsInitializeVPtrs(const CXXRecordDecl *VTableClass) override {
return !VTableClass->hasAttr<MSNoVTableAttr>();
}
@@ -458,7 +458,7 @@ public:
friend struct MSRTTIBuilder;
bool isImageRelative() const {
- return CGM.getTarget().getPointerWidth(/*AddrSpace=*/0) == 64;
+ return CGM.getTarget().getPointerWidth(LangAS::Default) == 64;
}
// 5 routines for constructing the llvm types for MS RTTI structs.
@@ -1086,8 +1086,8 @@ bool MicrosoftCXXABI::hasMostDerivedReturn(GlobalDecl GD) const {
return isDeletingDtor(GD);
}
-static bool isTrivialForAArch64MSVC(const CXXRecordDecl *RD) {
- // For AArch64, we use the C++14 definition of an aggregate, so we also
+static bool isTrivialForMSVC(const CXXRecordDecl *RD) {
+ // We use the C++14 definition of an aggregate, so we also
// check for:
// No private or protected non static data members.
// No base classes
@@ -1115,15 +1115,7 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
if (!RD)
return false;
- // Normally, the C++ concept of "is trivially copyable" is used to determine
- // if a struct can be returned directly. However, as MSVC and the language
- // have evolved, the definition of "trivially copyable" has changed, while the
- // ABI must remain stable. AArch64 uses the C++14 concept of an "aggregate",
- // while other ISAs use the older concept of "plain old data".
- bool isTrivialForABI = RD->isPOD();
- bool isAArch64 = CGM.getTarget().getTriple().isAArch64();
- if (isAArch64)
- isTrivialForABI = RD->canPassInRegisters() && isTrivialForAArch64MSVC(RD);
+ bool isTrivialForABI = RD->canPassInRegisters() && isTrivialForMSVC(RD);
// MSVC always returns structs indirectly from C++ instance methods.
bool isIndirectReturn = !isTrivialForABI || FI.isInstanceMethod();
@@ -1137,7 +1129,7 @@ bool MicrosoftCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
// On AArch64, use the `inreg` attribute if the object is considered to not
// be trivially copyable, or if this is an instance method struct return.
- FI.getReturnInfo().setInReg(isAArch64);
+ FI.getReturnInfo().setInReg(CGM.getTarget().getTriple().isAArch64());
return true;
}
@@ -1679,7 +1671,7 @@ void MicrosoftCXXABI::emitVTableTypeMetadata(const VPtrInfo &Info,
CharUnits AddressPoint =
getContext().getLangOpts().RTTIData
? getContext().toCharUnitsFromBits(
- getContext().getTargetInfo().getPointerWidth(0))
+ getContext().getTargetInfo().getPointerWidth(LangAS::Default))
: CharUnits::Zero();
if (Info.PathToIntroducingObject.empty()) {
@@ -1952,7 +1944,9 @@ CGCallee MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF,
if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) {
VFunc = CGF.EmitVTableTypeCheckedLoad(
getObjectWithVPtr(), VTable, Ty,
- ML.Index * CGM.getContext().getTargetInfo().getPointerWidth(0) / 8);
+ ML.Index *
+ CGM.getContext().getTargetInfo().getPointerWidth(LangAS::Default) /
+ 8);
} else {
if (CGM.getCodeGenOpts().PrepareForLTO)
CGF.EmitTypeMetadataCodeForVCall(getObjectWithVPtr(), VTable, Loc);
@@ -2083,6 +2077,8 @@ MicrosoftCXXABI::EmitVirtualMemPtrThunk(const CXXMethodDecl *MD,
// Start defining the function.
CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
FunctionArgs, MD->getLocation(), SourceLocation());
+
+ ApplyDebugLocation AL(CGF, MD->getLocation());
setCXXABIThisValue(CGF, loadIncomingCXXThis(CGF));
// Load the vfptr and then callee from the vftable. The callee should have
@@ -2127,7 +2123,7 @@ MicrosoftCXXABI::getAddrOfVBTable(const VPtrInfo &VBT, const CXXRecordDecl *RD,
CharUnits Alignment =
CGM.getContext().getTypeAlignInChars(CGM.getContext().IntTy);
llvm::GlobalVariable *GV = CGM.CreateOrReplaceCXXRuntimeVariable(
- Name, VBTableType, Linkage, Alignment.getQuantity());
+ Name, VBTableType, Linkage, Alignment.getAsAlign());
GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
if (RD->hasAttr<DLLImportAttr>())
@@ -2348,6 +2344,10 @@ void MicrosoftCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
if (D.getTLSKind())
return emitGlobalDtorWithTLRegDtor(CGF, D, Dtor, Addr);
+ // HLSL doesn't support atexit.
+ if (CGM.getLangOpts().HLSL)
+ return CGM.AddCXXDtorEntry(Dtor, Addr);
+
// The default behavior is to use atexit.
CGF.registerGlobalDtorWithAtExit(D, Dtor, Addr);
}
@@ -4142,7 +4142,7 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
CodeGenFunction::RunCleanupsScope Cleanups(CGF);
const auto *FPT = CD->getType()->castAs<FunctionProtoType>();
- CGF.EmitCallArgs(Args, FPT, llvm::makeArrayRef(ArgVec), CD, IsCopy ? 1 : 0);
+ CGF.EmitCallArgs(Args, FPT, llvm::ArrayRef(ArgVec), CD, IsCopy ? 1 : 0);
// Insert any ABI-specific implicit constructor arguments.
AddedStructorArgCounts ExtraArgs =
@@ -4350,10 +4350,10 @@ llvm::GlobalVariable *MicrosoftCXXABI::getCatchableTypeArray(QualType T) {
llvm::ArrayType *AT = llvm::ArrayType::get(CTType, NumEntries);
llvm::StructType *CTAType = getCatchableTypeArrayType(NumEntries);
llvm::Constant *Fields[] = {
- llvm::ConstantInt::get(CGM.IntTy, NumEntries), // NumEntries
+ llvm::ConstantInt::get(CGM.IntTy, NumEntries), // NumEntries
llvm::ConstantArray::get(
- AT, llvm::makeArrayRef(CatchableTypes.begin(),
- CatchableTypes.end())) // CatchableTypes
+ AT, llvm::ArrayRef(CatchableTypes.begin(),
+ CatchableTypes.end())) // CatchableTypes
};
SmallString<256> MangledName;
{
@@ -4470,10 +4470,45 @@ MicrosoftCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This,
}
bool MicrosoftCXXABI::isPermittedToBeHomogeneousAggregate(
- const CXXRecordDecl *CXXRD) const {
- // MSVC Windows on Arm64 considers a type not HFA if it is not an
- // aggregate according to the C++14 spec. This is not consistent with the
- // AAPCS64, but is defacto spec on that platform.
- return !CGM.getTarget().getTriple().isAArch64() ||
- isTrivialForAArch64MSVC(CXXRD);
+ const CXXRecordDecl *RD) const {
+ // All aggregates are permitted to be HFA on non-ARM platforms, which mostly
+ // affects vectorcall on x64/x86.
+ if (!CGM.getTarget().getTriple().isAArch64())
+ return true;
+ // MSVC Windows on Arm64 has its own rules for determining if a type is HFA
+ // that are inconsistent with the AAPCS64 ABI. The following are our best
+ // determination of those rules so far, based on observation of MSVC's
+ // behavior.
+ if (RD->isEmpty())
+ return false;
+ if (RD->isPolymorphic())
+ return false;
+ if (RD->hasNonTrivialCopyAssignment())
+ return false;
+ if (RD->hasNonTrivialDestructor())
+ return false;
+ if (RD->hasNonTrivialDefaultConstructor())
+ return false;
+ // These two are somewhat redundant given the caller
+ // (ABIInfo::isHomogeneousAggregate) checks the bases and fields, but that
+ // caller doesn't consider empty bases/fields to be non-homogenous, but it
+ // looks like Microsoft's AArch64 ABI does care about these empty types &
+ // anything containing/derived from one is non-homogeneous.
+ // Instead we could add another CXXABI entry point to query this property and
+ // have ABIInfo::isHomogeneousAggregate use that property.
+ // I don't think any other of the features listed above could be true of a
+ // base/field while not true of the outer struct. For example, if you have a
+ // base/field that has an non-trivial copy assignment/dtor/default ctor, then
+ // the outer struct's corresponding operation must be non-trivial.
+ for (const CXXBaseSpecifier &B : RD->bases()) {
+ if (const CXXRecordDecl *FRD = B.getType()->getAsCXXRecordDecl()) {
+ if (!isPermittedToBeHomogeneousAggregate(FRD))
+ return false;
+ }
+ }
+ // empty fields seem to be caught by the ABIInfo::isHomogeneousAggregate
+ // checking for padding - but maybe there are ways to end up with an empty
+ // field without padding? Not that I know of, so don't check fields here &
+ // rely on the padding check.
+ return true;
}
diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp
index c9a5e56c72c7..e3e953c34c59 100644
--- a/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/clang/lib/CodeGen/ModuleBuilder.cpp
@@ -179,6 +179,7 @@ namespace {
}
bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ // FIXME: Why not return false and abort parsing?
if (Diags.hasErrorOccurred())
return true;
diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index f6eaa35b4873..677b66d3e1dc 100644
--- a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -107,7 +107,7 @@ class PCHContainerGenerator : public ASTConsumer {
return true;
SmallVector<QualType, 16> ArgTypes;
- for (auto i : D->parameters())
+ for (auto *i : D->parameters())
ArgTypes.push_back(i->getType());
QualType RetTy = D->getReturnType();
QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
@@ -126,7 +126,7 @@ class PCHContainerGenerator : public ASTConsumer {
ArgTypes.push_back(D->getSelfType(Ctx, D->getClassInterface(),
selfIsPseudoStrong, selfIsConsumed));
ArgTypes.push_back(Ctx.getObjCSelType());
- for (auto i : D->parameters())
+ for (auto *i : D->parameters())
ArgTypes.push_back(i->getType());
QualType RetTy = D->getReturnType();
QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
diff --git a/clang/lib/CodeGen/PatternInit.cpp b/clang/lib/CodeGen/PatternInit.cpp
index 26ac8b63a9ba..4400bc443688 100644
--- a/clang/lib/CodeGen/PatternInit.cpp
+++ b/clang/lib/CodeGen/PatternInit.cpp
@@ -43,8 +43,8 @@ llvm::Constant *clang::CodeGen::initializationPatternFor(CodeGenModule &CGM,
}
if (Ty->isPtrOrPtrVectorTy()) {
auto *PtrTy = cast<llvm::PointerType>(Ty->getScalarType());
- unsigned PtrWidth = CGM.getContext().getTargetInfo().getPointerWidth(
- PtrTy->getAddressSpace());
+ unsigned PtrWidth =
+ CGM.getDataLayout().getPointerSizeInBits(PtrTy->getAddressSpace());
if (PtrWidth > 64)
llvm_unreachable("pattern initialization of unsupported pointer width");
llvm::Type *IntTy = llvm::IntegerType::get(CGM.getLLVMContext(), PtrWidth);
diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp
index 7848cf012633..554f1ea2a47d 100644
--- a/clang/lib/CodeGen/SanitizerMetadata.cpp
+++ b/clang/lib/CodeGen/SanitizerMetadata.cpp
@@ -104,5 +104,5 @@ void SanitizerMetadata::disableSanitizerForGlobal(llvm::GlobalVariable *GV) {
void SanitizerMetadata::disableSanitizerForInstruction(llvm::Instruction *I) {
I->setMetadata(llvm::LLVMContext::MD_nosanitize,
- llvm::MDNode::get(CGM.getLLVMContext(), None));
+ llvm::MDNode::get(CGM.getLLVMContext(), std::nullopt));
}
diff --git a/clang/lib/CodeGen/SwiftCallingConv.cpp b/clang/lib/CodeGen/SwiftCallingConv.cpp
index 8fb24fcecf53..63d975193c02 100644
--- a/clang/lib/CodeGen/SwiftCallingConv.cpp
+++ b/clang/lib/CodeGen/SwiftCallingConv.cpp
@@ -15,13 +15,14 @@
#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/Basic/TargetInfo.h"
+#include <optional>
using namespace clang;
using namespace CodeGen;
using namespace swiftcall;
static const SwiftABIInfo &getSwiftABIInfo(CodeGenModule &CGM) {
- return cast<SwiftABIInfo>(CGM.getTargetCodeGenInfo().getABIInfo());
+ return CGM.getTargetCodeGenInfo().getSwiftABIInfo();
}
static bool isPowerOf2(unsigned n) {
@@ -124,7 +125,7 @@ void SwiftAggLowering::addTypedData(const RecordDecl *record, CharUnits begin,
const ASTRecordLayout &layout) {
// Unions are a special case.
if (record->isUnion()) {
- for (auto field : record->fields()) {
+ for (auto *field : record->fields()) {
if (field->isBitField()) {
addBitFieldData(field, begin, 0);
} else {
@@ -161,7 +162,7 @@ void SwiftAggLowering::addTypedData(const RecordDecl *record, CharUnits begin,
}
// Add fields.
- for (auto field : record->fields()) {
+ for (auto *field : record->fields()) {
auto fieldOffsetInBits = layout.getFieldOffset(field->getFieldIndex());
if (field->isBitField()) {
addBitFieldData(field, begin, fieldOffsetInBits);
@@ -439,7 +440,7 @@ static bool isMergeableEntryType(llvm::Type *type) {
// merge pointers, but (1) it doesn't currently matter in practice because
// the chunk size is never greater than the size of a pointer and (2)
// Swift IRGen uses integer types for a lot of things that are "really"
- // just storing pointers (like Optional<SomePointer>). If we ever have a
+ // just storing pointers (like std::optional<SomePointer>). If we ever have a
// target that would otherwise combine pointers, we should put some effort
// into fixing those cases in Swift IRGen and then call out pointer types
// here.
@@ -590,9 +591,8 @@ SwiftAggLowering::getCoerceAndExpandTypes() const {
hasPadding = true;
}
- if (!packed && !entry.Begin.isMultipleOf(
- CharUnits::fromQuantity(
- CGM.getDataLayout().getABITypeAlignment(entry.Type))))
+ if (!packed && !entry.Begin.isMultipleOf(CharUnits::fromQuantity(
+ CGM.getDataLayout().getABITypeAlign(entry.Type))))
packed = true;
elts.push_back(entry.Type);
@@ -631,9 +631,8 @@ bool SwiftAggLowering::shouldPassIndirectly(bool asReturnValue) const {
// Avoid copying the array of types when there's just a single element.
if (Entries.size() == 1) {
- return getSwiftABIInfo(CGM).shouldPassIndirectlyForSwift(
- Entries.back().Type,
- asReturnValue);
+ return getSwiftABIInfo(CGM).shouldPassIndirectly(Entries.back().Type,
+ asReturnValue);
}
SmallVector<llvm::Type*, 8> componentTys;
@@ -641,31 +640,27 @@ bool SwiftAggLowering::shouldPassIndirectly(bool asReturnValue) const {
for (auto &entry : Entries) {
componentTys.push_back(entry.Type);
}
- return getSwiftABIInfo(CGM).shouldPassIndirectlyForSwift(componentTys,
- asReturnValue);
+ return getSwiftABIInfo(CGM).shouldPassIndirectly(componentTys, asReturnValue);
}
bool swiftcall::shouldPassIndirectly(CodeGenModule &CGM,
ArrayRef<llvm::Type*> componentTys,
bool asReturnValue) {
- return getSwiftABIInfo(CGM).shouldPassIndirectlyForSwift(componentTys,
- asReturnValue);
+ return getSwiftABIInfo(CGM).shouldPassIndirectly(componentTys, asReturnValue);
}
CharUnits swiftcall::getMaximumVoluntaryIntegerSize(CodeGenModule &CGM) {
// Currently always the size of an ordinary pointer.
return CGM.getContext().toCharUnitsFromBits(
- CGM.getContext().getTargetInfo().getPointerWidth(0));
+ CGM.getContext().getTargetInfo().getPointerWidth(LangAS::Default));
}
CharUnits swiftcall::getNaturalAlignment(CodeGenModule &CGM, llvm::Type *type) {
// For Swift's purposes, this is always just the store size of the type
// rounded up to a power of 2.
auto size = (unsigned long long) getTypeStoreSize(CGM, type).getQuantity();
- if (!isPowerOf2(size)) {
- size = 1ULL << (llvm::findLastSet(size, llvm::ZB_Undefined) + 1);
- }
- assert(size >= CGM.getDataLayout().getABITypeAlignment(type));
+ size = llvm::bit_ceil(size);
+ assert(CGM.getDataLayout().getABITypeAlign(type) <= size);
return CharUnits::fromQuantity(size);
}
@@ -699,8 +694,7 @@ bool swiftcall::isLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize,
bool swiftcall::isLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize,
llvm::Type *eltTy, unsigned numElts) {
assert(numElts > 1 && "illegal vector length");
- return getSwiftABIInfo(CGM)
- .isLegalVectorTypeForSwift(vectorSize, eltTy, numElts);
+ return getSwiftABIInfo(CGM).isLegalVectorType(vectorSize, eltTy, numElts);
}
std::pair<llvm::Type*, unsigned>
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index d1ee61eab9d6..be1dbe8480c6 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -23,7 +23,6 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/CodeGen/CGFunctionInfo.h"
-#include "clang/CodeGen/SwiftCallingConv.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
@@ -107,7 +106,7 @@ static llvm::Type *getVAListElementType(CodeGenFunction &CGF) {
}
bool ABIInfo::isPromotableIntegerTypeForABI(QualType Ty) const {
- if (Ty->isPromotableIntegerType())
+ if (getContext().isPromotableIntegerType(Ty))
return true;
if (const auto *EIT = Ty->getAs<BitIntType>())
@@ -117,7 +116,9 @@ bool ABIInfo::isPromotableIntegerTypeForABI(QualType Ty) const {
return false;
}
-ABIInfo::~ABIInfo() {}
+ABIInfo::~ABIInfo() = default;
+
+SwiftABIInfo::~SwiftABIInfo() = default;
/// Does the given lowering require more than the given number of
/// registers when expanded?
@@ -140,7 +141,7 @@ static bool occupiesMoreThan(CodeGenTypes &cgt,
if (type->isPointerTy()) {
intCount++;
} else if (auto intTy = dyn_cast<llvm::IntegerType>(type)) {
- auto ptrWidth = cgt.getTarget().getPointerWidth(0);
+ auto ptrWidth = cgt.getTarget().getPointerWidth(LangAS::Default);
intCount += (intTy->getBitWidth() + ptrWidth - 1) / ptrWidth;
} else {
assert(type->isVectorTy() || type->isFloatingPointTy());
@@ -151,12 +152,16 @@ static bool occupiesMoreThan(CodeGenTypes &cgt,
return (intCount + fpCount > maxAllRegisters);
}
-bool SwiftABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize,
- llvm::Type *eltTy,
- unsigned numElts) const {
+bool SwiftABIInfo::shouldPassIndirectly(ArrayRef<llvm::Type *> ComponentTys,
+ bool AsReturnValue) const {
+ return occupiesMoreThan(CGT, ComponentTys, /*total=*/4);
+}
+
+bool SwiftABIInfo::isLegalVectorType(CharUnits VectorSize, llvm::Type *EltTy,
+ unsigned NumElts) const {
// The default implementation of this assumes that the target guarantees
// 128-bit SIMD support but nothing more.
- return (vectorSize.getQuantity() > 8 && vectorSize.getQuantity() <= 16);
+ return (VectorSize.getQuantity() > 8 && VectorSize.getQuantity() <= 16);
}
static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT,
@@ -317,13 +322,17 @@ static llvm::Value *emitRoundPointerUpToAlignment(CodeGenFunction &CGF,
/// leaving one or more empty slots behind as padding. If this
/// is false, the returned address might be less-aligned than
/// DirectAlign.
+/// \param ForceRightAdjust - Default is false. On big-endian platform and
+/// if the argument is smaller than a slot, set this flag will force
+/// right-adjust the argument in its slot irrespective of the type.
static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF,
Address VAListAddr,
llvm::Type *DirectTy,
CharUnits DirectSize,
CharUnits DirectAlign,
CharUnits SlotSize,
- bool AllowHigherAlign) {
+ bool AllowHigherAlign,
+ bool ForceRightAdjust = false) {
// Cast the element type to i8* if necessary. Some platforms define
// va_list as a struct containing an i8* instead of just an i8*.
if (VAListAddr.getElementType() != CGF.Int8PtrTy)
@@ -349,7 +358,7 @@ static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF,
// If the argument is smaller than a slot, and this is a big-endian
// target, the argument will be right-adjusted in its slot.
if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() &&
- !DirectTy->isStructTy()) {
+ (!DirectTy->isStructTy() || ForceRightAdjust)) {
Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize);
}
@@ -370,11 +379,15 @@ static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF,
/// an argument type with an alignment greater than the slot size
/// will be emitted on a higher-alignment address, potentially
/// leaving one or more empty slots behind as padding.
+/// \param ForceRightAdjust - Default is false. On big-endian platform and
+/// if the argument is smaller than a slot, set this flag will force
+/// right-adjust the argument in its slot irrespective of the type.
static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType ValueTy, bool IsIndirect,
TypeInfoChars ValueInfo,
CharUnits SlotSizeAndAlign,
- bool AllowHigherAlign) {
+ bool AllowHigherAlign,
+ bool ForceRightAdjust = false) {
// The size and alignment of the value that was passed directly.
CharUnits DirectSize, DirectAlign;
if (IsIndirect) {
@@ -390,9 +403,9 @@ static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,
if (IsIndirect)
DirectTy = DirectTy->getPointerTo(0);
- Address Addr =
- emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize, DirectAlign,
- SlotSizeAndAlign, AllowHigherAlign);
+ Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize,
+ DirectAlign, SlotSizeAndAlign,
+ AllowHigherAlign, ForceRightAdjust);
if (IsIndirect) {
Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align);
@@ -814,7 +827,7 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
// This is a very simple ABI that relies a lot on DefaultABIInfo.
//===----------------------------------------------------------------------===//
-class WebAssemblyABIInfo final : public SwiftABIInfo {
+class WebAssemblyABIInfo final : public ABIInfo {
public:
enum ABIKind {
MVP = 0,
@@ -827,7 +840,7 @@ private:
public:
explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT, ABIKind Kind)
- : SwiftABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {}
+ : ABIInfo(CGT), defaultInfo(CGT), Kind(Kind) {}
private:
ABIArgInfo classifyReturnType(QualType RetTy) const;
@@ -845,22 +858,16 @@ private:
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override;
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
-
- bool isSwiftErrorInRegister() const override {
- return false;
- }
};
class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
public:
explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
WebAssemblyABIInfo::ABIKind K)
- : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {}
+ : TargetCodeGenInfo(std::make_unique<WebAssemblyABIInfo>(CGT, K)) {
+ SwiftInfo =
+ std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
+ }
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const override {
@@ -1071,7 +1078,7 @@ static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
.Cases("y", "&y", "^Ym", true)
.Default(false);
if (IsMMXCons && Ty->isVectorTy()) {
- if (cast<llvm::VectorType>(Ty)->getPrimitiveSizeInBits().getFixedSize() !=
+ if (cast<llvm::VectorType>(Ty)->getPrimitiveSizeInBits().getFixedValue() !=
64) {
// Invalid MMX constraint
return nullptr;
@@ -1136,7 +1143,7 @@ struct CCState {
};
/// X86_32ABIInfo - The X86-32 ABI information.
-class X86_32ABIInfo : public SwiftABIInfo {
+class X86_32ABIInfo : public ABIInfo {
enum Class {
Integer,
Float
@@ -1210,26 +1217,27 @@ public:
X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI,
bool RetSmallStructInRegABI, bool Win32StructABI,
unsigned NumRegisterParameters, bool SoftFloatABI)
- : SwiftABIInfo(CGT), IsDarwinVectorABI(DarwinVectorABI),
- IsRetSmallStructInRegABI(RetSmallStructInRegABI),
- IsWin32StructABI(Win32StructABI), IsSoftFloatABI(SoftFloatABI),
- IsMCUABI(CGT.getTarget().getTriple().isOSIAMCU()),
- IsLinuxABI(CGT.getTarget().getTriple().isOSLinux() ||
- CGT.getTarget().getTriple().isOSCygMing()),
- DefaultNumRegisterParameters(NumRegisterParameters) {}
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
+ : ABIInfo(CGT), IsDarwinVectorABI(DarwinVectorABI),
+ IsRetSmallStructInRegABI(RetSmallStructInRegABI),
+ IsWin32StructABI(Win32StructABI), IsSoftFloatABI(SoftFloatABI),
+ IsMCUABI(CGT.getTarget().getTriple().isOSIAMCU()),
+ IsLinuxABI(CGT.getTarget().getTriple().isOSLinux() ||
+ CGT.getTarget().getTriple().isOSCygMing()),
+ DefaultNumRegisterParameters(NumRegisterParameters) {}
+};
+
+class X86_32SwiftABIInfo : public SwiftABIInfo {
+public:
+ explicit X86_32SwiftABIInfo(CodeGenTypes &CGT)
+ : SwiftABIInfo(CGT, /*SwiftErrorInRegister=*/false) {}
+
+ bool shouldPassIndirectly(ArrayRef<llvm::Type *> ComponentTys,
+ bool AsReturnValue) const override {
// LLVM's x86-32 lowering currently only assigns up to three
// integer registers and three fp registers. Oddly, it'll use up to
// four vector registers for vectors, but those can overlap with the
// scalar registers.
- return occupiesMoreThan(CGT, scalars, /*total*/ 3);
- }
-
- bool isSwiftErrorInRegister() const override {
- // x86-32 lowering does not support passing swifterror in a register.
- return false;
+ return occupiesMoreThan(CGT, ComponentTys, /*total=*/3);
}
};
@@ -1240,7 +1248,9 @@ public:
unsigned NumRegisterParameters, bool SoftFloatABI)
: TargetCodeGenInfo(std::make_unique<X86_32ABIInfo>(
CGT, DarwinVectorABI, RetSmallStructInRegABI, Win32StructABI,
- NumRegisterParameters, SoftFloatABI)) {}
+ NumRegisterParameters, SoftFloatABI)) {
+ SwiftInfo = std::make_unique<X86_32SwiftABIInfo>(CGT);
+ }
static bool isStructReturnInRegABI(
const llvm::Triple &Triple, const CodeGenOptions &Opts);
@@ -1769,23 +1779,22 @@ bool X86_32ABIInfo::shouldAggregateUseDirect(QualType Ty, CCState &State,
}
bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const {
- if (!updateFreeRegs(Ty, State))
- return false;
+ bool IsPtrOrInt = (getContext().getTypeSize(Ty) <= 32) &&
+ (Ty->isIntegralOrEnumerationType() || Ty->isPointerType() ||
+ Ty->isReferenceType());
- if (IsMCUABI)
+ if (!IsPtrOrInt && (State.CC == llvm::CallingConv::X86_FastCall ||
+ State.CC == llvm::CallingConv::X86_VectorCall))
return false;
- if (State.CC == llvm::CallingConv::X86_FastCall ||
- State.CC == llvm::CallingConv::X86_VectorCall ||
- State.CC == llvm::CallingConv::X86_RegCall) {
- if (getContext().getTypeSize(Ty) > 32)
- return false;
+ if (!updateFreeRegs(Ty, State))
+ return false;
- return (Ty->isIntegralOrEnumerationType() || Ty->isPointerType() ||
- Ty->isReferenceType());
- }
+ if (!IsPtrOrInt && State.CC == llvm::CallingConv::X86_RegCall)
+ return false;
- return true;
+ // Return true to apply inreg to all legal parameters except for MCU targets.
+ return !IsMCUABI;
}
void X86_32ABIInfo::runVectorCallFirstPass(CGFunctionInfo &FI, CCState &State) const {
@@ -2250,7 +2259,7 @@ static unsigned getNativeVectorSizeForAVXABI(X86AVXABILevel AVXLevel) {
}
/// X86_64ABIInfo - The X86_64 ABI information.
-class X86_64ABIInfo : public SwiftABIInfo {
+class X86_64ABIInfo : public ABIInfo {
enum Class {
Integer = 0,
SSE,
@@ -2396,10 +2405,9 @@ class X86_64ABIInfo : public SwiftABIInfo {
bool Has64BitPointers;
public:
- X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) :
- SwiftABIInfo(CGT), AVXLevel(AVXLevel),
- Has64BitPointers(CGT.getDataLayout().getPointerSize(0) == 8) {
- }
+ X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel)
+ : ABIInfo(CGT), AVXLevel(AVXLevel),
+ Has64BitPointers(CGT.getDataLayout().getPointerSize(0) == 8) {}
bool isPassedUsingAVXType(QualType type) const {
unsigned neededInt, neededSSE;
@@ -2409,7 +2417,7 @@ public:
if (info.isDirect()) {
llvm::Type *ty = info.getCoerceToType();
if (llvm::VectorType *vectorTy = dyn_cast_or_null<llvm::VectorType>(ty))
- return vectorTy->getPrimitiveSizeInBits().getFixedSize() > 128;
+ return vectorTy->getPrimitiveSizeInBits().getFixedValue() > 128;
}
return false;
}
@@ -2424,21 +2432,13 @@ public:
bool has64BitPointers() const {
return Has64BitPointers;
}
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
- bool isSwiftErrorInRegister() const override {
- return true;
- }
};
/// WinX86_64ABIInfo - The Windows X86_64 ABI information.
-class WinX86_64ABIInfo : public SwiftABIInfo {
+class WinX86_64ABIInfo : public ABIInfo {
public:
WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel)
- : SwiftABIInfo(CGT), AVXLevel(AVXLevel),
+ : ABIInfo(CGT), AVXLevel(AVXLevel),
IsMingw64(getTarget().getTriple().isWindowsGNUEnvironment()) {}
void computeInfo(CGFunctionInfo &FI) const override;
@@ -2457,15 +2457,6 @@ public:
return isX86VectorCallAggregateSmallEnough(NumMembers);
}
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type *> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
-
- bool isSwiftErrorInRegister() const override {
- return true;
- }
-
private:
ABIArgInfo classify(QualType Ty, unsigned &FreeSSERegs, bool IsReturnType,
bool IsVectorCall, bool IsRegCall) const;
@@ -2480,7 +2471,10 @@ private:
class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel)
- : TargetCodeGenInfo(std::make_unique<X86_64ABIInfo>(CGT, AVXLevel)) {}
+ : TargetCodeGenInfo(std::make_unique<X86_64ABIInfo>(CGT, AVXLevel)) {
+ SwiftInfo =
+ std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/true);
+ }
const X86_64ABIInfo &getABIInfo() const {
return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
@@ -2624,7 +2618,7 @@ void X86_64TargetCodeGenInfo::checkFunctionCallABI(
llvm::StringMap<bool> CalleeMap;
unsigned ArgIndex = 0;
- // We need to loop through the actual call arguments rather than the the
+ // We need to loop through the actual call arguments rather than the
// function's parameters, in case this variadic.
for (const CallArg &Arg : Args) {
// The "avx" feature changes how vectors >128 in size are passed. "avx512f"
@@ -2722,7 +2716,10 @@ class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
public:
WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
X86AVXABILevel AVXLevel)
- : TargetCodeGenInfo(std::make_unique<WinX86_64ABIInfo>(CGT, AVXLevel)) {}
+ : TargetCodeGenInfo(std::make_unique<WinX86_64ABIInfo>(CGT, AVXLevel)) {
+ SwiftInfo =
+ std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/true);
+ }
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const override;
@@ -2871,7 +2868,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
} else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) {
Current = Integer;
} else if (k == BuiltinType::Float || k == BuiltinType::Double ||
- k == BuiltinType::Float16) {
+ k == BuiltinType::Float16 || k == BuiltinType::BFloat16) {
Current = SSE;
} else if (k == BuiltinType::LongDouble) {
const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
@@ -3002,7 +2999,8 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
Current = Integer;
else if (Size <= 128)
Lo = Hi = Integer;
- } else if (ET->isFloat16Type() || ET == getContext().FloatTy) {
+ } else if (ET->isFloat16Type() || ET == getContext().FloatTy ||
+ ET->isBFloat16Type()) {
Current = SSE;
} else if (ET == getContext().DoubleTy) {
Lo = Hi = SSE;
@@ -3474,9 +3472,9 @@ GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
if (SourceSize > T0Size)
T1 = getFPTypeAtOffset(IRType, IROffset + T0Size, TD);
if (T1 == nullptr) {
- // Check if IRType is a half + float. float type will be in IROffset+4 due
+ // Check if IRType is a half/bfloat + float. float type will be in IROffset+4 due
// to its alignment.
- if (T0->isHalfTy() && SourceSize > 4)
+ if (T0->is16bitFPTy() && SourceSize > 4)
T1 = getFPTypeAtOffset(IRType, IROffset + 4, TD);
// If we can't get a second FP type, return a simple half or float.
// avx512fp16-abi.c:pr51813_2 shows it works to return float for
@@ -3488,7 +3486,7 @@ GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
if (T0->isFloatTy() && T1->isFloatTy())
return llvm::FixedVectorType::get(T0, 2);
- if (T0->isHalfTy() && T1->isHalfTy()) {
+ if (T0->is16bitFPTy() && T1->is16bitFPTy()) {
llvm::Type *T2 = nullptr;
if (SourceSize > 4)
T2 = getFPTypeAtOffset(IRType, IROffset + 4, TD);
@@ -3497,7 +3495,7 @@ GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset,
return llvm::FixedVectorType::get(T0, 4);
}
- if (T0->isHalfTy() || T1->isHalfTy())
+ if (T0->is16bitFPTy() || T1->is16bitFPTy())
return llvm::FixedVectorType::get(llvm::Type::getHalfTy(getVMContext()), 4);
return llvm::Type::getDoubleTy(getVMContext());
@@ -3594,7 +3592,7 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi,
// (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have
// the second element at offset 8. Check for this:
unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo);
- unsigned HiAlign = TD.getABITypeAlignment(Hi);
+ llvm::Align HiAlign = TD.getABITypeAlign(Hi);
unsigned HiStart = llvm::alignTo(LoSize, HiAlign);
assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!");
@@ -4171,13 +4169,13 @@ Address X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
// FIXME: Our choice of alignment here and below is probably pessimistic.
llvm::Value *V = CGF.Builder.CreateAlignedLoad(
TyLo, CGF.Builder.CreateBitCast(RegLoAddr, PTyLo),
- CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(TyLo)));
+ CharUnits::fromQuantity(getDataLayout().getABITypeAlign(TyLo)));
CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
// Copy the second element.
V = CGF.Builder.CreateAlignedLoad(
TyHi, CGF.Builder.CreateBitCast(RegHiAddr, PTyHi),
- CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(TyHi)));
+ CharUnits::fromQuantity(getDataLayout().getABITypeAlign(TyHi)));
CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
RegAddr = CGF.Builder.CreateElementBitCast(Tmp, LTy);
@@ -4590,7 +4588,7 @@ bool AIXABIInfo::isPromotableTypeForABI(QualType Ty) const {
Ty = EnumTy->getDecl()->getIntegerType();
// Promotable integer types are required to be promoted by the ABI.
- if (Ty->isPromotableIntegerType())
+ if (getContext().isPromotableIntegerType(Ty))
return true;
if (!Is64Bit)
@@ -4984,7 +4982,7 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
namespace {
/// PPC64_SVR4_ABIInfo - The 64-bit PowerPC ELF (SVR4) ABI information.
-class PPC64_SVR4_ABIInfo : public SwiftABIInfo {
+class PPC64_SVR4_ABIInfo : public ABIInfo {
public:
enum ABIKind {
ELFv1 = 0,
@@ -4999,7 +4997,7 @@ private:
public:
PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, ABIKind Kind,
bool SoftFloatABI)
- : SwiftABIInfo(CGT), Kind(Kind), IsSoftFloatABI(SoftFloatABI) {}
+ : ABIInfo(CGT), Kind(Kind), IsSoftFloatABI(SoftFloatABI) {}
bool isPromotableTypeForABI(QualType Ty) const;
CharUnits getParamTypeAlignment(QualType Ty) const;
@@ -5040,15 +5038,6 @@ public:
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override;
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
-
- bool isSwiftErrorInRegister() const override {
- return false;
- }
};
class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo {
@@ -5058,7 +5047,10 @@ public:
PPC64_SVR4_ABIInfo::ABIKind Kind,
bool SoftFloatABI)
: TargetCodeGenInfo(
- std::make_unique<PPC64_SVR4_ABIInfo>(CGT, Kind, SoftFloatABI)) {}
+ std::make_unique<PPC64_SVR4_ABIInfo>(CGT, Kind, SoftFloatABI)) {
+ SwiftInfo =
+ std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
+ }
int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override {
// This is recovered from gcc output.
@@ -5467,8 +5459,21 @@ Address PPC64_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
}
// Otherwise, just use the general rule.
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false,
- TypeInfo, SlotSize, /*AllowHigher*/ true);
+ //
+ // The PPC64 ABI passes some arguments in integer registers, even to variadic
+ // functions. To allow va_list to use the simple "void*" representation,
+ // variadic calls allocate space in the argument area for the integer argument
+ // registers, and variadic functions spill their integer argument registers to
+ // this area in their prologues. When aggregates smaller than a register are
+ // passed this way, they are passed in the least significant bits of the
+ // register, which means that after spilling on big-endian targets they will
+ // be right-aligned in their argument slot. This is uncommon; for a variety of
+ // reasons, other big-endian targets don't end up right-aligning aggregate
+ // types this way, and so right-alignment only applies to fundamental types.
+ // So on PPC64, we must force the use of right-alignment even for aggregates.
+ return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo,
+ SlotSize, /*AllowHigher*/ true,
+ /*ForceRightAdjust*/ true);
}
bool
@@ -5492,7 +5497,7 @@ PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
namespace {
-class AArch64ABIInfo : public SwiftABIInfo {
+class AArch64ABIInfo : public ABIInfo {
public:
enum ABIKind {
AAPCS = 0,
@@ -5504,8 +5509,7 @@ private:
ABIKind Kind;
public:
- AArch64ABIInfo(CodeGenTypes &CGT, ABIKind Kind)
- : SwiftABIInfo(CGT), Kind(Kind) {}
+ AArch64ABIInfo(CodeGenTypes &CGT, ABIKind Kind) : ABIInfo(CGT), Kind(Kind) {}
private:
ABIKind getABIKind() const { return Kind; }
@@ -5553,26 +5557,26 @@ private:
Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override;
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
- bool isSwiftErrorInRegister() const override {
- return true;
- }
-
- bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
- unsigned elts) const override;
-
bool allowBFloatArgsAndRet() const override {
return getTarget().hasBFloat16Type();
}
};
+class AArch64SwiftABIInfo : public SwiftABIInfo {
+public:
+ explicit AArch64SwiftABIInfo(CodeGenTypes &CGT)
+ : SwiftABIInfo(CGT, /*SwiftErrorInRegister=*/true) {}
+
+ bool isLegalVectorType(CharUnits VectorSize, llvm::Type *EltTy,
+ unsigned NumElts) const override;
+};
+
class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
public:
AArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind Kind)
- : TargetCodeGenInfo(std::make_unique<AArch64ABIInfo>(CGT, Kind)) {}
+ : TargetCodeGenInfo(std::make_unique<AArch64ABIInfo>(CGT, Kind)) {
+ SwiftInfo = std::make_unique<AArch64SwiftABIInfo>(CGT);
+ }
StringRef getARCRetainAutoreleasedReturnValueMarker() const override {
return "mov\tfp, fp\t\t// marker for objc_retainAutoreleaseReturnValue";
@@ -5594,14 +5598,15 @@ public:
if (TA == nullptr)
return;
- ParsedTargetAttr Attr = TA->parse();
+ ParsedTargetAttr Attr =
+ CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
if (Attr.BranchProtection.empty())
return;
TargetInfo::BranchProtectionInfo BPI;
StringRef Error;
- (void)CGM.getTarget().validateBranchProtection(
- Attr.BranchProtection, Attr.Architecture, BPI, Error);
+ (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
+ Attr.CPU, BPI, Error);
assert(Error.empty());
auto *Fn = cast<llvm::Function>(GV);
@@ -5826,8 +5831,9 @@ AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic,
Alignment = getContext().getTypeUnadjustedAlign(Ty);
Alignment = Alignment < 128 ? 64 : 128;
} else {
- Alignment = std::max(getContext().getTypeAlign(Ty),
- (unsigned)getTarget().getPointerWidth(0));
+ Alignment =
+ std::max(getContext().getTypeAlign(Ty),
+ (unsigned)getTarget().getPointerWidth(LangAS::Default));
}
Size = llvm::alignTo(Size, Alignment);
@@ -5946,13 +5952,13 @@ bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const {
return false;
}
-bool AArch64ABIInfo::isLegalVectorTypeForSwift(CharUnits totalSize,
- llvm::Type *eltTy,
- unsigned elts) const {
- if (!llvm::isPowerOf2_32(elts))
+bool AArch64SwiftABIInfo::isLegalVectorType(CharUnits VectorSize,
+ llvm::Type *EltTy,
+ unsigned NumElts) const {
+ if (!llvm::isPowerOf2_32(NumElts))
return false;
- if (totalSize.getQuantity() != 8 &&
- (totalSize.getQuantity() != 16 || elts == 1))
+ if (VectorSize.getQuantity() != 8 &&
+ (VectorSize.getQuantity() != 16 || NumElts == 1))
return false;
return true;
}
@@ -5992,6 +5998,16 @@ Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
ABIArgInfo AI = classifyArgumentType(Ty, /*IsVariadic=*/true,
CGF.CurFnInfo->getCallingConvention());
+ // Empty records are ignored for parameter passing purposes.
+ if (AI.isIgnore()) {
+ uint64_t PointerSize = getTarget().getPointerWidth(LangAS::Default) / 8;
+ CharUnits SlotSize = CharUnits::fromQuantity(PointerSize);
+ VAListAddr = CGF.Builder.CreateElementBitCast(VAListAddr, CGF.Int8PtrTy);
+ auto *Load = CGF.Builder.CreateLoad(VAListAddr);
+ Address Addr = Address(Load, CGF.Int8Ty, SlotSize);
+ return CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty));
+ }
+
bool IsIndirect = AI.isIndirect();
llvm::Type *BaseTy = CGF.ConvertType(Ty);
@@ -6242,7 +6258,7 @@ Address AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty,
if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty))
return EmitVAArgInstr(CGF, VAListAddr, Ty, ABIArgInfo::getDirect());
- uint64_t PointerSize = getTarget().getPointerWidth(0) / 8;
+ uint64_t PointerSize = getTarget().getPointerWidth(LangAS::Default) / 8;
CharUnits SlotSize = CharUnits::fromQuantity(PointerSize);
// Empty records are ignored for parameter passing purposes.
@@ -6290,7 +6306,7 @@ Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
namespace {
-class ARMABIInfo : public SwiftABIInfo {
+class ARMABIInfo : public ABIInfo {
public:
enum ABIKind {
APCS = 0,
@@ -6304,8 +6320,7 @@ private:
bool IsFloatABISoftFP;
public:
- ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind)
- : SwiftABIInfo(CGT), Kind(_Kind) {
+ ARMABIInfo(CodeGenTypes &CGT, ABIKind Kind) : ABIInfo(CGT), Kind(Kind) {
setCCs();
IsFloatABISoftFP = CGT.getCodeGenOpts().FloatABI == "softfp" ||
CGT.getCodeGenOpts().FloatABI == ""; // default
@@ -6369,22 +6384,23 @@ private:
llvm::CallingConv::ID getLLVMDefaultCC() const;
llvm::CallingConv::ID getABIDefaultCC() const;
void setCCs();
+};
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
- bool isSwiftErrorInRegister() const override {
- return true;
- }
- bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy,
- unsigned elts) const override;
+class ARMSwiftABIInfo : public SwiftABIInfo {
+public:
+ explicit ARMSwiftABIInfo(CodeGenTypes &CGT)
+ : SwiftABIInfo(CGT, /*SwiftErrorInRegister=*/true) {}
+
+ bool isLegalVectorType(CharUnits VectorSize, llvm::Type *EltTy,
+ unsigned NumElts) const override;
};
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
public:
ARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K)
- : TargetCodeGenInfo(std::make_unique<ARMABIInfo>(CGT, K)) {}
+ : TargetCodeGenInfo(std::make_unique<ARMABIInfo>(CGT, K)) {
+ SwiftInfo = std::make_unique<ARMSwiftABIInfo>(CGT);
+ }
const ARMABIInfo &getABIInfo() const {
return static_cast<const ARMABIInfo&>(TargetCodeGenInfo::getABIInfo());
@@ -6422,13 +6438,13 @@ public:
auto *Fn = cast<llvm::Function>(GV);
if (const auto *TA = FD->getAttr<TargetAttr>()) {
- ParsedTargetAttr Attr = TA->parse();
+ ParsedTargetAttr Attr =
+ CGM.getTarget().parseTargetAttr(TA->getFeaturesStr());
if (!Attr.BranchProtection.empty()) {
TargetInfo::BranchProtectionInfo BPI;
StringRef DiagMsg;
- StringRef Arch = Attr.Architecture.empty()
- ? CGM.getTarget().getTargetOpts().CPU
- : Attr.Architecture;
+ StringRef Arch =
+ Attr.CPU.empty() ? CGM.getTarget().getTargetOpts().CPU : Attr.CPU;
if (!CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
Arch, BPI, DiagMsg)) {
CGM.getDiags().Report(
@@ -6451,11 +6467,11 @@ public:
// If the Branch Protection attribute is missing, validate the target
// Architecture attribute against Branch Protection command line
// settings.
- if (!CGM.getTarget().isBranchProtectionSupportedArch(Attr.Architecture))
+ if (!CGM.getTarget().isBranchProtectionSupportedArch(Attr.CPU))
CGM.getDiags().Report(
D->getLocation(),
diag::warn_target_unsupported_branch_protection_attribute)
- << Attr.Architecture;
+ << Attr.CPU;
}
}
@@ -6690,7 +6706,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
if (getABIKind() == ARMABIInfo::AAPCS_VFP ||
getABIKind() == ARMABIInfo::AAPCS) {
TyAlign = getContext().getTypeUnadjustedAlignInChars(Ty).getQuantity();
- ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8);
+ ABIAlign = std::clamp(TyAlign, (uint64_t)4, (uint64_t)8);
} else {
TyAlign = getContext().getTypeAlignInChars(Ty).getQuantity();
}
@@ -6986,16 +7002,15 @@ bool ARMABIInfo::containsAnyFP16Vectors(QualType Ty) const {
}
}
-bool ARMABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize,
- llvm::Type *eltTy,
- unsigned numElts) const {
- if (!llvm::isPowerOf2_32(numElts))
+bool ARMSwiftABIInfo::isLegalVectorType(CharUnits VectorSize, llvm::Type *EltTy,
+ unsigned NumElts) const {
+ if (!llvm::isPowerOf2_32(NumElts))
return false;
- unsigned size = getDataLayout().getTypeStoreSizeInBits(eltTy);
+ unsigned size = CGT.getDataLayout().getTypeStoreSizeInBits(EltTy);
if (size > 64)
return false;
- if (vectorSize.getQuantity() != 8 &&
- (vectorSize.getQuantity() != 16 || numElts == 1))
+ if (VectorSize.getQuantity() != 8 &&
+ (VectorSize.getQuantity() != 16 || NumElts == 1))
return false;
return true;
}
@@ -7046,10 +7061,10 @@ Address ARMABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
// Empty records are ignored for parameter passing purposes.
if (isEmptyRecord(getContext(), Ty, true)) {
- Address Addr = Address(CGF.Builder.CreateLoad(VAListAddr),
- getVAListElementType(CGF), SlotSize);
- Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty));
- return Addr;
+ VAListAddr = CGF.Builder.CreateElementBitCast(VAListAddr, CGF.Int8PtrTy);
+ auto *Load = CGF.Builder.CreateLoad(VAListAddr);
+ Address Addr = Address(Load, CGF.Int8Ty, SlotSize);
+ return CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty));
}
CharUnits TySize = getContext().getTypeSizeInChars(Ty);
@@ -7380,13 +7395,13 @@ bool NVPTXTargetCodeGenInfo::shouldEmitStaticExternCAliases() const {
namespace {
-class SystemZABIInfo : public SwiftABIInfo {
+class SystemZABIInfo : public ABIInfo {
bool HasVector;
bool IsSoftFloatABI;
public:
SystemZABIInfo(CodeGenTypes &CGT, bool HV, bool SF)
- : SwiftABIInfo(CGT), HasVector(HV), IsSoftFloatABI(SF) {}
+ : ABIInfo(CGT), HasVector(HV), IsSoftFloatABI(SF) {}
bool isPromotableIntegerTypeForABI(QualType Ty) const;
bool isCompoundType(QualType Ty) const;
@@ -7397,30 +7412,58 @@ public:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType ArgTy) const;
- void computeInfo(CGFunctionInfo &FI) const override {
- if (!getCXXABI().classifyReturnType(FI))
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
- for (auto &I : FI.arguments())
- I.info = classifyArgumentType(I.type);
- }
-
+ void computeInfo(CGFunctionInfo &FI) const override;
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override;
-
- bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> scalars,
- bool asReturnValue) const override {
- return occupiesMoreThan(CGT, scalars, /*total*/ 4);
- }
- bool isSwiftErrorInRegister() const override {
- return false;
- }
};
class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
+ // These are used for speeding up the search for a visible vector ABI.
+ mutable bool HasVisibleVecABIFlag = false;
+ mutable std::set<const Type *> SeenTypes;
+
+ // Returns true (the first time) if Ty is or found to make use of a vector
+ // type (e.g. as a function argument).
+ bool isVectorTypeBased(const Type *Ty) const;
+
public:
SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector, bool SoftFloatABI)
: TargetCodeGenInfo(
- std::make_unique<SystemZABIInfo>(CGT, HasVector, SoftFloatABI)) {}
+ std::make_unique<SystemZABIInfo>(CGT, HasVector, SoftFloatABI)) {
+ SwiftInfo =
+ std::make_unique<SwiftABIInfo>(CGT, /*SwiftErrorInRegister=*/false);
+ }
+
+ // The vector ABI is different when the vector facility is present and when
+ // a module e.g. defines an externally visible vector variable, a flag
+ // indicating a visible vector ABI is added. Eventually this will result in
+ // a GNU attribute indicating the vector ABI of the module. Ty is the type
+ // of a variable or function parameter that is globally visible.
+ void handleExternallyVisibleObjABI(const Type *Ty,
+ CodeGen::CodeGenModule &M) const {
+ if (!HasVisibleVecABIFlag && isVectorTypeBased(Ty)) {
+ M.getModule().addModuleFlag(llvm::Module::Warning,
+ "s390x-visible-vector-ABI", 1);
+ HasVisibleVecABIFlag = true;
+ }
+ }
+
+ void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &M) const override {
+ if (!D)
+ return;
+
+ // Check if the vector ABI becomes visible by an externally visible
+ // variable or function.
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->isExternallyVisible())
+ handleExternallyVisibleObjABI(VD->getType().getTypePtr(), M);
+ }
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->isExternallyVisible())
+ handleExternallyVisibleObjABI(FD->getType().getTypePtr(), M);
+ }
+ }
llvm::Value *testFPKind(llvm::Value *V, unsigned BuiltinID,
CGBuilderTy &Builder,
@@ -7579,6 +7622,9 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
// Every non-vector argument occupies 8 bytes and is passed by preference
// in either GPRs or FPRs. Vector arguments occupy 8 or 16 bytes and are
// always passed on the stack.
+ const SystemZTargetCodeGenInfo &SZCGI =
+ static_cast<const SystemZTargetCodeGenInfo &>(
+ CGT.getCGM().getTargetCodeGenInfo());
Ty = getContext().getCanonicalType(Ty);
auto TyInfo = getContext().getTypeInfoInChars(Ty);
llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty);
@@ -7589,6 +7635,7 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
bool IsVector = false;
CharUnits UnpaddedSize;
CharUnits DirectAlign;
+ SZCGI.handleExternallyVisibleObjABI(Ty.getTypePtr(), CGT.getCGM());
if (IsIndirect) {
DirectTy = llvm::PointerType::getUnqual(DirectTy);
UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8);
@@ -7783,6 +7830,51 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
return ABIArgInfo::getDirect(nullptr);
}
+void SystemZABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ const SystemZTargetCodeGenInfo &SZCGI =
+ static_cast<const SystemZTargetCodeGenInfo &>(
+ CGT.getCGM().getTargetCodeGenInfo());
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ unsigned Idx = 0;
+ for (auto &I : FI.arguments()) {
+ I.info = classifyArgumentType(I.type);
+ if (FI.isVariadic() && Idx++ >= FI.getNumRequiredArgs())
+ // Check if a vararg vector argument is passed, in which case the
+ // vector ABI becomes visible as the va_list could be passed on to
+ // other functions.
+ SZCGI.handleExternallyVisibleObjABI(I.type.getTypePtr(), CGT.getCGM());
+ }
+}
+
+bool SystemZTargetCodeGenInfo::isVectorTypeBased(const Type *Ty) const {
+ while (Ty->isPointerType() || Ty->isArrayType())
+ Ty = Ty->getPointeeOrArrayElementType();
+ if (!SeenTypes.insert(Ty).second)
+ return false;
+ if (Ty->isVectorType())
+ return true;
+ if (const auto *RecordTy = Ty->getAs<RecordType>()) {
+ const RecordDecl *RD = RecordTy->getDecl();
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ if (CXXRD->hasDefinition())
+ for (const auto &I : CXXRD->bases())
+ if (isVectorTypeBased(I.getType().getTypePtr()))
+ return true;
+ for (const auto *FD : RD->fields())
+ if (isVectorTypeBased(FD->getType().getTypePtr()))
+ return true;
+ }
+ if (const auto *FT = Ty->getAs<FunctionType>())
+ if (isVectorTypeBased(FT->getReturnType().getTypePtr()))
+ return true;
+ if (const FunctionProtoType *Proto = Ty->getAs<FunctionProtoType>())
+ for (auto ParamType : Proto->getParamTypes())
+ if (isVectorTypeBased(ParamType.getTypePtr()))
+ return true;
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// MSP430 ABI Implementation
//===----------------------------------------------------------------------===//
@@ -7867,7 +7959,7 @@ void MSP430TargetCodeGenInfo::setTargetAttributes(
namespace {
class MipsABIInfo : public ABIInfo {
bool IsO32;
- unsigned MinABIStackAlignInBytes, StackAlignInBytes;
+ const unsigned MinABIStackAlignInBytes, StackAlignInBytes;
void CoerceToIntArgs(uint64_t TySize,
SmallVectorImpl<llvm::Type *> &ArgList) const;
llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const;
@@ -8044,8 +8136,8 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
uint64_t TySize = getContext().getTypeSize(Ty);
uint64_t Align = getContext().getTypeAlign(Ty) / 8;
- Align = std::min(std::max(Align, (uint64_t)MinABIStackAlignInBytes),
- (uint64_t)StackAlignInBytes);
+ Align = std::clamp(Align, (uint64_t)MinABIStackAlignInBytes,
+ (uint64_t)StackAlignInBytes);
unsigned CurrOffset = llvm::alignTo(Offset, Align);
Offset = CurrOffset + llvm::alignTo(TySize, Align * 8) / 8;
@@ -8200,7 +8292,7 @@ Address MipsABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
// Integer arguments are promoted to 32-bit on O32 and 64-bit on N32/N64.
// Pointers are also promoted in the same way but this only matters for N32.
unsigned SlotSizeInBits = IsO32 ? 32 : 64;
- unsigned PtrWidth = getTarget().getPointerWidth(0);
+ unsigned PtrWidth = getTarget().getPointerWidth(LangAS::Default);
bool DidPromote = false;
if ((Ty->isIntegerType() &&
getContext().getIntWidth(Ty) < SlotSizeInBits) ||
@@ -8340,18 +8432,23 @@ public:
: DefaultABIInfo(CGT), ParamRegs(NPR), RetRegs(NRR) {}
ABIArgInfo classifyReturnType(QualType Ty, bool &LargeRet) const {
- if (isAggregateTypeForABI(Ty)) {
- // On AVR, a return struct with size less than or equals to 8 bytes is
- // returned directly via registers R18-R25. On AVRTiny, a return struct
- // with size less than or equals to 4 bytes is returned directly via
- // registers R22-R25.
- if (getContext().getTypeSize(Ty) <= RetRegs * 8)
- return ABIArgInfo::getDirect();
- // A return struct with larger size is returned via a stack
- // slot, along with a pointer to it as the function's implicit argument.
+ // On AVR, a return struct with size less than or equals to 8 bytes is
+ // returned directly via registers R18-R25. On AVRTiny, a return struct
+ // with size less than or equals to 4 bytes is returned directly via
+ // registers R22-R25.
+ if (isAggregateTypeForABI(Ty) &&
+ getContext().getTypeSize(Ty) <= RetRegs * 8)
+ return ABIArgInfo::getDirect();
+ // A return value (struct or scalar) with larger size is returned via a
+ // stack slot, along with a pointer as the function's implicit argument.
+ if (getContext().getTypeSize(Ty) > RetRegs * 8) {
LargeRet = true;
return getNaturalAlignIndirect(Ty);
}
+ // An i8 return value should not be extended to i16, since AVR has 8-bit
+ // registers.
+ if (Ty->isIntegralOrEnumerationType() && getContext().getTypeSize(Ty) <= 8)
+ return ABIArgInfo::getDirect();
// Otherwise we follow the default way which is compatible.
return DefaultABIInfo::classifyReturnType(Ty);
}
@@ -9445,8 +9542,12 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
const bool IsHIPKernel =
M.getLangOpts().HIP && FD && FD->hasAttr<CUDAGlobalAttr>();
+ const bool IsOpenMPkernel =
+ M.getLangOpts().OpenMPIsDevice &&
+ (F->getCallingConv() == llvm::CallingConv::AMDGPU_KERNEL);
- if (IsHIPKernel)
+ // TODO: This should be moved to language specific attributes instead.
+ if (IsHIPKernel || IsOpenMPkernel)
F->addFnAttr("uniform-work-group-size", "true");
if (M.getContext().getTargetInfo().allowAMDGPUUnsafeFPAtomics())
@@ -9747,7 +9848,7 @@ private:
// Check if Ty is a usable substitute for the coercion type.
bool isUsableType(llvm::StructType *Ty) const {
- return llvm::makeArrayRef(Elems) == Ty->elements();
+ return llvm::ArrayRef(Elems) == Ty->elements();
}
// Get the coercion type as a literal struct type.
@@ -10302,7 +10403,7 @@ bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) {
void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str,
bool IsRecursive) {
if (!ID || IncompleteUsedCount)
- return; // No key or it is is an incomplete sub-type so don't add.
+ return; // No key or it is an incomplete sub-type so don't add.
Entry &E = Map[ID];
if (IsRecursive && !E.Str.empty()) {
assert(E.State==Recursive && E.Str.size() == Str.size() &&
@@ -10907,11 +11008,6 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
}
}
- // We must track the number of GPRs used in order to conform to the RISC-V
- // ABI, as integer scalars passed in registers should have signext/zeroext
- // when promoted, but are anyext if passed on the stack. As GPR usage is
- // 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();
@@ -11001,9 +11097,22 @@ bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
// Unions aren't eligible unless they're empty (which is caught above).
if (RD->isUnion())
return false;
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ // If this is a C++ record, check the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const CXXBaseSpecifier &B : CXXRD->bases()) {
+ const auto *BDecl =
+ cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
+ CharUnits BaseOff = Layout.getBaseClassOffset(BDecl);
+ bool Ret = detectFPCCEligibleStructHelper(B.getType(), CurOff + BaseOff,
+ Field1Ty, Field1Off, Field2Ty,
+ Field2Off);
+ if (!Ret)
+ 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()) {
@@ -11090,7 +11199,7 @@ ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct(
}
CharUnits Field2Align =
- CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(Field2Ty));
+ CharUnits::fromQuantity(getDataLayout().getABITypeAlign(Field2Ty));
CharUnits Field1End = Field1Off +
CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty));
CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align);
@@ -11176,7 +11285,6 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
}
uint64_t NeededAlign = getContext().getTypeAlign(Ty);
- bool MustUseStack = false;
// Determine the number of GPRs needed to pass the current argument
// according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
// register pairs, so may consume 3 registers.
@@ -11187,7 +11295,6 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
NeededArgGPRs = 2;
if (NeededArgGPRs > ArgGPRsLeft) {
- MustUseStack = true;
NeededArgGPRs = ArgGPRsLeft;
}
@@ -11198,14 +11305,13 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
Ty = EnumTy->getDecl()->getIntegerType();
- // All integral types are promoted to XLen width, unless passed on the
- // stack.
- if (Size < XLen && Ty->isIntegralOrEnumerationType() && !MustUseStack) {
+ // All integral types are promoted to XLen width
+ if (Size < XLen && Ty->isIntegralOrEnumerationType()) {
return extendType(Ty);
}
if (const auto *EIT = Ty->getAs<BitIntType>()) {
- if (EIT->getNumBits() < XLen && !MustUseStack)
+ if (EIT->getNumBits() < XLen)
return extendType(Ty);
if (EIT->getNumBits() > 128 ||
(!getContext().getTargetInfo().hasInt128Type() &&
@@ -11522,6 +11628,524 @@ public:
} // end anonymous namespace
//===----------------------------------------------------------------------===//
+// BPF ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class BPFABIInfo : public DefaultABIInfo {
+public:
+ BPFABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
+
+ ABIArgInfo classifyArgumentType(QualType Ty) const {
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
+ if (isAggregateTypeForABI(Ty)) {
+ uint64_t Bits = getContext().getTypeSize(Ty);
+ if (Bits == 0)
+ return ABIArgInfo::getIgnore();
+
+ // If the aggregate needs 1 or 2 registers, do not use reference.
+ if (Bits <= 128) {
+ llvm::Type *CoerceTy;
+ if (Bits <= 64) {
+ CoerceTy =
+ llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8));
+ } else {
+ llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), 64);
+ CoerceTy = llvm::ArrayType::get(RegTy, 2);
+ }
+ return ABIArgInfo::getDirect(CoerceTy);
+ } else {
+ return getNaturalAlignIndirect(Ty);
+ }
+ }
+
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ ASTContext &Context = getContext();
+ if (const auto *EIT = Ty->getAs<BitIntType>())
+ if (EIT->getNumBits() > Context.getTypeSize(Context.Int128Ty))
+ return getNaturalAlignIndirect(Ty);
+
+ return (isPromotableIntegerTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty)
+ : ABIArgInfo::getDirect());
+ }
+
+ ABIArgInfo classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ if (isAggregateTypeForABI(RetTy))
+ return getNaturalAlignIndirect(RetTy);
+
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
+ RetTy = EnumTy->getDecl()->getIntegerType();
+
+ ASTContext &Context = getContext();
+ if (const auto *EIT = RetTy->getAs<BitIntType>())
+ if (EIT->getNumBits() > Context.getTypeSize(Context.Int128Ty))
+ return getNaturalAlignIndirect(RetTy);
+
+ // Caller will do necessary sign/zero extension.
+ return ABIArgInfo::getDirect();
+ }
+
+ void computeInfo(CGFunctionInfo &FI) const override {
+ FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ for (auto &I : FI.arguments())
+ I.info = classifyArgumentType(I.type);
+ }
+
+};
+
+class BPFTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ BPFTargetCodeGenInfo(CodeGenTypes &CGT)
+ : TargetCodeGenInfo(std::make_unique<BPFABIInfo>(CGT)) {}
+
+ const BPFABIInfo &getABIInfo() const {
+ return static_cast<const BPFABIInfo&>(TargetCodeGenInfo::getABIInfo());
+ }
+};
+
+}
+
+// LoongArch ABI Implementation. Documented at
+// https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
+//
+//===----------------------------------------------------------------------===//
+
+namespace {
+class LoongArchABIInfo : public DefaultABIInfo {
+private:
+ // Size of the integer ('r') registers in bits.
+ unsigned GRLen;
+ // Size of the floating point ('f') registers in bits.
+ unsigned FRLen;
+ // Number of general-purpose argument registers.
+ static const int NumGARs = 8;
+ // Number of floating-point argument registers.
+ static const int NumFARs = 8;
+ bool detectFARsEligibleStructHelper(QualType Ty, CharUnits CurOff,
+ llvm::Type *&Field1Ty,
+ CharUnits &Field1Off,
+ llvm::Type *&Field2Ty,
+ CharUnits &Field2Off) const;
+
+public:
+ LoongArchABIInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen, unsigned FRLen)
+ : DefaultABIInfo(CGT), GRLen(GRLen), FRLen(FRLen) {}
+
+ void computeInfo(CGFunctionInfo &FI) const override;
+
+ ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &GARsLeft,
+ int &FARsLeft) const;
+ ABIArgInfo classifyReturnType(QualType RetTy) const;
+
+ Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const override;
+
+ ABIArgInfo extendType(QualType Ty) const;
+
+ bool detectFARsEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
+ CharUnits &Field1Off, llvm::Type *&Field2Ty,
+ CharUnits &Field2Off, int &NeededArgGPRs,
+ int &NeededArgFPRs) const;
+ ABIArgInfo coerceAndExpandFARsEligibleStruct(llvm::Type *Field1Ty,
+ CharUnits Field1Off,
+ llvm::Type *Field2Ty,
+ CharUnits Field2Off) const;
+};
+} // end anonymous namespace
+
+void LoongArchABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ QualType RetTy = FI.getReturnType();
+ if (!getCXXABI().classifyReturnType(FI))
+ FI.getReturnInfo() = classifyReturnType(RetTy);
+
+ // IsRetIndirect is true if classifyArgumentType indicated the value should
+ // be passed indirect, or if the type size is a scalar greater than 2*GRLen
+ // and not a complex type with elements <= FRLen. e.g. fp128 is passed direct
+ // in LLVM IR, relying on the backend lowering code to rewrite the argument
+ // list and pass indirectly on LA32.
+ bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
+ if (!IsRetIndirect && RetTy->isScalarType() &&
+ getContext().getTypeSize(RetTy) > (2 * GRLen)) {
+ if (RetTy->isComplexType() && FRLen) {
+ QualType EltTy = RetTy->castAs<ComplexType>()->getElementType();
+ IsRetIndirect = getContext().getTypeSize(EltTy) > FRLen;
+ } else {
+ // This is a normal scalar > 2*GRLen, such as fp128 on LA32.
+ IsRetIndirect = true;
+ }
+ }
+
+ // We must track the number of GARs and FARs used in order to conform to the
+ // LoongArch ABI. As GAR usage is different for variadic arguments, we must
+ // also track whether we are examining a vararg or not.
+ int GARsLeft = IsRetIndirect ? NumGARs - 1 : NumGARs;
+ int FARsLeft = FRLen ? NumFARs : 0;
+ int NumFixedArgs = FI.getNumRequiredArgs();
+
+ int ArgNum = 0;
+ for (auto &ArgInfo : FI.arguments()) {
+ ArgInfo.info = classifyArgumentType(
+ ArgInfo.type, /*IsFixed=*/ArgNum < NumFixedArgs, GARsLeft, FARsLeft);
+ ArgNum++;
+ }
+}
+
+// Returns true if the struct is a potential candidate to be passed in FARs (and
+// GARs). 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 LoongArchABIInfo::detectFARsEligibleStructHelper(
+ 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 > GRLen)
+ return false;
+ // Can't be eligible if larger than the FP registers. Half precision isn't
+ // currently supported on LoongArch and the ABI hasn't been confirmed, so
+ // default to the integer ABI in that case.
+ if (IsFloat && (Size > FRLen || 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) > FRLen)
+ return false;
+ Field1Ty = CGT.ConvertType(EltTy);
+ Field1Off = CurOff;
+ 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) {
+ if (!detectFARsEligibleStructHelper(EltTy, CurOff, Field1Ty, Field1Off,
+ Field2Ty, Field2Off))
+ 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;
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ // If this is a C++ record, check the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const CXXBaseSpecifier &B : CXXRD->bases()) {
+ const auto *BDecl =
+ cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
+ if (!detectFARsEligibleStructHelper(
+ B.getType(), CurOff + Layout.getBaseClassOffset(BDecl),
+ Field1Ty, Field1Off, Field2Ty, Field2Off))
+ return false;
+ }
+ }
+ for (const FieldDecl *FD : RD->fields()) {
+ QualType QTy = FD->getType();
+ if (FD->isBitField()) {
+ unsigned BitWidth = FD->getBitWidthValue(getContext());
+ // Zero-width bitfields are ignored.
+ if (BitWidth == 0)
+ continue;
+ // Allow a bitfield with a type greater than GRLen as long as the
+ // bitwidth is GRLen or less.
+ if (getContext().getTypeSize(QTy) > GRLen && BitWidth <= GRLen) {
+ QTy = getContext().getIntTypeForBitwidth(GRLen, false);
+ }
+ }
+
+ if (!detectFARsEligibleStructHelper(
+ QTy,
+ CurOff + getContext().toCharUnitsFromBits(
+ Layout.getFieldOffset(FD->getFieldIndex())),
+ Field1Ty, Field1Off, Field2Ty, Field2Off))
+ return false;
+ }
+ return Field1Ty != nullptr;
+ }
+
+ return false;
+}
+
+// Determine if a struct is eligible to be passed in FARs (and GARs) (i.e., when
+// flattened it contains a single fp value, fp+fp, or int+fp of appropriate
+// size). If so, NeededFARs and NeededGARs are incremented appropriately.
+bool LoongArchABIInfo::detectFARsEligibleStruct(
+ QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off,
+ llvm::Type *&Field2Ty, CharUnits &Field2Off, int &NeededGARs,
+ int &NeededFARs) const {
+ Field1Ty = nullptr;
+ Field2Ty = nullptr;
+ NeededGARs = 0;
+ NeededFARs = 0;
+ if (!detectFARsEligibleStructHelper(Ty, CharUnits::Zero(), Field1Ty,
+ Field1Off, Field2Ty, Field2Off))
+ return false;
+ // Not really a candidate if we have a single int but no float.
+ if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
+ return false;
+ if (Field1Ty && Field1Ty->isFloatingPointTy())
+ NeededFARs++;
+ else if (Field1Ty)
+ NeededGARs++;
+ if (Field2Ty && Field2Ty->isFloatingPointTy())
+ NeededFARs++;
+ else if (Field2Ty)
+ NeededGARs++;
+ return true;
+}
+
+// Call getCoerceAndExpand for the two-element flattened struct described by
+// Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an
+// appropriate coerceToType and unpaddedCoerceToType.
+ABIArgInfo LoongArchABIInfo::coerceAndExpandFARsEligibleStruct(
+ 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().getABITypeAlign(Field2Ty));
+ CharUnits Field1End =
+ Field1Off +
+ CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty));
+ CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Field2Align);
+
+ CharUnits Padding = CharUnits::Zero();
+ if (Field2Off > Field2OffNoPadNoPack)
+ Padding = Field2Off - Field2OffNoPadNoPack;
+ else if (Field2Off != Field2Align && Field2Off > Field1End)
+ Padding = Field2Off - Field1End;
+
+ 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);
+
+ return ABIArgInfo::getCoerceAndExpand(
+ llvm::StructType::get(getVMContext(), CoerceElts, IsPacked),
+ llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked));
+}
+
+ABIArgInfo LoongArchABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
+ int &GARsLeft,
+ int &FARsLeft) const {
+ assert(GARsLeft <= NumGARs && "GAR tracking underflow");
+ Ty = useFirstFieldIfTransparentUnion(Ty);
+
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always passed indirectly.
+ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
+ if (GARsLeft)
+ GARsLeft -= 1;
+ return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
+ CGCXXABI::RAA_DirectInMemory);
+ }
+
+ // Ignore empty structs/unions.
+ if (isEmptyRecord(getContext(), Ty, true))
+ return ABIArgInfo::getIgnore();
+
+ uint64_t Size = getContext().getTypeSize(Ty);
+
+ // Pass floating point values via FARs if possible.
+ if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
+ FRLen >= Size && FARsLeft) {
+ FARsLeft--;
+ return ABIArgInfo::getDirect();
+ }
+
+ // Complex types for the *f or *d ABI must be passed directly rather than
+ // using CoerceAndExpand.
+ if (IsFixed && Ty->isComplexType() && FRLen && FARsLeft >= 2) {
+ QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
+ if (getContext().getTypeSize(EltTy) <= FRLen) {
+ FARsLeft -= 2;
+ return ABIArgInfo::getDirect();
+ }
+ }
+
+ if (IsFixed && FRLen && Ty->isStructureOrClassType()) {
+ llvm::Type *Field1Ty = nullptr;
+ llvm::Type *Field2Ty = nullptr;
+ CharUnits Field1Off = CharUnits::Zero();
+ CharUnits Field2Off = CharUnits::Zero();
+ int NeededGARs = 0;
+ int NeededFARs = 0;
+ bool IsCandidate = detectFARsEligibleStruct(
+ Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, NeededGARs, NeededFARs);
+ if (IsCandidate && NeededGARs <= GARsLeft && NeededFARs <= FARsLeft) {
+ GARsLeft -= NeededGARs;
+ FARsLeft -= NeededFARs;
+ return coerceAndExpandFARsEligibleStruct(Field1Ty, Field1Off, Field2Ty,
+ Field2Off);
+ }
+ }
+
+ uint64_t NeededAlign = getContext().getTypeAlign(Ty);
+ // Determine the number of GARs needed to pass the current argument
+ // according to the ABI. 2*GRLen-aligned varargs are passed in "aligned"
+ // register pairs, so may consume 3 registers.
+ int NeededGARs = 1;
+ if (!IsFixed && NeededAlign == 2 * GRLen)
+ NeededGARs = 2 + (GARsLeft % 2);
+ else if (Size > GRLen && Size <= 2 * GRLen)
+ NeededGARs = 2;
+
+ if (NeededGARs > GARsLeft)
+ NeededGARs = GARsLeft;
+
+ GARsLeft -= NeededGARs;
+
+ if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ // All integral types are promoted to GRLen width.
+ if (Size < GRLen && Ty->isIntegralOrEnumerationType())
+ return extendType(Ty);
+
+ if (const auto *EIT = Ty->getAs<BitIntType>()) {
+ if (EIT->getNumBits() < GRLen)
+ return extendType(Ty);
+ if (EIT->getNumBits() > 128 ||
+ (!getContext().getTargetInfo().hasInt128Type() &&
+ EIT->getNumBits() > 64))
+ return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
+ }
+
+ return ABIArgInfo::getDirect();
+ }
+
+ // Aggregates which are <= 2*GRLen will be passed in registers if possible,
+ // so coerce to integers.
+ if (Size <= 2 * GRLen) {
+ // Use a single GRLen int if possible, 2*GRLen if 2*GRLen alignment is
+ // required, and a 2-element GRLen array if only GRLen alignment is
+ // required.
+ if (Size <= GRLen) {
+ return ABIArgInfo::getDirect(
+ llvm::IntegerType::get(getVMContext(), GRLen));
+ }
+ if (getContext().getTypeAlign(Ty) == 2 * GRLen) {
+ return ABIArgInfo::getDirect(
+ llvm::IntegerType::get(getVMContext(), 2 * GRLen));
+ }
+ return ABIArgInfo::getDirect(
+ llvm::ArrayType::get(llvm::IntegerType::get(getVMContext(), GRLen), 2));
+ }
+ return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
+}
+
+ABIArgInfo LoongArchABIInfo::classifyReturnType(QualType RetTy) const {
+ if (RetTy->isVoidType())
+ return ABIArgInfo::getIgnore();
+ // The rules for return and argument types are the same, so defer to
+ // classifyArgumentType.
+ int GARsLeft = 2;
+ int FARsLeft = FRLen ? 2 : 0;
+ return classifyArgumentType(RetTy, /*IsFixed=*/true, GARsLeft, FARsLeft);
+}
+
+Address LoongArchABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const {
+ CharUnits SlotSize = CharUnits::fromQuantity(GRLen / 8);
+
+ // Empty records are ignored for parameter passing purposes.
+ if (isEmptyRecord(getContext(), Ty, true)) {
+ Address Addr = Address(CGF.Builder.CreateLoad(VAListAddr),
+ getVAListElementType(CGF), SlotSize);
+ Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty));
+ return Addr;
+ }
+
+ auto TInfo = getContext().getTypeInfoInChars(Ty);
+
+ // Arguments bigger than 2*GRLen bytes are passed indirectly.
+ return emitVoidPtrVAArg(CGF, VAListAddr, Ty,
+ /*IsIndirect=*/TInfo.Width > 2 * SlotSize, TInfo,
+ SlotSize,
+ /*AllowHigherAlign=*/true);
+}
+
+ABIArgInfo LoongArchABIInfo::extendType(QualType Ty) const {
+ int TySize = getContext().getTypeSize(Ty);
+ // LA64 ABI requires unsigned 32 bit integers to be sign extended.
+ if (GRLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
+ return ABIArgInfo::getSignExtend(Ty);
+ return ABIArgInfo::getExtend(Ty);
+}
+
+namespace {
+class LoongArchTargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ LoongArchTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen,
+ unsigned FRLen)
+ : TargetCodeGenInfo(
+ std::make_unique<LoongArchABIInfo>(CGT, GRLen, FRLen)) {}
+};
+} // namespace
+
+//===----------------------------------------------------------------------===//
// Driver code
//===----------------------------------------------------------------------===//
@@ -11666,7 +12290,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::riscv32:
case llvm::Triple::riscv64: {
StringRef ABIStr = getTarget().getABI();
- unsigned XLen = getTarget().getPointerWidth(0);
+ unsigned XLen = getTarget().getPointerWidth(LangAS::Default);
unsigned ABIFLen = 0;
if (ABIStr.endswith("f"))
ABIFLen = 32;
@@ -11749,6 +12373,20 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
: hasFP64 ? 64
: 32));
}
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::bpfel:
+ return SetCGInfo(new BPFTargetCodeGenInfo(Types));
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64: {
+ StringRef ABIStr = getTarget().getABI();
+ unsigned ABIFRLen = 0;
+ if (ABIStr.endswith("f"))
+ ABIFRLen = 32;
+ else if (ABIStr.endswith("d"))
+ ABIFRLen = 64;
+ return SetCGInfo(new LoongArchTargetCodeGenInfo(
+ Types, getTarget().getPointerWidth(LangAS::Default), ABIFRLen));
+ }
}
}
@@ -11835,8 +12473,8 @@ llvm::Function *AMDGPUTargetCodeGenInfo::createEnqueuedBlockKernel(
auto *Cast = Builder.CreatePointerCast(BlockPtr, InvokeFT->getParamType(0));
llvm::SmallVector<llvm::Value *, 2> Args;
Args.push_back(Cast);
- for (auto I = F->arg_begin() + 1, E = F->arg_end(); I != E; ++I)
- Args.push_back(I);
+ for (llvm::Argument &A : llvm::drop_begin(F->args()))
+ Args.push_back(&A);
llvm::CallInst *call = Builder.CreateCall(Invoke, Args);
call->setCallingConv(Invoke->getCallingConv());
Builder.CreateRetVoid();
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index 30421612015b..c7c1ec7fce7e 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -38,6 +38,7 @@ class ABIInfo;
class CallArgList;
class CodeGenFunction;
class CGBlockInfo;
+class SwiftABIInfo;
/// TargetCodeGenInfo - This class organizes various target-specific
/// codegeneration issues, like target-specific attributes, builtins and so
@@ -45,6 +46,12 @@ class CGBlockInfo;
class TargetCodeGenInfo {
std::unique_ptr<ABIInfo> Info;
+protected:
+ // Target hooks supporting Swift calling conventions. The target must
+ // initialize this field if it claims to support these calling conventions
+ // by returning true from TargetInfo::checkCallingConvention for them.
+ std::unique_ptr<SwiftABIInfo> SwiftInfo;
+
public:
TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info);
virtual ~TargetCodeGenInfo();
@@ -52,6 +59,12 @@ public:
/// getABIInfo() - Returns ABI info helper for the target.
const ABIInfo &getABIInfo() const { return *Info; }
+ /// Returns Swift ABI info helper for the target.
+ const SwiftABIInfo &getSwiftABIInfo() const {
+ assert(SwiftInfo && "Swift ABI info has not been initialized");
+ return *SwiftInfo;
+ }
+
/// setTargetAttributes - Provides a convenient hook to handle extra
/// target-specific attributes for the given global.
virtual void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
diff --git a/clang/lib/CodeGen/VarBypassDetector.cpp b/clang/lib/CodeGen/VarBypassDetector.cpp
index e8717a61ce5e..6eda83dfdef2 100644
--- a/clang/lib/CodeGen/VarBypassDetector.cpp
+++ b/clang/lib/CodeGen/VarBypassDetector.cpp
@@ -77,7 +77,7 @@ bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
return false;
++StmtsToSkip;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Stmt::GotoStmtClass:
FromScopes.push_back({S, ParentScope});
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index 8210e8d7c21b..c75b9b9c9e13 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -19,7 +19,6 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Index/USRGeneration.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/ArgList.h"
@@ -30,6 +29,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <fstream>
+#include <optional>
#include <sstream>
#include <tuple>
@@ -241,7 +241,7 @@ CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
-llvm::Optional<std::string>
+std::optional<std::string>
CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
SmallString<128> DeclUSR;
bool Ret = index::generateUSRForDecl(ND, DeclUSR);
@@ -267,7 +267,7 @@ CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
const T *ResultDecl;
if (!ND || !hasBodyOrInit(ND, ResultDecl))
continue;
- llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
+ std::optional<std::string> ResultLookupName = getLookupName(ResultDecl);
if (!ResultLookupName || *ResultLookupName != LookupName)
continue;
return ResultDecl;
@@ -283,7 +283,7 @@ llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
assert(!hasBodyOrInit(D) &&
"D has a body or init in current translation unit!");
++NumGetCTUCalled;
- const llvm::Optional<std::string> LookupName = getLookupName(D);
+ const std::optional<std::string> LookupName = getLookupName(D);
if (!LookupName)
return llvm::make_error<IndexError>(
index_error_code::failed_to_generate_usr);
@@ -458,7 +458,7 @@ CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
return llvm::make_error<IndexError>(index_error_code::missing_definition);
}
- // Search in the index for the filename where the definition of FuncitonName
+ // Search in the index for the filename where the definition of FunctionName
// resides.
if (llvm::Expected<ASTUnit *> FoundForFile =
getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
@@ -793,11 +793,11 @@ CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
return *NewImporter;
}
-llvm::Optional<clang::MacroExpansionContext>
+std::optional<clang::MacroExpansionContext>
CrossTranslationUnitContext::getMacroExpansionContextForSourceLocation(
const clang::SourceLocation &ToLoc) const {
// FIXME: Implement: Record such a context for every imported ASTUnit; lookup.
- return llvm::None;
+ return std::nullopt;
}
bool CrossTranslationUnitContext::isImportedAsNew(const Decl *ToDecl) const {
diff --git a/clang/lib/DirectoryWatcher/DirectoryScanner.cpp b/clang/lib/DirectoryWatcher/DirectoryScanner.cpp
index fc4b493e7b4c..428f87eddc7b 100644
--- a/clang/lib/DirectoryWatcher/DirectoryScanner.cpp
+++ b/clang/lib/DirectoryWatcher/DirectoryScanner.cpp
@@ -9,16 +9,17 @@
#include "DirectoryScanner.h"
#include "llvm/Support/Path.h"
+#include <optional>
namespace clang {
using namespace llvm;
-Optional<sys::fs::file_status> getFileStatus(StringRef Path) {
+std::optional<sys::fs::file_status> getFileStatus(StringRef Path) {
sys::fs::file_status Status;
std::error_code EC = status(Path, Status);
if (EC)
- return None;
+ return std::nullopt;
return Status;
}
diff --git a/clang/lib/DirectoryWatcher/DirectoryScanner.h b/clang/lib/DirectoryWatcher/DirectoryScanner.h
index feb8b4ea861e..84cffa5704f7 100644
--- a/clang/lib/DirectoryWatcher/DirectoryScanner.h
+++ b/clang/lib/DirectoryWatcher/DirectoryScanner.h
@@ -8,6 +8,7 @@
#include "clang/DirectoryWatcher/DirectoryWatcher.h"
#include "llvm/Support/FileSystem.h"
+#include <optional>
#include <string>
#include <vector>
@@ -23,7 +24,7 @@ std::vector<DirectoryWatcher::Event>
getAsFileEvents(const std::vector<std::string> &Scan);
/// Gets status of file (or directory) at \p Path.
-/// \returns llvm::None if \p Path doesn't exist or can't get the status.
-llvm::Optional<llvm::sys::fs::file_status> getFileStatus(llvm::StringRef Path);
+/// \returns std::nullopt if \p Path doesn't exist or can't get the status.
+std::optional<llvm::sys::fs::file_status> getFileStatus(llvm::StringRef Path);
} // namespace clang
diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
index 963256f268bb..9b3d2571f29f 100644
--- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
+++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
@@ -25,6 +25,7 @@
#include <vector>
#include <fcntl.h>
+#include <optional>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <unistd.h>
@@ -72,10 +73,10 @@ struct SemaphorePipe {
const int FDWrite;
bool OwnsFDs;
- static llvm::Optional<SemaphorePipe> create() {
+ static std::optional<SemaphorePipe> create() {
int InotifyPollingStopperFDs[2];
if (pipe2(InotifyPollingStopperFDs, O_CLOEXEC) == -1)
- return llvm::None;
+ return std::nullopt;
return SemaphorePipe(InotifyPollingStopperFDs);
}
};
diff --git a/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp b/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
index bdc389516289..b8788bae8171 100644
--- a/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
+++ b/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
@@ -136,7 +136,7 @@ static void eventStreamCallback(ConstFSEventStreamRef Stream,
llvm::sys::path::filename(Path));
continue;
} else if (Flags & ModifyingFileEvents) {
- if (!getFileStatus(Path).hasValue()) {
+ if (!getFileStatus(Path).has_value()) {
Events.emplace_back(DirectoryWatcher::Event::EventKind::Removed,
llvm::sys::path::filename(Path));
} else {
diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp
index ead3a23da418..44b4715503f0 100644
--- a/clang/lib/Driver/Action.cpp
+++ b/clang/lib/Driver/Action.cpp
@@ -25,7 +25,6 @@ const char *Action::getClassName(ActionClass AC) {
return "offload";
case PreprocessJobClass: return "preprocessor";
case PrecompileJobClass: return "precompiler";
- case HeaderModulePrecompileJobClass: return "header-module-precompiler";
case ExtractAPIJobClass:
return "api-extractor";
case AnalyzeJobClass: return "analyzer";
@@ -43,8 +42,6 @@ const char *Action::getClassName(ActionClass AC) {
return "clang-offload-bundler";
case OffloadUnbundlingJobClass:
return "clang-offload-unbundler";
- case OffloadWrapperJobClass:
- return "clang-offload-wrapper";
case OffloadPackagerJobClass:
return "clang-offload-packager";
case LinkerWrapperJobClass:
@@ -200,7 +197,7 @@ OffloadAction::OffloadAction(const DeviceDependences &DDeps, types::ID Ty)
auto &OTCs = DDeps.getToolChains();
// If all inputs agree on the same kind, use it also for this action.
- if (llvm::all_of(OKinds, [&](OffloadKind K) { return K == OKinds.front(); }))
+ if (llvm::all_equal(OKinds))
OffloadingDeviceKind = OKinds.front();
// If we have a single dependency, inherit the architecture from it.
@@ -224,13 +221,17 @@ OffloadAction::OffloadAction(const HostDependence &HDep,
// Add device inputs and propagate info to the device actions. Do work only if
// we have dependencies.
- for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i)
+ for (unsigned i = 0, e = DDeps.getActions().size(); i != e; ++i) {
if (auto *A = DDeps.getActions()[i]) {
getInputs().push_back(A);
A->propagateDeviceOffloadInfo(DDeps.getOffloadKinds()[i],
DDeps.getBoundArchs()[i],
DDeps.getToolChains()[i]);
+ // If this action is used to forward single dependency, set the toolchain.
+ if (DDeps.getActions().size() == 1)
+ OffloadingToolChain = DDeps.getToolChains()[i];
}
+ }
}
void OffloadAction::doOnHostDependence(const OffloadActionWorkTy &Work) const {
@@ -309,6 +310,19 @@ void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
DeviceOffloadKinds.push_back(OKind);
}
+void OffloadAction::DeviceDependences::add(Action &A, const ToolChain &TC,
+ const char *BoundArch,
+ unsigned OffloadKindMask) {
+ DeviceActions.push_back(&A);
+ DeviceToolChains.push_back(&TC);
+ DeviceBoundArchs.push_back(BoundArch);
+
+ // Add each active offloading kind from a mask.
+ for (OffloadKind OKind : {OFK_OpenMP, OFK_Cuda, OFK_HIP})
+ if (OKind & OffloadKindMask)
+ DeviceOffloadKinds.push_back(OKind);
+}
+
OffloadAction::HostDependence::HostDependence(Action &A, const ToolChain &TC,
const char *BoundArch,
const DeviceDependences &DDeps)
@@ -341,13 +355,6 @@ PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input,
assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind");
}
-void HeaderModulePrecompileJobAction::anchor() {}
-
-HeaderModulePrecompileJobAction::HeaderModulePrecompileJobAction(
- Action *Input, types::ID OutputType, const char *ModuleName)
- : PrecompileJobAction(HeaderModulePrecompileJobClass, Input, OutputType),
- ModuleName(ModuleName) {}
-
void ExtractAPIJobAction::anchor() {}
ExtractAPIJobAction::ExtractAPIJobAction(Action *Inputs, types::ID OutputType)
@@ -428,12 +435,6 @@ 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) {}
-
void OffloadPackagerJobAction::anchor() {}
OffloadPackagerJobAction::OffloadPackagerJobAction(ActionList &Inputs,
diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp
index b4367a0af81e..f6eb7f009e78 100644
--- a/clang/lib/Driver/Compilation.cpp
+++ b/clang/lib/Driver/Compilation.cpp
@@ -15,7 +15,6 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
@@ -102,7 +101,7 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
}
// Add allocated arguments to the final DAL.
- for (auto ArgPtr : AllocatedArgs)
+ for (auto *ArgPtr : AllocatedArgs)
Entry->AddSynthesizedArg(ArgPtr);
}
@@ -283,9 +282,9 @@ void Compilation::initCompilationForDiagnostics() {
options::OPT_o, options::OPT_MD, options::OPT_MMD, options::OPT_M,
options::OPT_MM, options::OPT_MF, options::OPT_MG, options::OPT_MJ,
options::OPT_MQ, options::OPT_MT, options::OPT_MV};
- for (unsigned i = 0, e = llvm::array_lengthof(OutputOpts); i != e; ++i) {
- if (TranslatedArgs->hasArg(OutputOpts[i]))
- TranslatedArgs->eraseArg(OutputOpts[i]);
+ for (const auto &Opt : OutputOpts) {
+ if (TranslatedArgs->hasArg(Opt))
+ TranslatedArgs->eraseArg(Opt);
}
TranslatedArgs->ClaimAllArgs();
@@ -297,7 +296,7 @@ void Compilation::initCompilationForDiagnostics() {
TCArgs.clear();
// Redirect stdout/stderr to /dev/null.
- Redirects = {None, {""}, {""}};
+ Redirects = {std::nullopt, {""}, {""}};
// Temporary files added by diagnostics should be kept.
ForceKeepTempFiles = true;
@@ -307,6 +306,6 @@ StringRef Compilation::getSysRoot() const {
return getDriver().SysRoot;
}
-void Compilation::Redirect(ArrayRef<Optional<StringRef>> Redirects) {
+void Compilation::Redirect(ArrayRef<std::optional<StringRef>> Redirects) {
this->Redirects = Redirects;
}
diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp
index 1898667279cc..87a0c5a58511 100644
--- a/clang/lib/Driver/Distro.cpp
+++ b/clang/lib/Driver/Distro.cpp
@@ -92,6 +92,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) {
.Case("impish", Distro::UbuntuImpish)
.Case("jammy", Distro::UbuntuJammy)
.Case("kinetic", Distro::UbuntuKinetic)
+ .Case("lunar", Distro::UbuntuLunar)
.Default(Distro::UnknownDistro);
return Version;
}
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 3f29afd35971..661d9977fbc5 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -94,8 +94,10 @@
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
+#include <cstdlib> // ::getenv
#include <map>
#include <memory>
+#include <optional>
#include <utility>
#if LLVM_ON_UNIX
#include <unistd.h> // getpid
@@ -105,8 +107,8 @@ using namespace clang::driver;
using namespace clang;
using namespace llvm::opt;
-static llvm::Optional<llvm::Triple>
-getOffloadTargetTriple(const Driver &D, const ArgList &Args) {
+static std::optional<llvm::Triple> getOffloadTargetTriple(const Driver &D,
+ const ArgList &Args) {
auto OffloadTargets = Args.getAllArgValues(options::OPT_offload_EQ);
// Offload compilation flow does not support multiple targets for now. We
// need the HIPActionBuilder (and possibly the CudaActionBuilder{,Base}too)
@@ -114,17 +116,17 @@ getOffloadTargetTriple(const Driver &D, const ArgList &Args) {
switch (OffloadTargets.size()) {
default:
D.Diag(diag::err_drv_only_one_offload_target_supported);
- return llvm::None;
+ return std::nullopt;
case 0:
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << "";
- return llvm::None;
+ return std::nullopt;
case 1:
break;
}
return llvm::Triple(OffloadTargets[0]);
}
-static llvm::Optional<llvm::Triple>
+static std::optional<llvm::Triple>
getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args,
const llvm::Triple &HostTriple) {
if (!Args.hasArg(options::OPT_offload_EQ)) {
@@ -137,19 +139,19 @@ getNVIDIAOffloadTargetTriple(const Driver &D, const ArgList &Args,
if (Args.hasArg(options::OPT_emit_llvm))
return TT;
D.Diag(diag::err_drv_cuda_offload_only_emit_bc);
- return llvm::None;
+ return std::nullopt;
}
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str();
- return llvm::None;
+ return std::nullopt;
}
-static llvm::Optional<llvm::Triple>
+static std::optional<llvm::Triple>
getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
if (!Args.hasArg(options::OPT_offload_EQ)) {
return llvm::Triple("amdgcn-amd-amdhsa"); // Default HIP triple.
}
auto TT = getOffloadTargetTriple(D, Args);
if (!TT)
- return llvm::None;
+ return std::nullopt;
if (TT->getArch() == llvm::Triple::amdgcn &&
TT->getVendor() == llvm::Triple::AMD &&
TT->getOS() == llvm::Triple::AMDHSA)
@@ -157,7 +159,7 @@ getHIPOffloadTargetTriple(const Driver &D, const ArgList &Args) {
if (TT->getArch() == llvm::Triple::spirv64)
return TT;
D.Diag(diag::err_drv_invalid_or_unsupported_offload_target) << TT->str();
- return llvm::None;
+ return std::nullopt;
}
// static
@@ -180,8 +182,8 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath,
// path of the embedding binary, which for LLVM binaries will be in bin/.
// ../lib gets us to lib/ in both cases.
P = llvm::sys::path::parent_path(Dir);
- llvm::sys::path::append(P, Twine("lib") + CLANG_LIBDIR_SUFFIX, "clang",
- CLANG_VERSION_STRING);
+ llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
+ CLANG_VERSION_MAJOR_STRING);
}
return std::string(P.str());
@@ -196,7 +198,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
ModulesModeCXX20(false), LTOMode(LTOK_None),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
DriverTitle(Title), CCCPrintBindings(false), CCPrintOptions(false),
- CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false),
+ CCLogDiagnostics(false), CCGenDiagnostics(false),
CCPrintProcessStats(false), TargetTriple(TargetTriple), Saver(Alloc),
CheckInputsExist(true), ProbePrecompiled(true),
SuppressMissingInputWarning(false) {
@@ -219,7 +221,11 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR;
#endif
#if defined(CLANG_CONFIG_FILE_USER_DIR)
- UserConfigDir = CLANG_CONFIG_FILE_USER_DIR;
+ {
+ SmallString<128> P;
+ llvm::sys::fs::expand_tilde(CLANG_CONFIG_FILE_USER_DIR, P);
+ UserConfigDir = static_cast<std::string>(P);
+ }
#endif
// Compute the path to the resource directory.
@@ -229,14 +235,14 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
void Driver::setDriverMode(StringRef Value) {
static const std::string OptName =
getOpts().getOption(options::OPT_driver_mode).getPrefixedName();
- if (auto M = llvm::StringSwitch<llvm::Optional<DriverMode>>(Value)
+ if (auto M = llvm::StringSwitch<std::optional<DriverMode>>(Value)
.Case("gcc", GCCMode)
.Case("g++", GXXMode)
.Case("cpp", CPPMode)
.Case("cl", CLMode)
.Case("flang", FlangMode)
.Case("dxc", DXCMode)
- .Default(None))
+ .Default(std::nullopt))
Mode = *M;
else
Diag(diag::err_drv_unsupported_option_argument) << OptName << Value;
@@ -305,11 +311,17 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
unsigned DiagID;
auto ArgString = A->getAsString(Args);
std::string Nearest;
- if (getOpts().findNearest(
- ArgString, Nearest, IncludedFlagsBitmask, ExcludedFlagsBitmask) > 1) {
- DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
- : diag::err_drv_unknown_argument;
- Diags.Report(DiagID) << ArgString;
+ if (getOpts().findNearest(ArgString, Nearest, IncludedFlagsBitmask,
+ ExcludedFlagsBitmask) > 1) {
+ if (!IsCLMode() &&
+ getOpts().findExact(ArgString, Nearest, options::CC1Option)) {
+ DiagID = diag::err_drv_unknown_argument_with_suggestion;
+ Diags.Report(DiagID) << ArgString << "-Xclang " + Nearest;
+ } else {
+ DiagID = IsCLMode() ? diag::warn_drv_unknown_argument_clang_cl
+ : diag::err_drv_unknown_argument;
+ Diags.Report(DiagID) << ArgString;
+ }
} else {
DiagID = IsCLMode()
? diag::warn_drv_unknown_argument_clang_cl_with_suggestion
@@ -320,6 +332,19 @@ InputArgList Driver::ParseArgStrings(ArrayRef<const char *> ArgStrings,
DiagnosticsEngine::Warning;
}
+ for (const Arg *A : Args.filtered(options::OPT_o)) {
+ if (ArgStrings[A->getIndex()] == A->getSpelling())
+ continue;
+
+ // Warn on joined arguments that are similar to a long argument.
+ std::string ArgString = ArgStrings[A->getIndex()];
+ std::string Nearest;
+ if (getOpts().findExact("-" + ArgString, Nearest, IncludedFlagsBitmask,
+ ExcludedFlagsBitmask))
+ Diags.Report(diag::warn_drv_potentially_misspelled_joined_argument)
+ << A->getAsString(Args) << Nearest;
+ }
+
return Args;
}
@@ -551,7 +576,7 @@ static llvm::Triple computeTargetTriple(const Driver &D,
// On AIX, the env OBJECT_MODE may affect the resulting arch variant.
if (Target.isOSAIX()) {
- if (Optional<std::string> ObjectModeValue =
+ if (std::optional<std::string> ObjectModeValue =
llvm::sys::Process::GetEnv("OBJECT_MODE")) {
StringRef ObjectMode = *ObjectModeValue;
llvm::Triple::ArchType AT = llvm::Triple::UnknownArch;
@@ -628,36 +653,38 @@ static llvm::Triple computeTargetTriple(const Driver &D,
// If target is MIPS adjust the target triple
// accordingly to provided ABI name.
- A = Args.getLastArg(options::OPT_mabi_EQ);
- if (A && Target.isMIPS()) {
- StringRef ABIName = A->getValue();
- if (ABIName == "32") {
- Target = Target.get32BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNUABI64 ||
- Target.getEnvironment() == llvm::Triple::GNUABIN32)
- Target.setEnvironment(llvm::Triple::GNU);
- } else if (ABIName == "n32") {
- Target = Target.get64BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNU ||
- Target.getEnvironment() == llvm::Triple::GNUABI64)
- Target.setEnvironment(llvm::Triple::GNUABIN32);
- } else if (ABIName == "64") {
- Target = Target.get64BitArchVariant();
- if (Target.getEnvironment() == llvm::Triple::GNU ||
- Target.getEnvironment() == llvm::Triple::GNUABIN32)
- Target.setEnvironment(llvm::Triple::GNUABI64);
+ if (Target.isMIPS()) {
+ if ((A = Args.getLastArg(options::OPT_mabi_EQ))) {
+ StringRef ABIName = A->getValue();
+ if (ABIName == "32") {
+ Target = Target.get32BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNUABI64 ||
+ Target.getEnvironment() == llvm::Triple::GNUABIN32)
+ Target.setEnvironment(llvm::Triple::GNU);
+ } else if (ABIName == "n32") {
+ Target = Target.get64BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNU ||
+ Target.getEnvironment() == llvm::Triple::GNUABI64)
+ Target.setEnvironment(llvm::Triple::GNUABIN32);
+ } else if (ABIName == "64") {
+ Target = Target.get64BitArchVariant();
+ if (Target.getEnvironment() == llvm::Triple::GNU ||
+ Target.getEnvironment() == llvm::Triple::GNUABIN32)
+ Target.setEnvironment(llvm::Triple::GNUABI64);
+ }
}
}
// If target is RISC-V adjust the target triple according to
// provided architecture name
- A = Args.getLastArg(options::OPT_march_EQ);
- if (A && Target.isRISCV()) {
- StringRef ArchName = A->getValue();
- if (ArchName.startswith_insensitive("rv32"))
- Target.setArch(llvm::Triple::riscv32);
- else if (ArchName.startswith_insensitive("rv64"))
- Target.setArch(llvm::Triple::riscv64);
+ if (Target.isRISCV()) {
+ if ((A = Args.getLastArg(options::OPT_march_EQ))) {
+ StringRef ArchName = A->getValue();
+ if (ArchName.startswith_insensitive("rv32"))
+ Target.setArch(llvm::Triple::riscv32);
+ else if (ArchName.startswith_insensitive("rv64"))
+ Target.setArch(llvm::Triple::riscv64);
+ }
}
return Target;
@@ -681,7 +708,7 @@ static driver::LTOKind parseLTOMode(Driver &D, const llvm::opt::ArgList &Args,
if (LTOMode == LTOK_Unknown) {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
return LTOK_None;
}
return LTOMode;
@@ -694,6 +721,17 @@ void Driver::setLTOMode(const llvm::opt::ArgList &Args) {
OffloadLTOMode = parseLTOMode(*this, Args, options::OPT_foffload_lto_EQ,
options::OPT_fno_offload_lto);
+
+ // Try to enable `-foffload-lto=full` if `-fopenmp-target-jit` is on.
+ if (Args.hasFlag(options::OPT_fopenmp_target_jit,
+ options::OPT_fno_openmp_target_jit, false)) {
+ if (Arg *A = Args.getLastArg(options::OPT_foffload_lto_EQ,
+ options::OPT_fno_offload_lto))
+ if (OffloadLTOMode != LTOK_Full)
+ Diag(diag::err_drv_incompatible_options)
+ << A->getSpelling() << "-fopenmp-target-jit";
+ OffloadLTOMode = LTOK_Full;
+ }
}
/// Compute the desired OpenMP runtime from the flags provided.
@@ -713,7 +751,7 @@ Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const {
if (RT == OMPRT_Unknown) {
if (A)
Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
else
// FIXME: We could use a nicer diagnostic here.
Diag(diag::err_drv_unsupported_opt) << "-fopenmp";
@@ -757,7 +795,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
auto &CudaTC = ToolChains[CudaTriple->str() + "/" + HostTriple.str()];
if (!CudaTC) {
CudaTC = std::make_unique<toolchains::CudaToolChain>(
- *this, *CudaTriple, *HostTC, C.getInputArgs(), OFK);
+ *this, *CudaTriple, *HostTC, C.getInputArgs());
}
C.addOffloadDeviceToolChain(CudaTC.get(), OFK);
} else if (IsHIP) {
@@ -821,9 +859,30 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
HostTC->getTriple());
// Attempt to deduce the offloading triple from the set of architectures.
- // We can only correctly deduce NVPTX / AMDGPU triples currently.
- llvm::DenseSet<StringRef> Archs =
- getOffloadArchs(C, C.getArgs(), Action::OFK_OpenMP, nullptr);
+ // We can only correctly deduce NVPTX / AMDGPU triples currently. We need
+ // to temporarily create these toolchains so that we can access tools for
+ // inferring architectures.
+ llvm::DenseSet<StringRef> Archs;
+ if (NVPTXTriple) {
+ auto TempTC = std::make_unique<toolchains::CudaToolChain>(
+ *this, *NVPTXTriple, *HostTC, C.getInputArgs());
+ for (StringRef Arch : getOffloadArchs(
+ C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true))
+ Archs.insert(Arch);
+ }
+ if (AMDTriple) {
+ auto TempTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
+ *this, *AMDTriple, *HostTC, C.getInputArgs());
+ for (StringRef Arch : getOffloadArchs(
+ C, C.getArgs(), Action::OFK_OpenMP, &*TempTC, true))
+ Archs.insert(Arch);
+ }
+ if (!AMDTriple && !NVPTXTriple) {
+ for (StringRef Arch :
+ getOffloadArchs(C, C.getArgs(), Action::OFK_OpenMP, nullptr, true))
+ Archs.insert(Arch);
+ }
+
for (StringRef Arch : Archs) {
if (NVPTXTriple && IsNVIDIAGpuArch(StringToCudaArch(
getProcessorFromTargetID(*NVPTXTriple, Arch)))) {
@@ -838,6 +897,13 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
}
}
+ // If the set is empty then we failed to find a native architecture.
+ if (Archs.empty()) {
+ Diag(clang::diag::err_drv_failed_to_deduce_target_from_arch)
+ << "native";
+ return;
+ }
+
for (const auto &TripleAndArchs : DerivedArchs)
OpenMPTriples.push_back(TripleAndArchs.first());
}
@@ -874,7 +940,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
if (!DeviceTC) {
if (TT.isNVPTX())
DeviceTC = std::make_unique<toolchains::CudaToolChain>(
- *this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP);
+ *this, TT, *HostTC, C.getInputArgs());
else if (TT.isAMDGCN())
DeviceTC = std::make_unique<toolchains::AMDGPUOpenMPToolChain>(
*this, TT, *HostTC, C.getInputArgs());
@@ -900,69 +966,78 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
//
}
-/// Looks the given directories for the specified file.
-///
-/// \param[out] FilePath File path, if the file was found.
-/// \param[in] Dirs Directories used for the search.
-/// \param[in] FileName Name of the file to search for.
-/// \return True if file was found.
-///
-/// Looks for file specified by FileName sequentially in directories specified
-/// by Dirs.
-///
-static bool searchForFile(SmallVectorImpl<char> &FilePath,
- ArrayRef<StringRef> Dirs, StringRef FileName) {
- SmallString<128> WPath;
- for (const StringRef &Dir : Dirs) {
- if (Dir.empty())
- continue;
- WPath.clear();
- llvm::sys::path::append(WPath, Dir, FileName);
- llvm::sys::path::native(WPath);
- if (llvm::sys::fs::is_regular_file(WPath)) {
- FilePath = std::move(WPath);
- return true;
- }
- }
- return false;
+static void appendOneArg(InputArgList &Args, const Arg *Opt,
+ const Arg *BaseArg) {
+ // The args for config files or /clang: flags belong to different InputArgList
+ // objects than Args. This copies an Arg from one of those other InputArgLists
+ // to the ownership of Args.
+ unsigned Index = Args.MakeIndex(Opt->getSpelling());
+ Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index),
+ Index, BaseArg);
+ Copy->getValues() = Opt->getValues();
+ if (Opt->isClaimed())
+ Copy->claim();
+ Copy->setOwnsValues(Opt->getOwnsValues());
+ Opt->setOwnsValues(false);
+ Args.append(Copy);
}
-bool Driver::readConfigFile(StringRef FileName) {
+bool Driver::readConfigFile(StringRef FileName,
+ llvm::cl::ExpansionContext &ExpCtx) {
+ // Try opening the given file.
+ auto Status = getVFS().status(FileName);
+ if (!Status) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << FileName << Status.getError().message();
+ return true;
+ }
+ if (Status->getType() != llvm::sys::fs::file_type::regular_file) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << FileName << "not a regular file";
+ return true;
+ }
+
// Try reading the given file.
SmallVector<const char *, 32> NewCfgArgs;
- if (!llvm::cl::readConfigFile(FileName, Saver, NewCfgArgs)) {
- Diag(diag::err_drv_cannot_read_config_file) << FileName;
+ if (llvm::Error Err = ExpCtx.readConfigFile(FileName, NewCfgArgs)) {
+ Diag(diag::err_drv_cannot_read_config_file)
+ << FileName << toString(std::move(Err));
return true;
}
// Read options from config file.
llvm::SmallString<128> CfgFileName(FileName);
llvm::sys::path::native(CfgFileName);
- ConfigFile = std::string(CfgFileName);
bool ContainErrors;
- CfgOptions = std::make_unique<InputArgList>(
+ std::unique_ptr<InputArgList> NewOptions = std::make_unique<InputArgList>(
ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors));
- if (ContainErrors) {
- CfgOptions.reset();
- return true;
- }
-
- if (CfgOptions->hasArg(options::OPT_config)) {
- CfgOptions.reset();
- Diag(diag::err_drv_nested_config_file);
+ if (ContainErrors)
return true;
- }
// Claim all arguments that come from a configuration file so that the driver
// does not warn on any that is unused.
- for (Arg *A : *CfgOptions)
+ for (Arg *A : *NewOptions)
A->claim();
+
+ if (!CfgOptions)
+ CfgOptions = std::move(NewOptions);
+ else {
+ // If this is a subsequent config file, append options to the previous one.
+ for (auto *Opt : *NewOptions) {
+ const Arg *BaseArg = &Opt->getBaseArg();
+ if (BaseArg == Opt)
+ BaseArg = nullptr;
+ appendOneArg(*CfgOptions, Opt, BaseArg);
+ }
+ }
+ ConfigFiles.push_back(std::string(CfgFileName));
return false;
}
-bool Driver::loadConfigFile() {
- std::string CfgFileName;
- bool FileSpecifiedExplicitly = false;
+bool Driver::loadConfigFiles() {
+ llvm::cl::ExpansionContext ExpCtx(Saver.getAllocator(),
+ llvm::cl::tokenizeConfigFile);
+ ExpCtx.setVFS(&getVFS());
// Process options that change search path for config files.
if (CLOptions) {
@@ -970,143 +1045,141 @@ bool Driver::loadConfigFile() {
SmallString<128> CfgDir;
CfgDir.append(
CLOptions->getLastArgValue(options::OPT_config_system_dir_EQ));
- if (!CfgDir.empty()) {
- if (llvm::sys::fs::make_absolute(CfgDir).value() != 0)
- SystemConfigDir.clear();
- else
- SystemConfigDir = static_cast<std::string>(CfgDir);
- }
+ if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir))
+ SystemConfigDir.clear();
+ else
+ SystemConfigDir = static_cast<std::string>(CfgDir);
}
if (CLOptions->hasArg(options::OPT_config_user_dir_EQ)) {
SmallString<128> CfgDir;
- CfgDir.append(
- CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ));
- if (!CfgDir.empty()) {
- if (llvm::sys::fs::make_absolute(CfgDir).value() != 0)
- UserConfigDir.clear();
- else
- UserConfigDir = static_cast<std::string>(CfgDir);
- }
+ llvm::sys::fs::expand_tilde(
+ CLOptions->getLastArgValue(options::OPT_config_user_dir_EQ), CfgDir);
+ if (CfgDir.empty() || getVFS().makeAbsolute(CfgDir))
+ UserConfigDir.clear();
+ else
+ UserConfigDir = static_cast<std::string>(CfgDir);
}
}
- // First try to find config file specified in command line.
- if (CLOptions) {
- std::vector<std::string> ConfigFiles =
- CLOptions->getAllArgValues(options::OPT_config);
- if (ConfigFiles.size() > 1) {
- if (!llvm::all_of(ConfigFiles, [ConfigFiles](const std::string &s) {
- return s == ConfigFiles[0];
- })) {
- Diag(diag::err_drv_duplicate_config);
- return true;
- }
- }
+ // Prepare list of directories where config file is searched for.
+ StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir};
+ ExpCtx.setSearchDirs(CfgFileSearchDirs);
- if (!ConfigFiles.empty()) {
- CfgFileName = ConfigFiles.front();
- assert(!CfgFileName.empty());
+ // First try to load configuration from the default files, return on error.
+ if (loadDefaultConfigFiles(ExpCtx))
+ return true;
+ // Then load configuration files specified explicitly.
+ SmallString<128> CfgFilePath;
+ if (CLOptions) {
+ for (auto CfgFileName : CLOptions->getAllArgValues(options::OPT_config)) {
// If argument contains directory separator, treat it as a path to
// configuration file.
if (llvm::sys::path::has_parent_path(CfgFileName)) {
- SmallString<128> CfgFilePath;
- if (llvm::sys::path::is_relative(CfgFileName))
- llvm::sys::fs::current_path(CfgFilePath);
- llvm::sys::path::append(CfgFilePath, CfgFileName);
- if (!llvm::sys::fs::is_regular_file(CfgFilePath)) {
- Diag(diag::err_drv_config_file_not_exist) << CfgFilePath;
- return true;
+ CfgFilePath.assign(CfgFileName);
+ if (llvm::sys::path::is_relative(CfgFilePath)) {
+ if (getVFS().makeAbsolute(CfgFilePath)) {
+ Diag(diag::err_drv_cannot_open_config_file)
+ << CfgFilePath << "cannot get absolute path";
+ return true;
+ }
}
- return readConfigFile(CfgFilePath);
+ } else if (!ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) {
+ // Report an error that the config file could not be found.
+ Diag(diag::err_drv_config_file_not_found) << CfgFileName;
+ for (const StringRef &SearchDir : CfgFileSearchDirs)
+ if (!SearchDir.empty())
+ Diag(diag::note_drv_config_file_searched_in) << SearchDir;
+ return true;
}
- FileSpecifiedExplicitly = true;
+ // Try to read the config file, return on error.
+ if (readConfigFile(CfgFilePath, ExpCtx))
+ return true;
}
}
- // If config file is not specified explicitly, try to deduce configuration
- // from executable name. For instance, an executable 'armv7l-clang' will
- // search for config file 'armv7l-clang.cfg'.
- if (CfgFileName.empty() && !ClangNameParts.TargetPrefix.empty())
- CfgFileName = ClangNameParts.TargetPrefix + '-' + ClangNameParts.ModeSuffix;
+ // No error occurred.
+ return false;
+}
- if (CfgFileName.empty())
+bool Driver::loadDefaultConfigFiles(llvm::cl::ExpansionContext &ExpCtx) {
+ // Disable default config if CLANG_NO_DEFAULT_CONFIG is set to a non-empty
+ // value.
+ if (const char *NoConfigEnv = ::getenv("CLANG_NO_DEFAULT_CONFIG")) {
+ if (*NoConfigEnv)
+ return false;
+ }
+ if (CLOptions && CLOptions->hasArg(options::OPT_no_default_config))
return false;
- // Determine architecture part of the file name, if it is present.
- StringRef CfgFileArch = CfgFileName;
- size_t ArchPrefixLen = CfgFileArch.find('-');
- if (ArchPrefixLen == StringRef::npos)
- ArchPrefixLen = CfgFileArch.size();
- llvm::Triple CfgTriple;
- CfgFileArch = CfgFileArch.take_front(ArchPrefixLen);
- CfgTriple = llvm::Triple(llvm::Triple::normalize(CfgFileArch));
- if (CfgTriple.getArch() == llvm::Triple::ArchType::UnknownArch)
- ArchPrefixLen = 0;
-
- if (!StringRef(CfgFileName).endswith(".cfg"))
- CfgFileName += ".cfg";
-
- // If config file starts with architecture name and command line options
- // redefine architecture (with options like -m32 -LE etc), try finding new
- // config file with that architecture.
- SmallString<128> FixedConfigFile;
- size_t FixedArchPrefixLen = 0;
- if (ArchPrefixLen) {
- // Get architecture name from config file name like 'i386.cfg' or
- // 'armv7l-clang.cfg'.
- // Check if command line options changes effective triple.
- llvm::Triple EffectiveTriple = computeTargetTriple(*this,
- CfgTriple.getTriple(), *CLOptions);
- if (CfgTriple.getArch() != EffectiveTriple.getArch()) {
- FixedConfigFile = EffectiveTriple.getArchName();
- FixedArchPrefixLen = FixedConfigFile.size();
- // Append the rest of original file name so that file name transforms
- // like: i386-clang.cfg -> x86_64-clang.cfg.
- if (ArchPrefixLen < CfgFileName.size())
- FixedConfigFile += CfgFileName.substr(ArchPrefixLen);
- }
+ std::string RealMode = getExecutableForDriverMode(Mode);
+ std::string Triple;
+
+ // If name prefix is present, no --target= override was passed via CLOptions
+ // and the name prefix is not a valid triple, force it for backwards
+ // compatibility.
+ if (!ClangNameParts.TargetPrefix.empty() &&
+ computeTargetTriple(*this, "/invalid/", *CLOptions).str() ==
+ "/invalid/") {
+ llvm::Triple PrefixTriple{ClangNameParts.TargetPrefix};
+ if (PrefixTriple.getArch() == llvm::Triple::UnknownArch ||
+ PrefixTriple.isOSUnknown())
+ Triple = PrefixTriple.str();
+ }
+
+ // Otherwise, use the real triple as used by the driver.
+ if (Triple.empty()) {
+ llvm::Triple RealTriple =
+ computeTargetTriple(*this, TargetTriple, *CLOptions);
+ Triple = RealTriple.str();
+ assert(!Triple.empty());
+ }
+
+ // Search for config files in the following order:
+ // 1. <triple>-<mode>.cfg using real driver mode
+ // (e.g. i386-pc-linux-gnu-clang++.cfg).
+ // 2. <triple>-<mode>.cfg using executable suffix
+ // (e.g. i386-pc-linux-gnu-clang-g++.cfg for *clang-g++).
+ // 3. <triple>.cfg + <mode>.cfg using real driver mode
+ // (e.g. i386-pc-linux-gnu.cfg + clang++.cfg).
+ // 4. <triple>.cfg + <mode>.cfg using executable suffix
+ // (e.g. i386-pc-linux-gnu.cfg + clang-g++.cfg for *clang-g++).
+
+ // Try loading <triple>-<mode>.cfg, and return if we find a match.
+ SmallString<128> CfgFilePath;
+ std::string CfgFileName = Triple + '-' + RealMode + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+
+ bool TryModeSuffix = !ClangNameParts.ModeSuffix.empty() &&
+ ClangNameParts.ModeSuffix != RealMode;
+ if (TryModeSuffix) {
+ CfgFileName = Triple + '-' + ClangNameParts.ModeSuffix + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+ }
+
+ // Try loading <mode>.cfg, and return if loading failed. If a matching file
+ // was not found, still proceed on to try <triple>.cfg.
+ CfgFileName = RealMode + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath)) {
+ if (readConfigFile(CfgFilePath, ExpCtx))
+ return true;
+ } else if (TryModeSuffix) {
+ CfgFileName = ClangNameParts.ModeSuffix + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath) &&
+ readConfigFile(CfgFilePath, ExpCtx))
+ return true;
}
- // Prepare list of directories where config file is searched for.
- StringRef CfgFileSearchDirs[] = {UserConfigDir, SystemConfigDir, Dir};
-
- // Try to find config file. First try file with corrected architecture.
- llvm::SmallString<128> CfgFilePath;
- if (!FixedConfigFile.empty()) {
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
- return readConfigFile(CfgFilePath);
- // If 'x86_64-clang.cfg' was not found, try 'x86_64.cfg'.
- FixedConfigFile.resize(FixedArchPrefixLen);
- FixedConfigFile.append(".cfg");
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, FixedConfigFile))
- return readConfigFile(CfgFilePath);
- }
-
- // Then try original file name.
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
- return readConfigFile(CfgFilePath);
-
- // Finally try removing driver mode part: 'x86_64-clang.cfg' -> 'x86_64.cfg'.
- if (!ClangNameParts.ModeSuffix.empty() &&
- !ClangNameParts.TargetPrefix.empty()) {
- CfgFileName.assign(ClangNameParts.TargetPrefix);
- CfgFileName.append(".cfg");
- if (searchForFile(CfgFilePath, CfgFileSearchDirs, CfgFileName))
- return readConfigFile(CfgFilePath);
- }
-
- // Report error but only if config file was specified explicitly, by option
- // --config. If it was deduced from executable name, it is not an error.
- if (FileSpecifiedExplicitly) {
- Diag(diag::err_drv_config_file_not_found) << CfgFileName;
- for (const StringRef &SearchDir : CfgFileSearchDirs)
- if (!SearchDir.empty())
- Diag(diag::note_drv_config_file_searched_in) << SearchDir;
- return true;
- }
+ // Try loading <triple>.cfg and return if we find a match.
+ CfgFileName = Triple + ".cfg";
+ if (ExpCtx.findConfigFile(CfgFileName, CfgFilePath))
+ return readConfigFile(CfgFilePath, ExpCtx);
+ // If we were unable to find a config file deduced from executable name,
+ // that is not an error.
return false;
}
@@ -1132,28 +1205,13 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// Try parsing configuration file.
if (!ContainsError)
- ContainsError = loadConfigFile();
+ ContainsError = loadConfigFiles();
bool HasConfigFile = !ContainsError && (CfgOptions.get() != nullptr);
// All arguments, from both config file and command line.
InputArgList Args = std::move(HasConfigFile ? std::move(*CfgOptions)
: std::move(*CLOptions));
- // The args for config files or /clang: flags belong to different InputArgList
- // objects than Args. This copies an Arg from one of those other InputArgLists
- // to the ownership of Args.
- auto appendOneArg = [&Args](const Arg *Opt, const Arg *BaseArg) {
- unsigned Index = Args.MakeIndex(Opt->getSpelling());
- Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index),
- Index, BaseArg);
- Copy->getValues() = Opt->getValues();
- if (Opt->isClaimed())
- Copy->claim();
- Copy->setOwnsValues(Opt->getOwnsValues());
- Opt->setOwnsValues(false);
- Args.append(Copy);
- };
-
if (HasConfigFile)
for (auto *Opt : *CLOptions) {
if (Opt->getOption().matches(options::OPT_config))
@@ -1161,7 +1219,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
const Arg *BaseArg = &Opt->getBaseArg();
if (BaseArg == Opt)
BaseArg = nullptr;
- appendOneArg(Opt, BaseArg);
+ appendOneArg(Args, Opt, BaseArg);
}
// In CL mode, look for any pass-through arguments
@@ -1180,7 +1238,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (!ContainsError)
for (auto *Opt : *CLModePassThroughOptions) {
- appendOneArg(Opt, nullptr);
+ appendOneArg(Args, Opt, nullptr);
}
}
}
@@ -1193,9 +1251,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: This stuff needs to go into the Compilation, not the driver.
bool CCCPrintPhases;
- // Silence driver warnings if requested
- Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w));
-
// -canonical-prefixes, -no-canonical-prefixes are used very early in main.
Args.ClaimAllArgs(options::OPT_canonical_prefixes);
Args.ClaimAllArgs(options::OPT_no_canonical_prefixes);
@@ -1235,6 +1290,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
T.setVendor(llvm::Triple::PC);
T.setEnvironment(llvm::Triple::MSVC);
T.setObjectFormat(llvm::Triple::COFF);
+ if (Args.hasArg(options::OPT__SLASH_arm64EC))
+ T.setArch(llvm::Triple::aarch64, llvm::Triple::AArch64SubArch_arm64ec);
TargetTriple = T.str();
} else if (IsDXCMode()) {
// Build TargetTriple from target_profile option for clang-dxc.
@@ -1260,7 +1317,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
A->claim();
PrefixDirs.push_back(A->getValue(0));
}
- if (Optional<std::string> CompilerPathValue =
+ if (std::optional<std::string> CompilerPathValue =
llvm::sys::Process::GetEnv("COMPILER_PATH")) {
StringRef CompilerPath = *CompilerPathValue;
while (!CompilerPath.empty()) {
@@ -1359,6 +1416,14 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
const ToolChain &TC = getToolChain(
*UArgs, computeTargetTriple(*this, TargetTriple, *UArgs));
+ // Report warning when arm64EC option is overridden by specified target
+ if ((TC.getTriple().getArch() != llvm::Triple::aarch64 ||
+ TC.getTriple().getSubArch() != llvm::Triple::AArch64SubArch_arm64ec) &&
+ UArgs->hasArg(options::OPT__SLASH_arm64EC)) {
+ getDiags().Report(clang::diag::warn_target_override_arm64ec)
+ << TC.getTriple().str();
+ }
+
// The compilation takes ownership of Args.
Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs,
ContainsError);
@@ -1498,6 +1563,11 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
return false;
}
+static const char BugReporMsg[] =
+ "\n********************\n\n"
+ "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
+ "Preprocessed source(s) and associated run script(s) are located at:";
+
// When clang crashes, produce diagnostic information including the fully
// preprocessed source file(s). Request that the developer attach the
// diagnostic information to a bug report.
@@ -1507,11 +1577,36 @@ void Driver::generateCompilationDiagnostics(
if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics))
return;
- // Don't try to generate diagnostics for link or dsymutil jobs.
- if (FailingCommand.getCreator().isLinkJob() ||
- FailingCommand.getCreator().isDsymutilJob())
+ unsigned Level = 1;
+ if (Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_EQ)) {
+ Level = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("off", 0)
+ .Case("compiler", 1)
+ .Case("all", 2)
+ .Default(1);
+ }
+ if (!Level)
+ return;
+
+ // Don't try to generate diagnostics for dsymutil jobs.
+ if (FailingCommand.getCreator().isDsymutilJob())
return;
+ bool IsLLD = false;
+ ArgStringList SavedTemps;
+ if (FailingCommand.getCreator().isLinkJob()) {
+ C.getDefaultToolChain().GetLinkerPath(&IsLLD);
+ if (!IsLLD || Level < 2)
+ return;
+
+ // If lld crashed, we will re-run the same command with the input it used
+ // to have. In that case we should not remove temp files in
+ // initCompilationForDiagnostics yet. They will be added back and removed
+ // later.
+ SavedTemps = std::move(C.getTempFiles());
+ assert(!C.getTempFiles().size());
+ }
+
// Print the version of the compiler.
PrintVersion(C, llvm::errs());
@@ -1528,6 +1623,29 @@ void Driver::generateCompilationDiagnostics(
// Suppress tool output.
C.initCompilationForDiagnostics();
+ // If lld failed, rerun it again with --reproduce.
+ if (IsLLD) {
+ const char *TmpName = CreateTempFile(C, "linker-crash", "tar");
+ Command NewLLDInvocation = Cmd;
+ llvm::opt::ArgStringList ArgList = NewLLDInvocation.getArguments();
+ StringRef ReproduceOption =
+ C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment()
+ ? "/reproduce:"
+ : "--reproduce=";
+ ArgList.push_back(Saver.save(Twine(ReproduceOption) + TmpName).data());
+ NewLLDInvocation.replaceArguments(std::move(ArgList));
+
+ // Redirect stdout/stderr to /dev/null.
+ NewLLDInvocation.Execute({std::nullopt, {""}, {""}}, nullptr, nullptr);
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg;
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << TmpName;
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "\n\n********************";
+ if (Report)
+ Report->TemporaryFiles.push_back(TmpName);
+ return;
+ }
+
// Construct the list of inputs.
InputList Inputs;
BuildInputs(C.getDefaultToolChain(), C.getArgs(), Inputs);
@@ -1612,10 +1730,7 @@ void Driver::generateCompilationDiagnostics(
return;
}
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "\n********************\n\n"
- "PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
- "Preprocessed source(s) and associated run script(s) are located at:";
+ Diag(clang::diag::note_drv_command_failed_diag_msg) << BugReporMsg;
SmallString<128> VFS;
SmallString<128> ReproCrashFilename;
@@ -1635,6 +1750,9 @@ void Driver::generateCompilationDiagnostics(
}
}
+ for (const char *TempFile : SavedTemps)
+ C.addTempFile(TempFile);
+
// Assume associated files are based off of the first temporary file.
CrashReportInfo CrashInfo(TempFiles[0], VFS);
@@ -1830,8 +1948,8 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
// Print out the install directory.
OS << "InstalledDir: " << InstalledDir << '\n';
- // If configuration file was used, print its path.
- if (!ConfigFile.empty())
+ // If configuration files were used, print their paths.
+ for (auto ConfigFile : ConfigFiles)
OS << "Configuration file: " << ConfigFile << '\n';
}
@@ -2114,12 +2232,6 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return false;
}
- if (C.getArgs().hasArg(options::OPT_print_multiarch)) {
- llvm::outs() << TC.getMultiarchTriple(*this, TC.getTriple(), SysRoot)
- << "\n";
- return false;
- }
-
if (C.getArgs().hasArg(options::OPT_print_targets)) {
llvm::TargetRegistry::printRegisteredTargetsForVersion(llvm::outs());
return false;
@@ -2371,7 +2483,7 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
// they can be influenced by linker flags the clang driver might not
// understand.
// Examples:
- // - `clang-cl main.cc ole32.lib` in a a non-MSVC shell will make the driver
+ // - `clang-cl main.cc ole32.lib` in a non-MSVC shell will make the driver
// module look for an MSVC installation in the registry. (We could ask
// the MSVCToolChain object if it can find `ole32.lib`, but the logic to
// look in the registry might move into lld-link in the future so that
@@ -2694,7 +2806,7 @@ class OffloadingActionBuilder final {
/// Update the state to include the provided host action \a HostAction as a
/// dependency of the current device action. By default it is inactive.
- virtual ActionBuilderReturnCode addDeviceDepences(Action *HostAction) {
+ virtual ActionBuilderReturnCode addDeviceDependences(Action *HostAction) {
return ABRT_Inactive;
}
@@ -2782,7 +2894,7 @@ class OffloadingActionBuilder final {
Action::OffloadKind OFKind)
: DeviceActionBuilder(C, Args, Inputs, OFKind) {}
- ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override {
+ ActionBuilderReturnCode addDeviceDependences(Action *HostAction) override {
// While generating code for CUDA, we only depend on the host input action
// to trigger the creation of all the CUDA device actions.
@@ -2856,12 +2968,16 @@ class OffloadingActionBuilder final {
std::string FileName = IA->getInputArg().getAsString(Args);
// Check if the type of the file is the same as the action. Do not
// unbundle it if it is not. Do not unbundle .so files, for example,
- // which are not object files.
+ // which are not object files. Files with extension ".lib" is classified
+ // as TY_Object but they are actually archives, therefore should not be
+ // unbundled here as objects. They will be handled at other places.
+ const StringRef LibFileExt = ".lib";
if (IA->getType() == types::TY_Object &&
(!llvm::sys::path::has_extension(FileName) ||
types::lookupTypeForExtension(
llvm::sys::path::extension(FileName).drop_front()) !=
- types::TY_Object))
+ types::TY_Object ||
+ llvm::sys::path::extension(FileName) == LibFileExt))
return ABRT_Inactive;
for (auto Arch : GpuArchList) {
@@ -2912,7 +3028,7 @@ class OffloadingActionBuilder final {
/// option is invalid.
virtual StringRef getCanonicalOffloadArch(StringRef Arch) = 0;
- virtual llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ virtual std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(const std::set<StringRef> &GpuArchs) = 0;
bool initialize() override {
@@ -2990,6 +3106,19 @@ class OffloadingActionBuilder final {
if (A->getOption().matches(options::OPT_no_offload_arch_EQ) &&
ArchStr == "all") {
GpuArchs.clear();
+ } else if (ArchStr == "native") {
+ const ToolChain &TC = *ToolChains.front();
+ auto GPUsOrErr = ToolChains.front()->getSystemGPUArchs(Args);
+ if (!GPUsOrErr) {
+ TC.getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(TC.getArch())
+ << llvm::toString(GPUsOrErr.takeError()) << "--offload-arch";
+ continue;
+ }
+
+ for (auto GPU : *GPUsOrErr) {
+ GpuArchs.insert(Args.MakeArgString(GPU));
+ }
} else {
ArchStr = getCanonicalOffloadArch(ArchStr);
if (ArchStr.empty()) {
@@ -3049,10 +3178,10 @@ class OffloadingActionBuilder final {
return CudaArchToString(Arch);
}
- llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(
const std::set<StringRef> &GpuArchs) override {
- return llvm::None;
+ return std::nullopt;
}
ActionBuilderReturnCode
@@ -3168,13 +3297,13 @@ class OffloadingActionBuilder final {
// Bundle code objects except --no-gpu-output is specified for device
// only compilation. Bundle other type of output files only if
// --gpu-bundle-output is specified for device only compilation.
- Optional<bool> BundleOutput;
+ std::optional<bool> BundleOutput;
public:
HIPActionBuilder(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs)
: CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {
- DefaultCudaArch = CudaArch::GFX803;
+ DefaultCudaArch = CudaArch::GFX906;
if (Args.hasArg(options::OPT_gpu_bundle_output,
options::OPT_no_gpu_bundle_output))
BundleOutput = Args.hasFlag(options::OPT_gpu_bundle_output,
@@ -3199,7 +3328,7 @@ class OffloadingActionBuilder final {
return Args.MakeArgStringRef(CanId);
};
- llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+ std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(
const std::set<StringRef> &GpuArchs) override {
return getConflictTargetIDCombination(GpuArchs);
@@ -3326,7 +3455,7 @@ class OffloadingActionBuilder final {
AssociatedOffloadKind);
if (CompileDeviceOnly && CurPhase == FinalPhase && BundleOutput &&
- BundleOutput.value()) {
+ *BundleOutput) {
for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) {
OffloadAction::DeviceDependences DDep;
DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I],
@@ -3401,178 +3530,6 @@ class OffloadingActionBuilder final {
void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {}
};
- /// OpenMP action builder. The host bitcode is passed to the device frontend
- /// and all the device linked images are passed to the host link phase.
- class OpenMPActionBuilder final : public DeviceActionBuilder {
- /// The OpenMP actions for the current input.
- ActionList OpenMPDeviceActions;
-
- /// The linker inputs obtained for each toolchain.
- SmallVector<ActionList, 8> DeviceLinkerInputs;
-
- public:
- OpenMPActionBuilder(Compilation &C, DerivedArgList &Args,
- const Driver::InputList &Inputs)
- : DeviceActionBuilder(C, Args, Inputs, Action::OFK_OpenMP) {}
-
- ActionBuilderReturnCode
- getDeviceDependences(OffloadAction::DeviceDependences &DA,
- phases::ID CurPhase, phases::ID FinalPhase,
- PhasesTy &Phases) override {
- if (OpenMPDeviceActions.empty())
- return ABRT_Inactive;
-
- // We should always have an action for each input.
- assert(OpenMPDeviceActions.size() == ToolChains.size() &&
- "Number of OpenMP actions and toolchains do not match.");
-
- // The host only depends on device action in the linking phase, when all
- // the device images have to be embedded in the host image.
- if (CurPhase == phases::Link) {
- assert(ToolChains.size() == DeviceLinkerInputs.size() &&
- "Toolchains and linker inputs sizes do not match.");
- auto LI = DeviceLinkerInputs.begin();
- for (auto *A : OpenMPDeviceActions) {
- LI->push_back(A);
- ++LI;
- }
-
- // We passed the device action as a host dependence, so we don't need to
- // do anything else with them.
- OpenMPDeviceActions.clear();
- return ABRT_Success;
- }
-
- // By default, we produce an action for each device arch.
- for (Action *&A : OpenMPDeviceActions)
- A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A);
-
- return ABRT_Success;
- }
-
- ActionBuilderReturnCode addDeviceDepences(Action *HostAction) override {
-
- // If this is an input action replicate it for each OpenMP toolchain.
- if (auto *IA = dyn_cast<InputAction>(HostAction)) {
- OpenMPDeviceActions.clear();
- for (unsigned I = 0; I < ToolChains.size(); ++I)
- OpenMPDeviceActions.push_back(
- C.MakeAction<InputAction>(IA->getInputArg(), IA->getType()));
- return ABRT_Success;
- }
-
- // If this is an unbundling action use it as is for each OpenMP toolchain.
- if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction)) {
- OpenMPDeviceActions.clear();
- auto *IA = cast<InputAction>(UA->getInputs().back());
- std::string FileName = IA->getInputArg().getAsString(Args);
- // Check if the type of the file is the same as the action. Do not
- // unbundle it if it is not. Do not unbundle .so files, for example,
- // which are not object files.
- if (IA->getType() == types::TY_Object &&
- (!llvm::sys::path::has_extension(FileName) ||
- types::lookupTypeForExtension(
- llvm::sys::path::extension(FileName).drop_front()) !=
- types::TY_Object))
- return ABRT_Inactive;
- for (unsigned I = 0; I < ToolChains.size(); ++I) {
- OpenMPDeviceActions.push_back(UA);
- UA->registerDependentActionInfo(
- ToolChains[I], /*BoundArch=*/StringRef(), Action::OFK_OpenMP);
- }
- return ABRT_Success;
- }
-
- // When generating code for OpenMP we use the host compile phase result as
- // a dependence to the device compile phase so that it can learn what
- // declarations should be emitted. However, this is not the only use for
- // the host action, so we prevent it from being collapsed.
- if (isa<CompileJobAction>(HostAction)) {
- HostAction->setCannotBeCollapsedWithNextDependentAction();
- assert(ToolChains.size() == OpenMPDeviceActions.size() &&
- "Toolchains and device action sizes do not match.");
- OffloadAction::HostDependence HDep(
- *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- auto TC = ToolChains.begin();
- for (Action *&A : OpenMPDeviceActions) {
- assert(isa<CompileJobAction>(A));
- OffloadAction::DeviceDependences DDep;
- DDep.add(*A, **TC, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- A = C.MakeAction<OffloadAction>(HDep, DDep);
- ++TC;
- }
- }
- return ABRT_Success;
- }
-
- void appendTopLevelActions(ActionList &AL) override {
- if (OpenMPDeviceActions.empty())
- return;
-
- // We should always have an action for each input.
- assert(OpenMPDeviceActions.size() == ToolChains.size() &&
- "Number of OpenMP actions and toolchains do not match.");
-
- // Append all device actions followed by the proper offload action.
- auto TI = ToolChains.begin();
- for (auto *A : OpenMPDeviceActions) {
- OffloadAction::DeviceDependences Dep;
- Dep.add(*A, **TI, /*BoundArch=*/nullptr, Action::OFK_OpenMP);
- AL.push_back(C.MakeAction<OffloadAction>(Dep, A->getType()));
- ++TI;
- }
- // We no longer need the action stored in this builder.
- OpenMPDeviceActions.clear();
- }
-
- void appendLinkDeviceActions(ActionList &AL) override {
- assert(ToolChains.size() == DeviceLinkerInputs.size() &&
- "Toolchains and linker inputs sizes do not match.");
-
- // Append a new link action for each device.
- auto TC = ToolChains.begin();
- for (auto &LI : DeviceLinkerInputs) {
- auto *DeviceLinkAction =
- C.MakeAction<LinkJobAction>(LI, types::TY_Image);
- OffloadAction::DeviceDependences DeviceLinkDeps;
- DeviceLinkDeps.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr,
- Action::OFK_OpenMP);
- AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps,
- DeviceLinkAction->getType()));
- ++TC;
- }
- DeviceLinkerInputs.clear();
- }
-
- Action* appendLinkHostActions(ActionList &AL) override {
- // 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>(AL, types::TY_LLVM_BC);
- auto *ASM = C.MakeAction<BackendJobAction>(BC, types::TY_PP_Asm);
- return C.MakeAction<AssembleJobAction>(ASM, types::TY_Object);
- }
-
- 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.
- auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>();
- for (auto TI = OpenMPTCRange.first, TE = OpenMPTCRange.second; TI != TE;
- ++TI)
- ToolChains.push_back(TI->second);
-
- DeviceLinkerInputs.resize(ToolChains.size());
- return false;
- }
-
- bool canUseBundlerUnbundler() const override {
- // OpenMP should use bundled files whenever possible.
- return true;
- }
- };
-
///
/// TODO: Add the implementation for other specialized builders here.
///
@@ -3597,9 +3554,6 @@ public:
// Create a specialized builder for HIP.
SpecializedBuilders.push_back(new HIPActionBuilder(C, Args, Inputs));
- // Create a specialized builder for OpenMP.
- SpecializedBuilders.push_back(new OpenMPActionBuilder(C, Args, Inputs));
-
//
// TODO: Build other specialized builders here.
//
@@ -3736,7 +3690,7 @@ public:
if (!SB->isValid())
continue;
- auto RetCode = SB->addDeviceDepences(HostAction);
+ auto RetCode = SB->addDeviceDependences(HostAction);
// Host dependences for device actions are not compatible with that same
// action being ignored.
@@ -3858,7 +3812,7 @@ public:
/*BoundArch=*/nullptr);
// Propagate active offloading kinds for each input to the link action.
// Each input may have different active offloading kind.
- for (auto A : HostAction->inputs()) {
+ for (auto *A : HostAction->inputs()) {
auto ArgLoc = HostActionToInputArgMap.find(A);
if (ArgLoc == HostActionToInputArgMap.end())
continue;
@@ -4006,11 +3960,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
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();
@@ -4046,18 +3995,18 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
handleArguments(C, Args, Inputs, Actions);
- // Builder to be used to build offloading actions.
- OffloadingActionBuilder OffloadBuilder(C, Args, Inputs);
-
bool UseNewOffloadingDriver =
- (C.isOffloadingHostKind(Action::OFK_OpenMP) &&
- Args.hasFlag(options::OPT_fopenmp_new_driver,
- options::OPT_no_offload_new_driver, true)) ||
+ C.isOffloadingHostKind(Action::OFK_OpenMP) ||
Args.hasFlag(options::OPT_offload_new_driver,
options::OPT_no_offload_new_driver, false);
+ // Builder to be used to build offloading actions.
+ std::unique_ptr<OffloadingActionBuilder> OffloadBuilder =
+ !UseNewOffloadingDriver
+ ? std::make_unique<OffloadingActionBuilder>(C, Args, Inputs)
+ : nullptr;
+
// Construct the actions to perform.
- HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr;
ExtractAPIJobAction *ExtractAPIAction = nullptr;
ActionList LinkerInputs;
ActionList MergerInputs;
@@ -4078,14 +4027,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Use the current host action in any of the offloading actions, if
// required.
if (!UseNewOffloadingDriver)
- if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg))
+ if (OffloadBuilder->addHostDependenceToDeviceActions(Current, InputArg))
break;
for (phases::ID Phase : PL) {
// Add any offload action the host action depends on.
if (!UseNewOffloadingDriver)
- Current = OffloadBuilder.addDeviceDependencesToHostAction(
+ Current = OffloadBuilder->addDeviceDependencesToHostAction(
Current, InputArg, Phase, PL.back(), FullPL);
if (!Current)
break;
@@ -4112,16 +4061,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
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.
- if (Phase == phases::Precompile && HeaderModuleAction &&
- getPrecompiledType(InputType) == types::TY_PCH) {
- HeaderModuleAction->addModuleHeaderInput(Current);
- Current = nullptr;
- break;
- }
-
if (Phase == phases::Precompile && ExtractAPIAction) {
ExtractAPIAction->addHeaderInput(Current);
Current = nullptr;
@@ -4138,9 +4077,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
if (NewCurrent == Current)
continue;
- if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent))
- HeaderModuleAction = HMA;
- else if (auto *EAA = dyn_cast<ExtractAPIJobAction>(NewCurrent))
+ if (auto *EAA = dyn_cast<ExtractAPIJobAction>(NewCurrent))
ExtractAPIAction = EAA;
Current = NewCurrent;
@@ -4148,7 +4085,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Use the current host action in any of the offloading actions, if
// required.
if (!UseNewOffloadingDriver)
- if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg))
+ if (OffloadBuilder->addHostDependenceToDeviceActions(Current, InputArg))
break;
// Try to build the offloading actions and add the result as a dependency
@@ -4166,7 +4103,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Add any top level actions generated for offloading.
if (!UseNewOffloadingDriver)
- OffloadBuilder.appendTopLevelActions(Actions, Current, InputArg);
+ OffloadBuilder->appendTopLevelActions(Actions, Current, InputArg);
else if (Current)
Current->propagateHostOffloadInfo(C.getActiveOffloadKinds(),
/*BoundArch=*/nullptr);
@@ -4178,12 +4115,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Arg *FinalPhaseArg;
if (getFinalPhase(Args, &FinalPhaseArg) == phases::Link)
if (!UseNewOffloadingDriver)
- OffloadBuilder.appendDeviceLinkActions(Actions);
+ OffloadBuilder->appendDeviceLinkActions(Actions);
}
if (!LinkerInputs.empty()) {
if (!UseNewOffloadingDriver)
- if (Action *Wrapper = OffloadBuilder.makeHostLinkAction())
+ if (Action *Wrapper = OffloadBuilder->makeHostLinkAction())
LinkerInputs.push_back(Wrapper);
Action *LA;
// Check if this Linker Job should emit a static library.
@@ -4198,7 +4135,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image);
}
if (!UseNewOffloadingDriver)
- LA = OffloadBuilder.processHostLinkAction(LA);
+ LA = OffloadBuilder->processHostLinkAction(LA);
Actions.push_back(LA);
}
@@ -4284,16 +4221,17 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
static StringRef getCanonicalArchString(Compilation &C,
const llvm::opt::DerivedArgList &Args,
StringRef ArchStr,
- const llvm::Triple &Triple) {
+ const llvm::Triple &Triple,
+ bool SuppressError = false) {
// Lookup the CUDA / HIP architecture string. Only report an error if we were
// expecting the triple to be only NVPTX / AMDGPU.
CudaArch Arch = StringToCudaArch(getProcessorFromTargetID(Triple, ArchStr));
- if (Triple.isNVPTX() &&
+ if (!SuppressError && Triple.isNVPTX() &&
(Arch == CudaArch::UNKNOWN || !IsNVIDIAGpuArch(Arch))) {
C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
<< "CUDA" << ArchStr;
return StringRef();
- } else if (Triple.isAMDGPU() &&
+ } else if (!SuppressError && Triple.isAMDGPU() &&
(Arch == CudaArch::UNKNOWN || !IsAMDGpuArch(Arch))) {
C.getDriver().Diag(clang::diag::err_drv_offload_bad_gpu_arch)
<< "HIP" << ArchStr;
@@ -4323,11 +4261,11 @@ static StringRef getCanonicalArchString(Compilation &C,
/// Checks if the set offloading architectures does not conflict. Returns the
/// incompatible pair if a conflict occurs.
-static llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>>
+static std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictOffloadArchCombination(const llvm::DenseSet<StringRef> &Archs,
Action::OffloadKind Kind) {
if (Kind != Action::OFK_HIP)
- return None;
+ return std::nullopt;
std::set<StringRef> ArchSet;
llvm::copy(Archs, std::inserter(ArchSet, ArchSet.begin()));
@@ -4336,7 +4274,8 @@ getConflictOffloadArchCombination(const llvm::DenseSet<StringRef> &Archs,
llvm::DenseSet<StringRef>
Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
- Action::OffloadKind Kind, const ToolChain *TC) const {
+ Action::OffloadKind Kind, const ToolChain *TC,
+ bool SuppressError) const {
if (!TC)
TC = &C.getDefaultToolChain();
@@ -4366,15 +4305,46 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
Arg = ExtractedArg.get();
}
+ // Add or remove the seen architectures in order of appearance. If an
+ // invalid architecture is given we simply exit.
if (Arg->getOption().matches(options::OPT_offload_arch_EQ)) {
- for (StringRef Arch : llvm::split(Arg->getValue(), ","))
- Archs.insert(getCanonicalArchString(C, Args, Arch, TC->getTriple()));
+ for (StringRef Arch : llvm::split(Arg->getValue(), ",")) {
+ if (Arch == "native" || Arch.empty()) {
+ auto GPUsOrErr = TC->getSystemGPUArchs(Args);
+ if (!GPUsOrErr) {
+ if (SuppressError)
+ llvm::consumeError(GPUsOrErr.takeError());
+ else
+ TC->getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(TC->getArch())
+ << llvm::toString(GPUsOrErr.takeError()) << "--offload-arch";
+ continue;
+ }
+
+ for (auto ArchStr : *GPUsOrErr) {
+ Archs.insert(
+ getCanonicalArchString(C, Args, Args.MakeArgString(ArchStr),
+ TC->getTriple(), SuppressError));
+ }
+ } else {
+ StringRef ArchStr = getCanonicalArchString(
+ C, Args, Arch, TC->getTriple(), SuppressError);
+ if (ArchStr.empty())
+ return Archs;
+ Archs.insert(ArchStr);
+ }
+ }
} else if (Arg->getOption().matches(options::OPT_no_offload_arch_EQ)) {
for (StringRef Arch : llvm::split(Arg->getValue(), ",")) {
- if (Arch == StringRef("all"))
+ if (Arch == "all") {
Archs.clear();
- else
- Archs.erase(getCanonicalArchString(C, Args, Arch, TC->getTriple()));
+ } else {
+ StringRef ArchStr = getCanonicalArchString(
+ C, Args, Arch, TC->getTriple(), SuppressError);
+ if (ArchStr.empty())
+ return Archs;
+ Archs.erase(ArchStr);
+ }
}
}
}
@@ -4385,6 +4355,10 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
C.setContainsError();
}
+ // Skip filling defaults if we're just querying what is availible.
+ if (SuppressError)
+ return Archs;
+
if (Archs.empty()) {
if (Kind == Action::OFK_Cuda)
Archs.insert(CudaArchToString(CudaArch::CudaDefault));
@@ -4459,10 +4433,17 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
auto TCAndArch = TCAndArchs.begin();
for (Action *&A : DeviceActions) {
+ if (A->getType() == types::TY_Nothing)
+ continue;
+
+ // Propagate the ToolChain so we can use it in ConstructPhaseAction.
+ A->propagateDeviceOffloadInfo(Kind, TCAndArch->second.data(),
+ TCAndArch->first);
A = ConstructPhaseAction(C, Args, Phase, A, Kind);
if (isa<CompileJobAction>(A) && isa<CompileJobAction>(HostAction) &&
- Kind == Action::OFK_OpenMP) {
+ Kind == Action::OFK_OpenMP &&
+ HostAction->getType() != types::TY_Nothing) {
// OpenMP offloading has a dependency on the host compile action to
// identify which declarations need to be emitted. This shouldn't be
// collapsed with any other actions so we can use it in the device.
@@ -4474,13 +4455,16 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
DDep.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind);
A = C.MakeAction<OffloadAction>(HDep, DDep);
}
+
++TCAndArch;
}
}
// Compiling HIP in non-RDC mode requires linking each action individually.
for (Action *&A : DeviceActions) {
- if (A->getType() != types::TY_Object || Kind != Action::OFK_HIP ||
+ if ((A->getType() != types::TY_Object &&
+ A->getType() != types::TY_LTO_BC) ||
+ Kind != Action::OFK_HIP ||
Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
continue;
ActionList LinkerInput = {A};
@@ -4527,14 +4511,18 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
Action *PackagerAction =
C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image);
DDep.add(*PackagerAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- nullptr, Action::OFK_None);
+ nullptr, C.getActiveOffloadKinds());
}
+ // If we are unable to embed a single device output into the host, we need to
+ // add each device output as a host dependency to ensure they are still built.
+ bool SingleDeviceOutput = !llvm::any_of(OffloadActions, [](Action *A) {
+ return A->getType() == types::TY_Nothing;
+ }) && isa<CompileJobAction>(HostAction);
OffloadAction::HostDependence HDep(
*HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
- /*BoundArch=*/nullptr, isa<CompileJobAction>(HostAction) ? DDep : DDeps);
- return C.MakeAction<OffloadAction>(
- HDep, isa<CompileJobAction>(HostAction) ? DDep : DDeps);
+ /*BoundArch=*/nullptr, SingleDeviceOutput ? DDep : DDeps);
+ return C.MakeAction<OffloadAction>(HDep, SingleDeviceOutput ? DDep : DDeps);
}
Action *Driver::ConstructPhaseAction(
@@ -4602,9 +4590,6 @@ Action *Driver::ConstructPhaseAction(
OutputTy = types::TY_Nothing;
}
- if (ModName)
- return C.MakeAction<HeaderModulePrecompileJobAction>(Input, OutputTy,
- ModName);
return C.MakeAction<PrecompileJobAction>(Input, OutputTy);
}
case phases::Compile: {
@@ -4642,11 +4627,21 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<BackendJobAction>(Input, Output);
}
if (Args.hasArg(options::OPT_emit_llvm) ||
- (TargetDeviceOffloadKind == Action::OFK_HIP &&
- Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
- false))) {
+ (((Input->getOffloadingToolChain() &&
+ Input->getOffloadingToolChain()->getTriple().isAMDGPU()) ||
+ TargetDeviceOffloadKind == Action::OFK_HIP) &&
+ (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ false) ||
+ TargetDeviceOffloadKind == Action::OFK_OpenMP))) {
types::ID Output =
- Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
+ Args.hasArg(options::OPT_S) &&
+ (TargetDeviceOffloadKind == Action::OFK_None ||
+ offloadDeviceOnly() ||
+ (TargetDeviceOffloadKind == Action::OFK_HIP &&
+ !Args.hasFlag(options::OPT_offload_new_driver,
+ options::OPT_no_offload_new_driver, false)))
+ ? types::TY_LLVM_IR
+ : types::TY_LLVM_BC;
return C.MakeAction<BackendJobAction>(Input, Output);
}
return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm);
@@ -4676,10 +4671,14 @@ void Driver::BuildJobs(Compilation &C) const {
// we are also generating .o files. So we allow more than one output file in
// this case as well.
//
+ // OffloadClass of type TY_Nothing: device-only output will place many outputs
+ // into a single offloading action. We should count all inputs to the action
+ // as outputs. Also ignore device-only outputs if we're compiling with
+ // -fsyntax-only.
if (FinalOutput) {
unsigned NumOutputs = 0;
unsigned NumIfsOutputs = 0;
- for (const Action *A : C.getActions())
+ for (const Action *A : C.getActions()) {
if (A->getType() != types::TY_Nothing &&
!(A->getKind() == Action::IfsMergeJobClass ||
(A->getType() == clang::driver::types::TY_IFS_CPP &&
@@ -4688,6 +4687,11 @@ void Driver::BuildJobs(Compilation &C) const {
(A->getKind() == Action::BindArchClass && A->getInputs().size() &&
A->getInputs().front()->getKind() == Action::IfsMergeJobClass)))
++NumOutputs;
+ else if (A->getKind() == Action::OffloadClass &&
+ A->getType() == types::TY_Nothing &&
+ !C.getArgs().hasArg(options::OPT_fsyntax_only))
+ NumOutputs += A->size();
+ }
if (NumOutputs > 1) {
Diag(clang::diag::err_drv_output_argument_with_multiple_files);
@@ -4744,7 +4748,7 @@ void Driver::BuildJobs(Compilation &C) const {
if (CCPrintProcessStats) {
C.setPostCallback([=](const Command &Cmd, int Res) {
- Optional<llvm::sys::ProcessStatistics> ProcStat =
+ std::optional<llvm::sys::ProcessStatistics> ProcStat =
Cmd.getProcessStatistics();
if (!ProcStat)
return;
@@ -5225,20 +5229,21 @@ InputInfoList Driver::BuildJobsForActionNoCache(
// \
// Device Action 1 ---> OffloadAction -> Device Action 2
//
- // For a) and b), we just return the job generated for the dependence. For
+ // For a) and b), we just return the job generated for the dependences. For
// c) and d) we override the current action with the host/device dependence
// if the current toolchain is host/device and set the offload dependences
// info with the jobs obtained from the device/host dependence(s).
- // If there is a single device option, just generate the job for it.
- if (OA->hasSingleDeviceDependence()) {
+ // If there is a single device option or has no host action, just generate
+ // the job for it.
+ if (OA->hasSingleDeviceDependence() || !OA->hasHostDependence()) {
InputInfoList DevA;
OA->doOnEachDeviceDependence([&](Action *DepA, const ToolChain *DepTC,
const char *DepBoundArch) {
- DevA =
- BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel,
- /*MultipleArchs*/ !!DepBoundArch, LinkingOutput,
- CachedResults, DepA->getOffloadingDeviceKind());
+ DevA.append(BuildJobsForAction(C, DepA, DepTC, DepBoundArch, AtTopLevel,
+ /*MultipleArchs*/ !!DepBoundArch,
+ LinkingOutput, CachedResults,
+ DepA->getOffloadingDeviceKind()));
});
return DevA;
}
@@ -5313,25 +5318,6 @@ InputInfoList Driver::BuildJobsForActionNoCache(
if (!T)
return {InputInfo()};
- if (BuildingForOffloadDevice &&
- A->getOffloadingDeviceKind() == Action::OFK_OpenMP) {
- if (TC->getTriple().isAMDGCN()) {
- // AMDGCN treats backend and assemble actions as no-op because
- // linker does not support object files.
- if (const BackendJobAction *BA = dyn_cast<BackendJobAction>(A)) {
- return BuildJobsForAction(C, *BA->input_begin(), TC, BoundArch,
- AtTopLevel, MultipleArchs, LinkingOutput,
- CachedResults, TargetDeviceOffloadKind);
- }
-
- if (const AssembleJobAction *AA = dyn_cast<AssembleJobAction>(A)) {
- return BuildJobsForAction(C, *AA->input_begin(), TC, BoundArch,
- AtTopLevel, MultipleArchs, LinkingOutput,
- CachedResults, TargetDeviceOffloadKind);
- }
- }
- }
-
// If we've collapsed action list that contained OffloadAction we
// need to build jobs for host/device-side inputs it may have held.
for (const auto *OA : CollapsedOffloadActions)
@@ -5371,10 +5357,6 @@ InputInfoList Driver::BuildJobsForActionNoCache(
if (JA->getType() == types::TY_dSYM)
BaseInput = InputInfos[0].getFilename();
- // ... and in header module compilations, which use the module name.
- if (auto *ModuleJA = dyn_cast<HeaderModulePrecompileJobAction>(JA))
- BaseInput = ModuleJA->getModuleName();
-
// Append outputs of offload device jobs to the input list
if (!OffloadDependencesInputInfo.empty())
InputInfos.append(OffloadDependencesInputInfo.begin(),
@@ -5457,14 +5439,6 @@ InputInfoList Driver::BuildJobsForActionNoCache(
/*CreatePrefixForHost=*/isa<OffloadPackagerJobAction>(A) ||
!(A->getOffloadingHostActiveKinds() == Action::OFK_None ||
AtTopLevel));
- if (isa<OffloadWrapperJobAction>(JA)) {
- if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
- BaseInput = FinalOutput->getValue();
- else
- BaseInput = getDefaultImageName();
- BaseInput =
- C.getArgs().MakeArgString(std::string(BaseInput) + "-wrapper");
- }
Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch,
AtTopLevel, MultipleArchs,
OffloadingPrefix),
@@ -5554,6 +5528,71 @@ static bool HasPreprocessOutput(const Action &JA) {
return false;
}
+const char *Driver::CreateTempFile(Compilation &C, StringRef Prefix,
+ StringRef Suffix, bool MultipleArchs,
+ StringRef BoundArch) const {
+ SmallString<128> TmpName;
+ Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir);
+ std::optional<std::string> CrashDirectory =
+ CCGenDiagnostics && A
+ ? std::string(A->getValue())
+ : llvm::sys::Process::GetEnv("CLANG_CRASH_DIAGNOSTICS_DIR");
+ if (CrashDirectory) {
+ if (!getVFS().exists(*CrashDirectory))
+ llvm::sys::fs::create_directories(*CrashDirectory);
+ SmallString<128> Path(*CrashDirectory);
+ llvm::sys::path::append(Path, Prefix);
+ const char *Middle = !Suffix.empty() ? "-%%%%%%." : "-%%%%%%";
+ if (std::error_code EC =
+ llvm::sys::fs::createUniqueFile(Path + Middle + Suffix, TmpName)) {
+ Diag(clang::diag::err_unable_to_make_temp) << EC.message();
+ return "";
+ }
+ } else {
+ if (MultipleArchs && !BoundArch.empty()) {
+ TmpName = GetTemporaryDirectory(Prefix);
+ llvm::sys::path::append(TmpName,
+ Twine(Prefix) + "-" + BoundArch + "." + Suffix);
+ } else {
+ TmpName = GetTemporaryPath(Prefix, Suffix);
+ }
+ }
+ return C.addTempFile(C.getArgs().MakeArgString(TmpName));
+}
+
+// Calculate the output path of the module file when compiling a module unit
+// with the `-fmodule-output` option or `-fmodule-output=` option specified.
+// The behavior is:
+// - If `-fmodule-output=` is specfied, then the module file is
+// writing to the value.
+// - Otherwise if the output object file of the module unit is specified, the
+// output path
+// of the module file should be the same with the output object file except
+// the corresponding suffix. This requires both `-o` and `-c` are specified.
+// - Otherwise, the output path of the module file will be the same with the
+// input with the corresponding suffix.
+static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA,
+ const char *BaseInput) {
+ assert(isa<PrecompileJobAction>(JA) && JA.getType() == types::TY_ModuleFile &&
+ (C.getArgs().hasArg(options::OPT_fmodule_output) ||
+ C.getArgs().hasArg(options::OPT_fmodule_output_EQ)));
+
+ if (Arg *ModuleOutputEQ =
+ C.getArgs().getLastArg(options::OPT_fmodule_output_EQ))
+ return C.addResultFile(ModuleOutputEQ->getValue(), &JA);
+
+ SmallString<64> OutputPath;
+ Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
+ if (FinalOutput && C.getArgs().hasArg(options::OPT_c))
+ OutputPath = FinalOutput->getValue();
+ else
+ OutputPath = BaseInput;
+
+ const char *Extension = types::getTypeTempSuffix(JA.getType());
+ llvm::sys::path::replace_extension(OutputPath, Extension);
+ return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA);
+}
+
const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
const char *BaseInput,
StringRef OrigBoundArch, bool AtTopLevel,
@@ -5595,6 +5634,9 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
return "-";
}
+ if (IsDXCMode() && !C.getArgs().hasArg(options::OPT_o))
+ return "-";
+
// Is this the assembly listing for /FA?
if (JA.getType() == types::TY_PP_Asm &&
(C.getArgs().hasArg(options::OPT__SLASH_FA) ||
@@ -5607,37 +5649,26 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
&JA);
}
+ bool SpecifiedModuleOutput =
+ C.getArgs().hasArg(options::OPT_fmodule_output) ||
+ C.getArgs().hasArg(options::OPT_fmodule_output_EQ);
+ if (MultipleArchs && SpecifiedModuleOutput)
+ Diag(clang::diag::err_drv_module_output_with_multiple_arch);
+
+ // If we're emitting a module output with the specified option
+ // `-fmodule-output`.
+ if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
+ JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput)
+ return GetModuleOutputPath(C, JA, BaseInput);
+
// Output to a temporary file?
if ((!AtTopLevel && !isSaveTempsEnabled() &&
!C.getArgs().hasArg(options::OPT__SLASH_Fo)) ||
CCGenDiagnostics) {
StringRef Name = llvm::sys::path::filename(BaseInput);
std::pair<StringRef, StringRef> Split = Name.split('.');
- SmallString<128> TmpName;
const char *Suffix = types::getTypeTempSuffix(JA.getType(), IsCLMode());
- Arg *A = C.getArgs().getLastArg(options::OPT_fcrash_diagnostics_dir);
- if (CCGenDiagnostics && A) {
- SmallString<128> CrashDirectory(A->getValue());
- if (!getVFS().exists(CrashDirectory))
- llvm::sys::fs::create_directories(CrashDirectory);
- llvm::sys::path::append(CrashDirectory, Split.first);
- const char *Middle = Suffix ? "-%%%%%%." : "-%%%%%%";
- std::error_code EC = llvm::sys::fs::createUniqueFile(
- CrashDirectory + Middle + Suffix, TmpName);
- if (EC) {
- Diag(clang::diag::err_unable_to_make_temp) << EC.message();
- return "";
- }
- } else {
- if (MultipleArchs && !BoundArch.empty()) {
- TmpName = GetTemporaryDirectory(Split.first);
- llvm::sys::path::append(TmpName,
- Split.first + "-" + BoundArch + "." + Suffix);
- } else {
- TmpName = GetTemporaryPath(Split.first, Suffix);
- }
- }
- return C.addTempFile(C.getArgs().MakeArgString(TmpName));
+ return CreateTempFile(C, Split.first, Suffix, MultipleArchs, BoundArch);
}
SmallString<128> BasePath(BaseInput);
@@ -5733,19 +5764,22 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
// When using both -save-temps and -emit-llvm, use a ".tmp.bc" suffix for
// the unoptimized bitcode so that it does not get overwritten by the ".bc"
// optimized bitcode output.
- auto IsHIPRDCInCompilePhase = [](const JobAction &JA,
+ auto IsAMDRDCInCompilePhase = [](const JobAction &JA,
const llvm::opt::DerivedArgList &Args) {
- // The relocatable compilation in HIP implies -emit-llvm. Similarly, use a
- // ".tmp.bc" suffix for the unoptimized bitcode (generated in the compile
- // phase.)
+ // The relocatable compilation in HIP and OpenMP implies -emit-llvm.
+ // Similarly, use a ".tmp.bc" suffix for the unoptimized bitcode
+ // (generated in the compile phase.)
+ const ToolChain *TC = JA.getOffloadingToolChain();
return isa<CompileJobAction>(JA) &&
- JA.getOffloadingDeviceKind() == Action::OFK_HIP &&
- Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
- false);
+ ((JA.getOffloadingDeviceKind() == Action::OFK_HIP &&
+ Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ false)) ||
+ (JA.getOffloadingDeviceKind() == Action::OFK_OpenMP && TC &&
+ TC->getTriple().isAMDGPU()));
};
if (!AtTopLevel && JA.getType() == types::TY_LLVM_BC &&
(C.getArgs().hasArg(options::OPT_emit_llvm) ||
- IsHIPRDCInCompilePhase(JA, C.getArgs())))
+ IsAMDRDCInCompilePhase(JA, C.getArgs())))
Suffixed += ".tmp";
Suffixed += '.';
Suffixed += Suffix;
@@ -5789,15 +5823,15 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
else
llvm::sys::path::append(BasePath, NamedOutput);
return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA);
- } else {
- return C.addResultFile(NamedOutput, &JA);
}
+
+ return C.addResultFile(NamedOutput, &JA);
}
std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
// Search for Name in a list of paths.
auto SearchPaths = [&](const llvm::SmallVectorImpl<std::string> &P)
- -> llvm::Optional<std::string> {
+ -> std::optional<std::string> {
// Respect a limited subset of the '-Bprefix' functionality in GCC by
// attempting to use this prefix when looking for file paths.
for (const auto &Dir : P) {
@@ -5808,7 +5842,7 @@ std::string Driver::GetFilePath(StringRef Name, const ToolChain &TC) const {
if (llvm::sys::fs::exists(Twine(P)))
return std::string(P);
}
- return None;
+ return std::nullopt;
};
if (auto P = SearchPaths(PrefixDirs))
@@ -6012,6 +6046,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Solaris:
TC = std::make_unique<toolchains::Solaris>(*this, Target, Args);
break;
+ case llvm::Triple::CUDA:
+ TC = std::make_unique<toolchains::NVPTXToolChain>(*this, Target, Args);
+ break;
case llvm::Triple::AMDHSA:
TC = std::make_unique<toolchains::ROCMToolChain>(*this, Target, Args);
break;
@@ -6131,11 +6168,6 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
}
}
- // Intentionally omitted from the switch above: llvm::Triple::CUDA. CUDA
- // compiles always need two toolchains, the CUDA toolchain and the host
- // toolchain. So the only valid way to create a CUDA toolchain is via
- // CreateOffloadingDeviceToolChains.
-
return *TC;
}
@@ -6300,6 +6332,25 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const {
return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask);
}
+const char *Driver::getExecutableForDriverMode(DriverMode Mode) {
+ switch (Mode) {
+ case GCCMode:
+ return "clang";
+ case GXXMode:
+ return "clang++";
+ case CPPMode:
+ return "clang-cpp";
+ case CLMode:
+ return "clang-cl";
+ case FlangMode:
+ return "flang";
+ case DXCMode:
+ return "clang-dxc";
+ }
+
+ llvm_unreachable("Unhandled Mode");
+}
+
bool clang::driver::isOptimizationLevelFast(const ArgList &Args) {
return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false);
}
diff --git a/clang/lib/Driver/DriverOptions.cpp b/clang/lib/Driver/DriverOptions.cpp
index 67d4198d222a..2a6868d17915 100644
--- a/clang/lib/Driver/DriverOptions.cpp
+++ b/clang/lib/Driver/DriverOptions.cpp
@@ -16,11 +16,26 @@ using namespace clang::driver;
using namespace clang::driver::options;
using namespace llvm::opt;
-#define PREFIX(NAME, VALUE) static const char *const NAME[] = VALUE;
+#define OPTTABLE_VALUES_CODE
+#include "clang/Driver/Options.inc"
+#undef OPTTABLE_VALUES_CODE
+
+#define PREFIX(NAME, VALUE) \
+ static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
+ static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
+ NAME##_init, std::size(NAME##_init) - 1);
#include "clang/Driver/Options.inc"
#undef PREFIX
-static const OptTable::Info InfoTable[] = {
+static constexpr const llvm::StringLiteral PrefixTable_init[] =
+#define PREFIX_UNION(VALUES) VALUES
+#include "clang/Driver/Options.inc"
+#undef PREFIX_UNION
+ ;
+static constexpr const llvm::ArrayRef<llvm::StringLiteral>
+ PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
+
+static constexpr OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
@@ -31,25 +46,13 @@ static const OptTable::Info InfoTable[] = {
namespace {
-class DriverOptTable : public OptTable {
+class DriverOptTable : public PrecomputedOptTable {
public:
- DriverOptTable()
- : OptTable(InfoTable) {}
+ DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
};
-
}
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 Result.release();
- }();
- return *Table;
+ static DriverOptTable Table;
+ return Table;
}
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index f63763effaff..ec355ceb84a9 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -301,6 +301,11 @@ void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) {
Environment.push_back(nullptr);
}
+void Command::setRedirectFiles(
+ const std::vector<std::optional<std::string>> &Redirects) {
+ RedirectFiles = Redirects;
+}
+
void Command::PrintFileNames() const {
if (PrintInputFilenames) {
for (const auto &Arg : InputInfoList)
@@ -309,7 +314,7 @@ void Command::PrintFileNames() const {
}
}
-int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
+int Command::Execute(ArrayRef<std::optional<StringRef>> Redirects,
std::string *ErrMsg, bool *ExecutionFailed) const {
PrintFileNames();
@@ -342,16 +347,32 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
}
}
- Optional<ArrayRef<StringRef>> Env;
+ std::optional<ArrayRef<StringRef>> Env;
std::vector<StringRef> ArgvVectorStorage;
if (!Environment.empty()) {
assert(Environment.back() == nullptr &&
"Environment vector should be null-terminated by now");
ArgvVectorStorage = llvm::toStringRefArray(Environment.data());
- Env = makeArrayRef(ArgvVectorStorage);
+ Env = ArrayRef(ArgvVectorStorage);
}
auto Args = llvm::toStringRefArray(Argv.data());
+
+ // Use Job-specific redirect files if they are present.
+ if (!RedirectFiles.empty()) {
+ std::vector<std::optional<StringRef>> RedirectFilesOptional;
+ for (const auto &Ele : RedirectFiles)
+ if (Ele)
+ RedirectFilesOptional.push_back(std::optional<StringRef>(*Ele));
+ else
+ RedirectFilesOptional.push_back(std::nullopt);
+
+ return llvm::sys::ExecuteAndWait(Executable, Args, Env,
+ ArrayRef(RedirectFilesOptional),
+ /*secondsToWait=*/0, /*memoryLimit=*/0,
+ ErrMsg, ExecutionFailed, &ProcStat);
+ }
+
return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects,
/*secondsToWait*/ 0, /*memoryLimit*/ 0,
ErrMsg, ExecutionFailed, &ProcStat);
@@ -374,7 +395,7 @@ void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote,
Command::Print(OS, Terminator, Quote, CrashInfo);
}
-int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
+int CC1Command::Execute(ArrayRef<std::optional<StringRef>> Redirects,
std::string *ErrMsg, bool *ExecutionFailed) const {
// FIXME: Currently, if there're more than one job, we disable
// -fintegrate-cc1. If we're no longer a integrated-cc1 job, fallback to
@@ -431,7 +452,7 @@ void ForceSuccessCommand::Print(raw_ostream &OS, const char *Terminator,
OS << " || (exit 0)" << Terminator;
}
-int ForceSuccessCommand::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects,
+int ForceSuccessCommand::Execute(ArrayRef<std::optional<StringRef>> Redirects,
std::string *ErrMsg,
bool *ExecutionFailed) const {
int Status = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
diff --git a/clang/lib/Driver/OffloadBundler.cpp b/clang/lib/Driver/OffloadBundler.cpp
new file mode 100644
index 000000000000..cdacceb0a86a
--- /dev/null
+++ b/clang/lib/Driver/OffloadBundler.cpp
@@ -0,0 +1,1283 @@
+//===- OffloadBundler.cpp - File Bundling and Unbundling ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements an offload bundling API that bundles different files
+/// that relate with the same source code but different targets into a single
+/// one. Also the implements the opposite functionality, i.e. unbundle files
+/// previous created by this API.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/OffloadBundler.h"
+#include "clang/Basic/Cuda.h"
+#include "clang/Basic/TargetID.h"
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <forward_list>
+#include <memory>
+#include <set>
+#include <string>
+#include <system_error>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace clang;
+
+/// Magic string that marks the existence of offloading data.
+#define OFFLOAD_BUNDLER_MAGIC_STR "__CLANG_OFFLOAD_BUNDLE__"
+
+OffloadTargetInfo::OffloadTargetInfo(const StringRef Target,
+ const OffloadBundlerConfig &BC)
+ : BundlerConfig(BC) {
+
+ // TODO: Add error checking from ClangOffloadBundler.cpp
+ auto TargetFeatures = Target.split(':');
+ auto TripleOrGPU = TargetFeatures.first.rsplit('-');
+
+ if (clang::StringToCudaArch(TripleOrGPU.second) != clang::CudaArch::UNKNOWN) {
+ auto KindTriple = TripleOrGPU.first.split('-');
+ this->OffloadKind = KindTriple.first;
+ this->Triple = llvm::Triple(KindTriple.second);
+ this->TargetID = Target.substr(Target.find(TripleOrGPU.second));
+ } else {
+ auto KindTriple = TargetFeatures.first.split('-');
+ this->OffloadKind = KindTriple.first;
+ this->Triple = llvm::Triple(KindTriple.second);
+ this->TargetID = "";
+ }
+}
+
+bool OffloadTargetInfo::hasHostKind() const {
+ return this->OffloadKind == "host";
+}
+
+bool OffloadTargetInfo::isOffloadKindValid() const {
+ return OffloadKind == "host" || OffloadKind == "openmp" ||
+ OffloadKind == "hip" || OffloadKind == "hipv4";
+}
+
+bool OffloadTargetInfo::isOffloadKindCompatible(
+ const StringRef TargetOffloadKind) const {
+ if (OffloadKind == TargetOffloadKind)
+ return true;
+ if (BundlerConfig.HipOpenmpCompatible) {
+ bool HIPCompatibleWithOpenMP = OffloadKind.startswith_insensitive("hip") &&
+ TargetOffloadKind == "openmp";
+ bool OpenMPCompatibleWithHIP =
+ OffloadKind == "openmp" &&
+ TargetOffloadKind.startswith_insensitive("hip");
+ return HIPCompatibleWithOpenMP || OpenMPCompatibleWithHIP;
+ }
+ return false;
+}
+
+bool OffloadTargetInfo::isTripleValid() const {
+ return !Triple.str().empty() && Triple.getArch() != Triple::UnknownArch;
+}
+
+bool OffloadTargetInfo::operator==(const OffloadTargetInfo &Target) const {
+ return OffloadKind == Target.OffloadKind &&
+ Triple.isCompatibleWith(Target.Triple) && TargetID == Target.TargetID;
+}
+
+std::string OffloadTargetInfo::str() const {
+ return Twine(OffloadKind + "-" + Triple.str() + "-" + TargetID).str();
+}
+
+static StringRef getDeviceFileExtension(StringRef Device,
+ StringRef BundleFileName) {
+ if (Device.contains("gfx"))
+ return ".bc";
+ if (Device.contains("sm_"))
+ return ".cubin";
+ return sys::path::extension(BundleFileName);
+}
+
+static std::string getDeviceLibraryFileName(StringRef BundleFileName,
+ StringRef Device) {
+ StringRef LibName = sys::path::stem(BundleFileName);
+ StringRef Extension = getDeviceFileExtension(Device, BundleFileName);
+
+ std::string Result;
+ Result += LibName;
+ Result += Extension;
+ return Result;
+}
+
+/// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
+/// target \p TargetInfo.
+/// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
+bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo,
+ const OffloadTargetInfo &TargetInfo) {
+
+ // Compatible in case of exact match.
+ if (CodeObjectInfo == TargetInfo) {
+ DEBUG_WITH_TYPE("CodeObjectCompatibility",
+ dbgs() << "Compatible: Exact match: \t[CodeObject: "
+ << CodeObjectInfo.str()
+ << "]\t:\t[Target: " << TargetInfo.str() << "]\n");
+ return true;
+ }
+
+ // Incompatible if Kinds or Triples mismatch.
+ if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
+ !CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
+ DEBUG_WITH_TYPE(
+ "CodeObjectCompatibility",
+ dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
+ << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
+ << "]\n");
+ return false;
+ }
+
+ // Incompatible if target IDs are incompatible.
+ if (!clang::isCompatibleTargetID(CodeObjectInfo.TargetID,
+ TargetInfo.TargetID)) {
+ DEBUG_WITH_TYPE(
+ "CodeObjectCompatibility",
+ dbgs() << "Incompatible: target IDs are incompatible \t[CodeObject: "
+ << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
+ << "]\n");
+ return false;
+ }
+
+ DEBUG_WITH_TYPE(
+ "CodeObjectCompatibility",
+ dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
+ << CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
+ << "]\n");
+ return true;
+}
+
+namespace {
+/// Generic file handler interface.
+class FileHandler {
+public:
+ struct BundleInfo {
+ StringRef BundleID;
+ };
+
+ FileHandler() {}
+
+ virtual ~FileHandler() {}
+
+ /// Update the file handler with information from the header of the bundled
+ /// file.
+ virtual Error ReadHeader(MemoryBuffer &Input) = 0;
+
+ /// Read the marker of the next bundled to be read in the file. The bundle
+ /// name is returned if there is one in the file, or `std::nullopt` if there
+ /// are no more bundles to be read.
+ virtual Expected<std::optional<StringRef>>
+ ReadBundleStart(MemoryBuffer &Input) = 0;
+
+ /// Read the marker that closes the current bundle.
+ virtual Error ReadBundleEnd(MemoryBuffer &Input) = 0;
+
+ /// Read the current bundle and write the result into the stream \a OS.
+ virtual Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) = 0;
+
+ /// Write the header of the bundled file to \a OS based on the information
+ /// gathered from \a Inputs.
+ virtual Error WriteHeader(raw_fd_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) = 0;
+
+ /// Write the marker that initiates a bundle for the triple \a TargetTriple to
+ /// \a OS.
+ virtual Error WriteBundleStart(raw_fd_ostream &OS,
+ StringRef TargetTriple) = 0;
+
+ /// Write the marker that closes a bundle for the triple \a TargetTriple to \a
+ /// OS.
+ virtual Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) = 0;
+
+ /// Write the bundle from \a Input into \a OS.
+ virtual Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) = 0;
+
+ /// List bundle IDs in \a Input.
+ virtual Error listBundleIDs(MemoryBuffer &Input) {
+ if (Error Err = ReadHeader(Input))
+ return Err;
+ return forEachBundle(Input, [&](const BundleInfo &Info) -> Error {
+ llvm::outs() << Info.BundleID << '\n';
+ Error Err = listBundleIDsCallback(Input, Info);
+ if (Err)
+ return Err;
+ return Error::success();
+ });
+ }
+
+ /// For each bundle in \a Input, do \a Func.
+ Error forEachBundle(MemoryBuffer &Input,
+ std::function<Error(const BundleInfo &)> Func) {
+ while (true) {
+ Expected<std::optional<StringRef>> CurTripleOrErr =
+ ReadBundleStart(Input);
+ if (!CurTripleOrErr)
+ return CurTripleOrErr.takeError();
+
+ // No more bundles.
+ if (!*CurTripleOrErr)
+ break;
+
+ StringRef CurTriple = **CurTripleOrErr;
+ assert(!CurTriple.empty());
+
+ BundleInfo Info{CurTriple};
+ if (Error Err = Func(Info))
+ return Err;
+ }
+ return Error::success();
+ }
+
+protected:
+ virtual Error listBundleIDsCallback(MemoryBuffer &Input,
+ const BundleInfo &Info) {
+ return Error::success();
+ }
+};
+
+/// Handler for binary files. The bundled file will have the following format
+/// (all integers are stored in little-endian format):
+///
+/// "OFFLOAD_BUNDLER_MAGIC_STR" (ASCII encoding of the string)
+///
+/// NumberOfOffloadBundles (8-byte integer)
+///
+/// OffsetOfBundle1 (8-byte integer)
+/// SizeOfBundle1 (8-byte integer)
+/// NumberOfBytesInTripleOfBundle1 (8-byte integer)
+/// TripleOfBundle1 (byte length defined before)
+///
+/// ...
+///
+/// OffsetOfBundleN (8-byte integer)
+/// SizeOfBundleN (8-byte integer)
+/// NumberOfBytesInTripleOfBundleN (8-byte integer)
+/// TripleOfBundleN (byte length defined before)
+///
+/// Bundle1
+/// ...
+/// BundleN
+
+/// Read 8-byte integers from a buffer in little-endian format.
+static uint64_t Read8byteIntegerFromBuffer(StringRef Buffer, size_t pos) {
+ return llvm::support::endian::read64le(Buffer.data() + pos);
+}
+
+/// Write 8-byte integers to a buffer in little-endian format.
+static void Write8byteIntegerToBuffer(raw_fd_ostream &OS, uint64_t Val) {
+ llvm::support::endian::write(OS, Val, llvm::support::little);
+}
+
+class BinaryFileHandler final : public FileHandler {
+ /// Information about the bundles extracted from the header.
+ struct BinaryBundleInfo final : public BundleInfo {
+ /// Size of the bundle.
+ uint64_t Size = 0u;
+ /// Offset at which the bundle starts in the bundled file.
+ uint64_t Offset = 0u;
+
+ BinaryBundleInfo() {}
+ BinaryBundleInfo(uint64_t Size, uint64_t Offset)
+ : Size(Size), Offset(Offset) {}
+ };
+
+ /// Map between a triple and the corresponding bundle information.
+ StringMap<BinaryBundleInfo> BundlesInfo;
+
+ /// Iterator for the bundle information that is being read.
+ StringMap<BinaryBundleInfo>::iterator CurBundleInfo;
+ StringMap<BinaryBundleInfo>::iterator NextBundleInfo;
+
+ /// Current bundle target to be written.
+ std::string CurWriteBundleTarget;
+
+ /// Configuration options and arrays for this bundler job
+ const OffloadBundlerConfig &BundlerConfig;
+
+public:
+ // TODO: Add error checking from ClangOffloadBundler.cpp
+ BinaryFileHandler(const OffloadBundlerConfig &BC) : BundlerConfig(BC) {}
+
+ ~BinaryFileHandler() final {}
+
+ Error ReadHeader(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Initialize the current bundle with the end of the container.
+ CurBundleInfo = BundlesInfo.end();
+
+ // Check if buffer is smaller than magic string.
+ size_t ReadChars = sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
+ if (ReadChars > FC.size())
+ return Error::success();
+
+ // Check if no magic was found.
+ StringRef Magic(FC.data(), sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
+ if (!Magic.equals(OFFLOAD_BUNDLER_MAGIC_STR))
+ return Error::success();
+
+ // Read number of bundles.
+ if (ReadChars + 8 > FC.size())
+ return Error::success();
+
+ uint64_t NumberOfBundles = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read bundle offsets, sizes and triples.
+ for (uint64_t i = 0; i < NumberOfBundles; ++i) {
+
+ // Read offset.
+ if (ReadChars + 8 > FC.size())
+ return Error::success();
+
+ uint64_t Offset = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read size.
+ if (ReadChars + 8 > FC.size())
+ return Error::success();
+
+ uint64_t Size = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read triple size.
+ if (ReadChars + 8 > FC.size())
+ return Error::success();
+
+ uint64_t TripleSize = Read8byteIntegerFromBuffer(FC, ReadChars);
+ ReadChars += 8;
+
+ // Read triple.
+ if (ReadChars + TripleSize > FC.size())
+ return Error::success();
+
+ StringRef Triple(&FC.data()[ReadChars], TripleSize);
+ ReadChars += TripleSize;
+
+ // Check if the offset and size make sense.
+ if (!Offset || Offset + Size > FC.size())
+ return Error::success();
+
+ assert(BundlesInfo.find(Triple) == BundlesInfo.end() &&
+ "Triple is duplicated??");
+ BundlesInfo[Triple] = BinaryBundleInfo(Size, Offset);
+ }
+ // Set the iterator to where we will start to read.
+ CurBundleInfo = BundlesInfo.end();
+ NextBundleInfo = BundlesInfo.begin();
+ return Error::success();
+ }
+
+ Expected<std::optional<StringRef>>
+ ReadBundleStart(MemoryBuffer &Input) final {
+ if (NextBundleInfo == BundlesInfo.end())
+ return std::nullopt;
+ CurBundleInfo = NextBundleInfo++;
+ return CurBundleInfo->first();
+ }
+
+ Error ReadBundleEnd(MemoryBuffer &Input) final {
+ assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
+ return Error::success();
+ }
+
+ Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ assert(CurBundleInfo != BundlesInfo.end() && "Invalid reader info!");
+ StringRef FC = Input.getBuffer();
+ OS.write(FC.data() + CurBundleInfo->second.Offset,
+ CurBundleInfo->second.Size);
+ return Error::success();
+ }
+
+ Error WriteHeader(raw_fd_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+
+ // Compute size of the header.
+ uint64_t HeaderSize = 0;
+
+ HeaderSize += sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1;
+ HeaderSize += 8; // Number of Bundles
+
+ for (auto &T : BundlerConfig.TargetNames) {
+ HeaderSize += 3 * 8; // Bundle offset, Size of bundle and size of triple.
+ HeaderSize += T.size(); // The triple.
+ }
+
+ // Write to the buffer the header.
+ OS << OFFLOAD_BUNDLER_MAGIC_STR;
+
+ Write8byteIntegerToBuffer(OS, BundlerConfig.TargetNames.size());
+
+ unsigned Idx = 0;
+ for (auto &T : BundlerConfig.TargetNames) {
+ MemoryBuffer &MB = *Inputs[Idx++];
+ HeaderSize = alignTo(HeaderSize, BundlerConfig.BundleAlignment);
+ // Bundle offset.
+ Write8byteIntegerToBuffer(OS, HeaderSize);
+ // Size of the bundle (adds to the next bundle's offset)
+ Write8byteIntegerToBuffer(OS, MB.getBufferSize());
+ BundlesInfo[T] = BinaryBundleInfo(MB.getBufferSize(), HeaderSize);
+ HeaderSize += MB.getBufferSize();
+ // Size of the triple
+ Write8byteIntegerToBuffer(OS, T.size());
+ // Triple
+ OS << T;
+ }
+ return Error::success();
+ }
+
+ Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ CurWriteBundleTarget = TargetTriple.str();
+ return Error::success();
+ }
+
+ Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ return Error::success();
+ }
+
+ Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ auto BI = BundlesInfo[CurWriteBundleTarget];
+ OS.seek(BI.Offset);
+ OS.write(Input.getBufferStart(), Input.getBufferSize());
+ return Error::success();
+ }
+};
+
+// This class implements a list of temporary files that are removed upon
+// object destruction.
+class TempFileHandlerRAII {
+public:
+ ~TempFileHandlerRAII() {
+ for (const auto &File : Files)
+ sys::fs::remove(File);
+ }
+
+ // Creates temporary file with given contents.
+ Expected<StringRef> Create(std::optional<ArrayRef<char>> Contents) {
+ SmallString<128u> File;
+ if (std::error_code EC =
+ sys::fs::createTemporaryFile("clang-offload-bundler", "tmp", File))
+ return createFileError(File, EC);
+ Files.push_front(File);
+
+ if (Contents) {
+ std::error_code EC;
+ raw_fd_ostream OS(File, EC);
+ if (EC)
+ return createFileError(File, EC);
+ OS.write(Contents->data(), Contents->size());
+ }
+ return Files.front().str();
+ }
+
+private:
+ std::forward_list<SmallString<128u>> Files;
+};
+
+/// Handler for object files. The bundles are organized by sections with a
+/// designated name.
+///
+/// To unbundle, we just copy the contents of the designated section.
+class ObjectFileHandler final : public FileHandler {
+
+ /// The object file we are currently dealing with.
+ std::unique_ptr<ObjectFile> Obj;
+
+ /// Return the input file contents.
+ StringRef getInputFileContents() const { return Obj->getData(); }
+
+ /// Return bundle name (<kind>-<triple>) if the provided section is an offload
+ /// section.
+ static Expected<std::optional<StringRef>>
+ IsOffloadSection(SectionRef CurSection) {
+ Expected<StringRef> NameOrErr = CurSection.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+
+ // If it does not start with the reserved suffix, just skip this section.
+ if (!NameOrErr->startswith(OFFLOAD_BUNDLER_MAGIC_STR))
+ return std::nullopt;
+
+ // Return the triple that is right after the reserved prefix.
+ return NameOrErr->substr(sizeof(OFFLOAD_BUNDLER_MAGIC_STR) - 1);
+ }
+
+ /// Total number of inputs.
+ unsigned NumberOfInputs = 0;
+
+ /// Total number of processed inputs, i.e, inputs that were already
+ /// read from the buffers.
+ unsigned NumberOfProcessedInputs = 0;
+
+ /// Iterator of the current and next section.
+ section_iterator CurrentSection;
+ section_iterator NextSection;
+
+ /// Configuration options and arrays for this bundler job
+ const OffloadBundlerConfig &BundlerConfig;
+
+public:
+ // TODO: Add error checking from ClangOffloadBundler.cpp
+ ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn,
+ const OffloadBundlerConfig &BC)
+ : Obj(std::move(ObjIn)), CurrentSection(Obj->section_begin()),
+ NextSection(Obj->section_begin()), BundlerConfig(BC) {}
+
+ ~ObjectFileHandler() final {}
+
+ Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
+
+ Expected<std::optional<StringRef>>
+ ReadBundleStart(MemoryBuffer &Input) final {
+ while (NextSection != Obj->section_end()) {
+ CurrentSection = NextSection;
+ ++NextSection;
+
+ // Check if the current section name starts with the reserved prefix. If
+ // so, return the triple.
+ Expected<std::optional<StringRef>> TripleOrErr =
+ IsOffloadSection(*CurrentSection);
+ if (!TripleOrErr)
+ return TripleOrErr.takeError();
+ if (*TripleOrErr)
+ return **TripleOrErr;
+ }
+ return std::nullopt;
+ }
+
+ Error ReadBundleEnd(MemoryBuffer &Input) final { return Error::success(); }
+
+ Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ Expected<StringRef> ContentOrErr = CurrentSection->getContents();
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+ StringRef Content = *ContentOrErr;
+
+ // Copy fat object contents to the output when extracting host bundle.
+ if (Content.size() == 1u && Content.front() == 0)
+ Content = StringRef(Input.getBufferStart(), Input.getBufferSize());
+
+ OS.write(Content.data(), Content.size());
+ return Error::success();
+ }
+
+ Error WriteHeader(raw_fd_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+ assert(BundlerConfig.HostInputIndex != ~0u &&
+ "Host input index not defined.");
+
+ // Record number of inputs.
+ NumberOfInputs = Inputs.size();
+ return Error::success();
+ }
+
+ Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ ++NumberOfProcessedInputs;
+ return Error::success();
+ }
+
+ Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ assert(NumberOfProcessedInputs <= NumberOfInputs &&
+ "Processing more inputs that actually exist!");
+ assert(BundlerConfig.HostInputIndex != ~0u &&
+ "Host input index not defined.");
+
+ // If this is not the last output, we don't have to do anything.
+ if (NumberOfProcessedInputs != NumberOfInputs)
+ return Error::success();
+
+ // We will use llvm-objcopy to add target objects sections to the output
+ // fat object. These sections should have 'exclude' flag set which tells
+ // link editor to remove them from linker inputs when linking executable or
+ // shared library.
+
+ assert(BundlerConfig.ObjcopyPath != "" &&
+ "llvm-objcopy path not specified");
+
+ // We write to the output file directly. So, we close it and use the name
+ // to pass down to llvm-objcopy.
+ OS.close();
+
+ // Temporary files that need to be removed.
+ TempFileHandlerRAII TempFiles;
+
+ // Compose llvm-objcopy command line for add target objects' sections with
+ // appropriate flags.
+ BumpPtrAllocator Alloc;
+ StringSaver SS{Alloc};
+ SmallVector<StringRef, 8u> ObjcopyArgs{"llvm-objcopy"};
+
+ for (unsigned I = 0; I < NumberOfInputs; ++I) {
+ StringRef InputFile = BundlerConfig.InputFileNames[I];
+ if (I == BundlerConfig.HostInputIndex) {
+ // Special handling for the host bundle. We do not need to add a
+ // standard bundle for the host object since we are going to use fat
+ // object as a host object. Therefore use dummy contents (one zero byte)
+ // when creating section for the host bundle.
+ Expected<StringRef> TempFileOrErr = TempFiles.Create(ArrayRef<char>(0));
+ if (!TempFileOrErr)
+ return TempFileOrErr.takeError();
+ InputFile = *TempFileOrErr;
+ }
+
+ ObjcopyArgs.push_back(
+ SS.save(Twine("--add-section=") + OFFLOAD_BUNDLER_MAGIC_STR +
+ BundlerConfig.TargetNames[I] + "=" + InputFile));
+ ObjcopyArgs.push_back(
+ SS.save(Twine("--set-section-flags=") + OFFLOAD_BUNDLER_MAGIC_STR +
+ BundlerConfig.TargetNames[I] + "=readonly,exclude"));
+ }
+ ObjcopyArgs.push_back("--");
+ ObjcopyArgs.push_back(
+ BundlerConfig.InputFileNames[BundlerConfig.HostInputIndex]);
+ ObjcopyArgs.push_back(BundlerConfig.OutputFileNames.front());
+
+ if (Error Err = executeObjcopy(BundlerConfig.ObjcopyPath, ObjcopyArgs))
+ return Err;
+
+ return Error::success();
+ }
+
+ Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ return Error::success();
+ }
+
+private:
+ Error executeObjcopy(StringRef Objcopy, ArrayRef<StringRef> Args) {
+ // If the user asked for the commands to be printed out, we do that
+ // instead of executing it.
+ if (BundlerConfig.PrintExternalCommands) {
+ errs() << "\"" << Objcopy << "\"";
+ for (StringRef Arg : drop_begin(Args, 1))
+ errs() << " \"" << Arg << "\"";
+ errs() << "\n";
+ } else {
+ if (sys::ExecuteAndWait(Objcopy, Args))
+ return createStringError(inconvertibleErrorCode(),
+ "'llvm-objcopy' tool failed");
+ }
+ return Error::success();
+ }
+};
+
+/// Handler for text files. The bundled file will have the following format.
+///
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
+/// Bundle 1
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
+/// ...
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__START__ triple"
+/// Bundle N
+/// "Comment OFFLOAD_BUNDLER_MAGIC_STR__END__ triple"
+class TextFileHandler final : public FileHandler {
+ /// String that begins a line comment.
+ StringRef Comment;
+
+ /// String that initiates a bundle.
+ std::string BundleStartString;
+
+ /// String that closes a bundle.
+ std::string BundleEndString;
+
+ /// Number of chars read from input.
+ size_t ReadChars = 0u;
+
+protected:
+ Error ReadHeader(MemoryBuffer &Input) final { return Error::success(); }
+
+ Expected<std::optional<StringRef>>
+ ReadBundleStart(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Find start of the bundle.
+ ReadChars = FC.find(BundleStartString, ReadChars);
+ if (ReadChars == FC.npos)
+ return std::nullopt;
+
+ // Get position of the triple.
+ size_t TripleStart = ReadChars = ReadChars + BundleStartString.size();
+
+ // Get position that closes the triple.
+ size_t TripleEnd = ReadChars = FC.find("\n", ReadChars);
+ if (TripleEnd == FC.npos)
+ return std::nullopt;
+
+ // Next time we read after the new line.
+ ++ReadChars;
+
+ return StringRef(&FC.data()[TripleStart], TripleEnd - TripleStart);
+ }
+
+ Error ReadBundleEnd(MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+
+ // Read up to the next new line.
+ assert(FC[ReadChars] == '\n' && "The bundle should end with a new line.");
+
+ size_t TripleEnd = ReadChars = FC.find("\n", ReadChars + 1);
+ if (TripleEnd != FC.npos)
+ // Next time we read after the new line.
+ ++ReadChars;
+
+ return Error::success();
+ }
+
+ Error ReadBundle(raw_ostream &OS, MemoryBuffer &Input) final {
+ StringRef FC = Input.getBuffer();
+ size_t BundleStart = ReadChars;
+
+ // Find end of the bundle.
+ size_t BundleEnd = ReadChars = FC.find(BundleEndString, ReadChars);
+
+ StringRef Bundle(&FC.data()[BundleStart], BundleEnd - BundleStart);
+ OS << Bundle;
+
+ return Error::success();
+ }
+
+ Error WriteHeader(raw_fd_ostream &OS,
+ ArrayRef<std::unique_ptr<MemoryBuffer>> Inputs) final {
+ return Error::success();
+ }
+
+ Error WriteBundleStart(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ OS << BundleStartString << TargetTriple << "\n";
+ return Error::success();
+ }
+
+ Error WriteBundleEnd(raw_fd_ostream &OS, StringRef TargetTriple) final {
+ OS << BundleEndString << TargetTriple << "\n";
+ return Error::success();
+ }
+
+ Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final {
+ OS << Input.getBuffer();
+ return Error::success();
+ }
+
+public:
+ TextFileHandler(StringRef Comment) : Comment(Comment), ReadChars(0) {
+ BundleStartString =
+ "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__START__ ";
+ BundleEndString =
+ "\n" + Comment.str() + " " OFFLOAD_BUNDLER_MAGIC_STR "__END__ ";
+ }
+
+ Error listBundleIDsCallback(MemoryBuffer &Input,
+ const BundleInfo &Info) final {
+ // TODO: To list bundle IDs in a bundled text file we need to go through
+ // all bundles. The format of bundled text file may need to include a
+ // header if the performance of listing bundle IDs of bundled text file is
+ // important.
+ ReadChars = Input.getBuffer().find(BundleEndString, ReadChars);
+ if (Error Err = ReadBundleEnd(Input))
+ return Err;
+ return Error::success();
+ }
+};
+} // namespace
+
+/// Return an appropriate object file handler. We use the specific object
+/// handler if we know how to deal with that format, otherwise we use a default
+/// binary file handler.
+static std::unique_ptr<FileHandler>
+CreateObjectFileHandler(MemoryBuffer &FirstInput,
+ const OffloadBundlerConfig &BundlerConfig) {
+ // Check if the input file format is one that we know how to deal with.
+ Expected<std::unique_ptr<Binary>> BinaryOrErr = createBinary(FirstInput);
+
+ // We only support regular object files. If failed to open the input as a
+ // known binary or this is not an object file use the default binary handler.
+ if (errorToBool(BinaryOrErr.takeError()) || !isa<ObjectFile>(*BinaryOrErr))
+ return std::make_unique<BinaryFileHandler>(BundlerConfig);
+
+ // Otherwise create an object file handler. The handler will be owned by the
+ // client of this function.
+ return std::make_unique<ObjectFileHandler>(
+ std::unique_ptr<ObjectFile>(cast<ObjectFile>(BinaryOrErr->release())),
+ BundlerConfig);
+}
+
+/// Return an appropriate handler given the input files and options.
+static Expected<std::unique_ptr<FileHandler>>
+CreateFileHandler(MemoryBuffer &FirstInput,
+ const OffloadBundlerConfig &BundlerConfig) {
+ std::string FilesType = BundlerConfig.FilesType;
+
+ if (FilesType == "i")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"//");
+ if (FilesType == "ii")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"//");
+ if (FilesType == "cui")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"//");
+ if (FilesType == "hipi")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"//");
+ // TODO: `.d` should be eventually removed once `-M` and its variants are
+ // handled properly in offload compilation.
+ if (FilesType == "d")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"#");
+ if (FilesType == "ll")
+ return std::make_unique<TextFileHandler>(/*Comment=*/";");
+ if (FilesType == "bc")
+ return std::make_unique<BinaryFileHandler>(BundlerConfig);
+ if (FilesType == "s")
+ return std::make_unique<TextFileHandler>(/*Comment=*/"#");
+ if (FilesType == "o")
+ return CreateObjectFileHandler(FirstInput, BundlerConfig);
+ if (FilesType == "a")
+ return CreateObjectFileHandler(FirstInput, BundlerConfig);
+ if (FilesType == "gch")
+ return std::make_unique<BinaryFileHandler>(BundlerConfig);
+ if (FilesType == "ast")
+ return std::make_unique<BinaryFileHandler>(BundlerConfig);
+
+ return createStringError(errc::invalid_argument,
+ "'" + FilesType + "': invalid file type specified");
+}
+
+// List bundle IDs. Return true if an error was found.
+Error OffloadBundler::ListBundleIDsInFile(
+ StringRef InputFileName, const OffloadBundlerConfig &BundlerConfig) {
+ // Open Input file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(InputFileName);
+ if (std::error_code EC = CodeOrErr.getError())
+ return createFileError(InputFileName, EC);
+
+ MemoryBuffer &Input = **CodeOrErr;
+
+ // Select the right files handler.
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+ CreateFileHandler(Input, BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
+ assert(FH);
+ return FH->listBundleIDs(Input);
+}
+
+/// Bundle the files. Return true if an error was found.
+Error OffloadBundler::BundleFiles() {
+ std::error_code EC;
+
+ // Create output file.
+ raw_fd_ostream OutputFile(BundlerConfig.OutputFileNames.front(), EC,
+ sys::fs::OF_None);
+ if (EC)
+ return createFileError(BundlerConfig.OutputFileNames.front(), EC);
+
+ // Open input files.
+ SmallVector<std::unique_ptr<MemoryBuffer>, 8u> InputBuffers;
+ InputBuffers.reserve(BundlerConfig.InputFileNames.size());
+ for (auto &I : BundlerConfig.InputFileNames) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(I);
+ if (std::error_code EC = CodeOrErr.getError())
+ return createFileError(I, EC);
+ InputBuffers.emplace_back(std::move(*CodeOrErr));
+ }
+
+ // Get the file handler. We use the host buffer as reference.
+ assert((BundlerConfig.HostInputIndex != ~0u || BundlerConfig.AllowNoHost) &&
+ "Host input index undefined??");
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr = CreateFileHandler(
+ *InputBuffers[BundlerConfig.AllowNoHost ? 0
+ : BundlerConfig.HostInputIndex],
+ BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
+ assert(FH);
+
+ // Write header.
+ if (Error Err = FH->WriteHeader(OutputFile, InputBuffers))
+ return Err;
+
+ // Write all bundles along with the start/end markers. If an error was found
+ // writing the end of the bundle component, abort the bundle writing.
+ auto Input = InputBuffers.begin();
+ for (auto &Triple : BundlerConfig.TargetNames) {
+ if (Error Err = FH->WriteBundleStart(OutputFile, Triple))
+ return Err;
+ if (Error Err = FH->WriteBundle(OutputFile, **Input))
+ return Err;
+ if (Error Err = FH->WriteBundleEnd(OutputFile, Triple))
+ return Err;
+ ++Input;
+ }
+ return Error::success();
+}
+
+// Unbundle the files. Return true if an error was found.
+Error OffloadBundler::UnbundleFiles() {
+ // Open Input file.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(BundlerConfig.InputFileNames.front());
+ if (std::error_code EC = CodeOrErr.getError())
+ return createFileError(BundlerConfig.InputFileNames.front(), EC);
+
+ MemoryBuffer &Input = **CodeOrErr;
+
+ // Select the right files handler.
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+ CreateFileHandler(Input, BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FH = *FileHandlerOrErr;
+ assert(FH);
+
+ // Read the header of the bundled file.
+ if (Error Err = FH->ReadHeader(Input))
+ return Err;
+
+ // Create a work list that consist of the map triple/output file.
+ StringMap<StringRef> Worklist;
+ auto Output = BundlerConfig.OutputFileNames.begin();
+ for (auto &Triple : BundlerConfig.TargetNames) {
+ Worklist[Triple] = *Output;
+ ++Output;
+ }
+
+ // Read all the bundles that are in the work list. If we find no bundles we
+ // assume the file is meant for the host target.
+ bool FoundHostBundle = false;
+ while (!Worklist.empty()) {
+ Expected<std::optional<StringRef>> CurTripleOrErr =
+ FH->ReadBundleStart(Input);
+ if (!CurTripleOrErr)
+ return CurTripleOrErr.takeError();
+
+ // We don't have more bundles.
+ if (!*CurTripleOrErr)
+ break;
+
+ StringRef CurTriple = **CurTripleOrErr;
+ assert(!CurTriple.empty());
+
+ auto Output = Worklist.begin();
+ for (auto E = Worklist.end(); Output != E; Output++) {
+ if (isCodeObjectCompatible(
+ OffloadTargetInfo(CurTriple, BundlerConfig),
+ OffloadTargetInfo((*Output).first(), BundlerConfig))) {
+ break;
+ }
+ }
+
+ if (Output == Worklist.end())
+ continue;
+ // Check if the output file can be opened and copy the bundle to it.
+ std::error_code EC;
+ raw_fd_ostream OutputFile((*Output).second, EC, sys::fs::OF_None);
+ if (EC)
+ return createFileError((*Output).second, EC);
+ if (Error Err = FH->ReadBundle(OutputFile, Input))
+ return Err;
+ if (Error Err = FH->ReadBundleEnd(Input))
+ return Err;
+ Worklist.erase(Output);
+
+ // Record if we found the host bundle.
+ auto OffloadInfo = OffloadTargetInfo(CurTriple, BundlerConfig);
+ if (OffloadInfo.hasHostKind())
+ FoundHostBundle = true;
+ }
+
+ if (!BundlerConfig.AllowMissingBundles && !Worklist.empty()) {
+ std::string ErrMsg = "Can't find bundles for";
+ std::set<StringRef> Sorted;
+ for (auto &E : Worklist)
+ Sorted.insert(E.first());
+ unsigned I = 0;
+ unsigned Last = Sorted.size() - 1;
+ for (auto &E : Sorted) {
+ if (I != 0 && Last > 1)
+ ErrMsg += ",";
+ ErrMsg += " ";
+ if (I == Last && I != 0)
+ ErrMsg += "and ";
+ ErrMsg += E.str();
+ ++I;
+ }
+ return createStringError(inconvertibleErrorCode(), ErrMsg);
+ }
+
+ // If no bundles were found, assume the input file is the host bundle and
+ // create empty files for the remaining targets.
+ if (Worklist.size() == BundlerConfig.TargetNames.size()) {
+ for (auto &E : Worklist) {
+ std::error_code EC;
+ raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
+ if (EC)
+ return createFileError(E.second, EC);
+
+ // If this entry has a host kind, copy the input file to the output file.
+ auto OffloadInfo = OffloadTargetInfo(E.getKey(), BundlerConfig);
+ if (OffloadInfo.hasHostKind())
+ OutputFile.write(Input.getBufferStart(), Input.getBufferSize());
+ }
+ return Error::success();
+ }
+
+ // If we found elements, we emit an error if none of those were for the host
+ // in case host bundle name was provided in command line.
+ if (!(FoundHostBundle || BundlerConfig.HostInputIndex == ~0u ||
+ BundlerConfig.AllowMissingBundles))
+ return createStringError(inconvertibleErrorCode(),
+ "Can't find bundle for the host target");
+
+ // If we still have any elements in the worklist, create empty files for them.
+ for (auto &E : Worklist) {
+ std::error_code EC;
+ raw_fd_ostream OutputFile(E.second, EC, sys::fs::OF_None);
+ if (EC)
+ return createFileError(E.second, EC);
+ }
+
+ return Error::success();
+}
+
+static Archive::Kind getDefaultArchiveKindForHost() {
+ return Triple(sys::getDefaultTargetTriple()).isOSDarwin() ? Archive::K_DARWIN
+ : Archive::K_GNU;
+}
+
+/// @brief Computes a list of targets among all given targets which are
+/// compatible with this code object
+/// @param [in] CodeObjectInfo Code Object
+/// @param [out] CompatibleTargets List of all compatible targets among all
+/// given targets
+/// @return false, if no compatible target is found.
+static bool
+getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo,
+ SmallVectorImpl<StringRef> &CompatibleTargets,
+ const OffloadBundlerConfig &BundlerConfig) {
+ if (!CompatibleTargets.empty()) {
+ DEBUG_WITH_TYPE("CodeObjectCompatibility",
+ dbgs() << "CompatibleTargets list should be empty\n");
+ return false;
+ }
+ for (auto &Target : BundlerConfig.TargetNames) {
+ auto TargetInfo = OffloadTargetInfo(Target, BundlerConfig);
+ if (isCodeObjectCompatible(CodeObjectInfo, TargetInfo))
+ CompatibleTargets.push_back(Target);
+ }
+ return !CompatibleTargets.empty();
+}
+
+/// UnbundleArchive takes an archive file (".a") as input containing bundled
+/// code object files, and a list of offload targets (not host), and extracts
+/// the code objects into a new archive file for each offload target. Each
+/// resulting archive file contains all code object files corresponding to that
+/// particular offload target. The created archive file does not
+/// contain an index of the symbols and code object files are named as
+/// <<Parent Bundle Name>-<CodeObject's GPUArch>>, with ':' replaced with '_'.
+Error OffloadBundler::UnbundleArchive() {
+ std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
+
+ /// Map of target names with list of object files that will form the device
+ /// specific archive for that target
+ StringMap<std::vector<NewArchiveMember>> OutputArchivesMap;
+
+ // Map of target names and output archive filenames
+ StringMap<StringRef> TargetOutputFileNameMap;
+
+ auto Output = BundlerConfig.OutputFileNames.begin();
+ for (auto &Target : BundlerConfig.TargetNames) {
+ TargetOutputFileNameMap[Target] = *Output;
+ ++Output;
+ }
+
+ StringRef IFName = BundlerConfig.InputFileNames.front();
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFileOrSTDIN(IFName, true, false);
+ if (std::error_code EC = BufOrErr.getError())
+ return createFileError(BundlerConfig.InputFileNames.front(), EC);
+
+ ArchiveBuffers.push_back(std::move(*BufOrErr));
+ Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr =
+ Archive::create(ArchiveBuffers.back()->getMemBufferRef());
+ if (!LibOrErr)
+ return LibOrErr.takeError();
+
+ auto Archive = std::move(*LibOrErr);
+
+ Error ArchiveErr = Error::success();
+ auto ChildEnd = Archive->child_end();
+
+ /// Iterate over all bundled code object files in the input archive.
+ for (auto ArchiveIter = Archive->child_begin(ArchiveErr);
+ ArchiveIter != ChildEnd; ++ArchiveIter) {
+ if (ArchiveErr)
+ return ArchiveErr;
+ auto ArchiveChildNameOrErr = (*ArchiveIter).getName();
+ if (!ArchiveChildNameOrErr)
+ return ArchiveChildNameOrErr.takeError();
+
+ StringRef BundledObjectFile = sys::path::filename(*ArchiveChildNameOrErr);
+
+ auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef();
+ if (!CodeObjectBufferRefOrErr)
+ return CodeObjectBufferRefOrErr.takeError();
+
+ auto CodeObjectBuffer =
+ MemoryBuffer::getMemBuffer(*CodeObjectBufferRefOrErr, false);
+
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
+ CreateFileHandler(*CodeObjectBuffer, BundlerConfig);
+ if (!FileHandlerOrErr)
+ return FileHandlerOrErr.takeError();
+
+ std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
+ assert(FileHandler &&
+ "FileHandle creation failed for file in the archive!");
+
+ if (Error ReadErr = FileHandler->ReadHeader(*CodeObjectBuffer))
+ return ReadErr;
+
+ Expected<std::optional<StringRef>> CurBundleIDOrErr =
+ FileHandler->ReadBundleStart(*CodeObjectBuffer);
+ if (!CurBundleIDOrErr)
+ return CurBundleIDOrErr.takeError();
+
+ std::optional<StringRef> OptionalCurBundleID = *CurBundleIDOrErr;
+ // No device code in this child, skip.
+ if (!OptionalCurBundleID)
+ continue;
+ StringRef CodeObject = *OptionalCurBundleID;
+
+ // Process all bundle entries (CodeObjects) found in this child of input
+ // archive.
+ while (!CodeObject.empty()) {
+ SmallVector<StringRef> CompatibleTargets;
+ auto CodeObjectInfo = OffloadTargetInfo(CodeObject, BundlerConfig);
+ if (CodeObjectInfo.hasHostKind()) {
+ // Do nothing, we don't extract host code yet.
+ } else if (getCompatibleOffloadTargets(CodeObjectInfo, CompatibleTargets,
+ BundlerConfig)) {
+ std::string BundleData;
+ raw_string_ostream DataStream(BundleData);
+ if (Error Err = FileHandler->ReadBundle(DataStream, *CodeObjectBuffer))
+ return Err;
+
+ for (auto &CompatibleTarget : CompatibleTargets) {
+ SmallString<128> BundledObjectFileName;
+ BundledObjectFileName.assign(BundledObjectFile);
+ auto OutputBundleName =
+ Twine(llvm::sys::path::stem(BundledObjectFileName) + "-" +
+ CodeObject +
+ getDeviceLibraryFileName(BundledObjectFileName,
+ CodeObjectInfo.TargetID))
+ .str();
+ // Replace ':' in optional target feature list with '_' to ensure
+ // cross-platform validity.
+ std::replace(OutputBundleName.begin(), OutputBundleName.end(), ':',
+ '_');
+
+ std::unique_ptr<MemoryBuffer> MemBuf = MemoryBuffer::getMemBufferCopy(
+ DataStream.str(), OutputBundleName);
+ ArchiveBuffers.push_back(std::move(MemBuf));
+ llvm::MemoryBufferRef MemBufRef =
+ MemoryBufferRef(*(ArchiveBuffers.back()));
+
+ // For inserting <CompatibleTarget, list<CodeObject>> entry in
+ // OutputArchivesMap.
+ if (OutputArchivesMap.find(CompatibleTarget) ==
+ OutputArchivesMap.end()) {
+
+ std::vector<NewArchiveMember> ArchiveMembers;
+ ArchiveMembers.push_back(NewArchiveMember(MemBufRef));
+ OutputArchivesMap.insert_or_assign(CompatibleTarget,
+ std::move(ArchiveMembers));
+ } else {
+ OutputArchivesMap[CompatibleTarget].push_back(
+ NewArchiveMember(MemBufRef));
+ }
+ }
+ }
+
+ if (Error Err = FileHandler->ReadBundleEnd(*CodeObjectBuffer))
+ return Err;
+
+ Expected<std::optional<StringRef>> NextTripleOrErr =
+ FileHandler->ReadBundleStart(*CodeObjectBuffer);
+ if (!NextTripleOrErr)
+ return NextTripleOrErr.takeError();
+
+ CodeObject = ((*NextTripleOrErr).has_value()) ? **NextTripleOrErr : "";
+ } // End of processing of all bundle entries of this child of input archive.
+ } // End of while over children of input archive.
+
+ assert(!ArchiveErr && "Error occurred while reading archive!");
+
+ /// Write out an archive for each target
+ for (auto &Target : BundlerConfig.TargetNames) {
+ StringRef FileName = TargetOutputFileNameMap[Target];
+ StringMapIterator<std::vector<llvm::NewArchiveMember>> CurArchiveMembers =
+ OutputArchivesMap.find(Target);
+ if (CurArchiveMembers != OutputArchivesMap.end()) {
+ if (Error WriteErr = writeArchive(FileName, CurArchiveMembers->getValue(),
+ true, getDefaultArchiveKindForHost(),
+ true, false, nullptr))
+ return WriteErr;
+ } else if (!BundlerConfig.AllowMissingBundles) {
+ std::string ErrMsg =
+ Twine("no compatible code object found for the target '" + Target +
+ "' in heterogeneous archive library: " + IFName)
+ .str();
+ return createStringError(inconvertibleErrorCode(), ErrMsg);
+ } else { // Create an empty archive file if no compatible code object is
+ // found and "allow-missing-bundles" is enabled. It ensures that
+ // the linker using output of this step doesn't complain about
+ // the missing input file.
+ std::vector<llvm::NewArchiveMember> EmptyArchive;
+ EmptyArchive.clear();
+ if (Error WriteErr = writeArchive(FileName, EmptyArchive, true,
+ getDefaultArchiveKindForHost(), true,
+ false, nullptr))
+ return WriteErr;
+ }
+ }
+
+ return Error::success();
+}
diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp
index 68fe90c7a69d..52bee6a755ff 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -37,7 +37,8 @@ static const SanitizerMask NotAllowedWithTrap = SanitizerKind::Vptr;
static const SanitizerMask NotAllowedWithMinimalRuntime =
SanitizerKind::Function | SanitizerKind::Vptr;
static const SanitizerMask RequiresPIE =
- SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo;
+ SanitizerKind::DataFlow | SanitizerKind::HWAddress | SanitizerKind::Scudo |
+ SanitizerKind::KCFI;
static const SanitizerMask NeedsUnwindTables =
SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Thread |
SanitizerKind::Memory | SanitizerKind::DataFlow;
@@ -52,15 +53,16 @@ static const SanitizerMask SupportsCoverage =
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack |
- SanitizerKind::Thread | SanitizerKind::ObjCCast;
+ SanitizerKind::Thread | SanitizerKind::ObjCCast | SanitizerKind::KCFI;
static const SanitizerMask RecoverableByDefault =
SanitizerKind::Undefined | SanitizerKind::Integer |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::FloatDivideByZero | SanitizerKind::ObjCCast;
static const SanitizerMask Unrecoverable =
SanitizerKind::Unreachable | SanitizerKind::Return;
-static const SanitizerMask AlwaysRecoverable =
- SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress;
+static const SanitizerMask AlwaysRecoverable = SanitizerKind::KernelAddress |
+ SanitizerKind::KernelHWAddress |
+ SanitizerKind::KCFI;
static const SanitizerMask NeedsLTO = SanitizerKind::CFI;
static const SanitizerMask TrappingSupported =
(SanitizerKind::Undefined & ~SanitizerKind::Vptr) | SanitizerKind::Integer |
@@ -96,6 +98,13 @@ enum CoverageFeature {
CoverageInlineBoolFlag = 1 << 15,
CoverageTraceLoads = 1 << 16,
CoverageTraceStores = 1 << 17,
+ CoverageControlFlow = 1 << 18,
+};
+
+enum BinaryMetadataFeature {
+ BinaryMetadataCovered = 1 << 0,
+ BinaryMetadataAtomics = 1 << 1,
+ BinaryMetadataUAR = 1 << 2,
};
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
@@ -108,6 +117,11 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
bool DiagnoseErrors);
+/// Parse -f(no-)?sanitize-metadata= flag values, diagnosing any invalid
+/// components. Returns OR of members of \c BinaryMetadataFeature enumeration.
+static int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors);
+
/// Produce an argument string from ArgList \p Args, which shows how it
/// provides some sanitizer kind from \p Mask. For example, the argument list
/// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
@@ -236,7 +250,7 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
SanitizerSet S;
S.Mask = InvalidValues;
D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << toString(S);
+ << Arg->getSpelling() << toString(S);
}
TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove;
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) {
@@ -591,7 +605,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SetToDiagnose.Mask |= KindsToDiagnose;
if (DiagnoseErrors)
D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << toString(SetToDiagnose);
+ << Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedUnrecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds |= expandSanitizerGroups(Add);
@@ -606,7 +620,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SetToDiagnose.Mask |= KindsToDiagnose;
if (DiagnoseErrors)
D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << toString(SetToDiagnose);
+ << Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds &= ~expandSanitizerGroups(Remove);
@@ -636,14 +650,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
if (AllAddedKinds & SanitizerKind::Memory) {
if (Arg *A =
Args.getLastArg(options::OPT_fsanitize_memory_track_origins_EQ,
- options::OPT_fsanitize_memory_track_origins,
options::OPT_fno_sanitize_memory_track_origins)) {
- if (A->getOption().matches(options::OPT_fsanitize_memory_track_origins)) {
- MsanTrackOrigins = 2;
- } else if (A->getOption().matches(
- options::OPT_fno_sanitize_memory_track_origins)) {
- MsanTrackOrigins = 0;
- } else {
+ if (!A->getOption().matches(
+ options::OPT_fno_sanitize_memory_track_origins)) {
StringRef S = A->getValue();
if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
MsanTrackOrigins > 2) {
@@ -712,6 +721,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
options::OPT_fno_sanitize_cfi_canonical_jump_tables, true);
}
+ if (AllAddedKinds & SanitizerKind::KCFI && DiagnoseErrors) {
+ if (AllAddedKinds & SanitizerKind::CFI)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fsanitize=kcfi"
+ << lastArgumentForMask(D, Args, SanitizerKind::CFI);
+ }
+
Stats = Args.hasFlag(options::OPT_fsanitize_stats,
options::OPT_fno_sanitize_stats, false);
@@ -789,19 +805,21 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge;
int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard |
CoverageInline8bitCounters | CoverageTraceLoads |
- CoverageTraceStores | CoverageInlineBoolFlag;
+ CoverageTraceStores | CoverageInlineBoolFlag |
+ CoverageControlFlow;
if ((CoverageFeatures & InsertionPointTypes) &&
!(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) {
D.Diag(clang::diag::warn_drv_deprecated_arg)
<< "-fsanitize-coverage=[func|bb|edge]"
- << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]";
+ << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],["
+ "control-flow]";
}
// trace-pc w/o func/bb/edge implies edge.
if (!(CoverageFeatures & InsertionPointTypes)) {
if (CoverageFeatures &
(CoverageTracePC | CoverageTracePCGuard | CoverageInline8bitCounters |
- CoverageInlineBoolFlag))
+ CoverageInlineBoolFlag | CoverageControlFlow))
CoverageFeatures |= CoverageEdge;
if (CoverageFeatures & CoverageStackDepth)
@@ -825,6 +843,22 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
DiagnoseErrors);
}
+ // Parse -f(no-)?sanitize-metadata.
+ for (const auto *Arg :
+ Args.filtered(options::OPT_fexperimental_sanitize_metadata_EQ,
+ options::OPT_fno_experimental_sanitize_metadata_EQ)) {
+ if (Arg->getOption().matches(
+ options::OPT_fexperimental_sanitize_metadata_EQ)) {
+ Arg->claim();
+ BinaryMetadataFeatures |=
+ parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
+ } else {
+ Arg->claim();
+ BinaryMetadataFeatures &=
+ ~parseBinaryMetadataFeatures(D, Arg, DiagnoseErrors);
+ }
+ }
+
SharedRuntime =
Args.hasFlag(options::OPT_shared_libsan, options::OPT_static_libsan,
TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia() ||
@@ -885,10 +919,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
!TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSFuchsia() ||
TC.getTriple().isPS());
+ // Enable ODR indicators which allow better handling of mixed instrumented
+ // and uninstrumented globals. Disable them for Windows where weak odr
+ // indicators (.weak.__odr_asan_gen*) may cause multiple definition linker
+ // errors in the absence of -lldmingw.
AsanUseOdrIndicator =
Args.hasFlag(options::OPT_fsanitize_address_use_odr_indicator,
options::OPT_fno_sanitize_address_use_odr_indicator,
- AsanUseOdrIndicator);
+ !TC.getTriple().isOSWindows());
if (AllAddedKinds & SanitizerKind::PointerCompare & ~AllRemove) {
AsanInvalidPointerCmp = true;
@@ -909,7 +947,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
auto parsedAsanDtorKind = AsanDtorKindFromString(Arg->getValue());
if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid && DiagnoseErrors) {
TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << Arg->getValue();
+ << Arg->getSpelling() << Arg->getValue();
}
AsanDtorKind = parsedAsanDtorKind;
}
@@ -922,7 +960,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
llvm::AsanDetectStackUseAfterReturnMode::Invalid &&
DiagnoseErrors) {
TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << Arg->getValue();
+ << Arg->getSpelling() << Arg->getValue();
}
AsanUseAfterReturn = parsedAsanUseAfterReturn;
}
@@ -1076,7 +1114,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"),
std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth"),
std::make_pair(CoverageTraceLoads, "-fsanitize-coverage-trace-loads"),
- std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores")};
+ std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores"),
+ std::make_pair(CoverageControlFlow, "-fsanitize-coverage-control-flow")};
for (auto F : CoverageFlags) {
if (CoverageFeatures & F.first)
CmdArgs.push_back(F.second);
@@ -1086,6 +1125,18 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-coverage-ignorelist=",
CoverageIgnorelistFiles);
+ // Translate available BinaryMetadataFeatures to corresponding clang-cc1
+ // flags. Does not depend on any other sanitizers.
+ const std::pair<int, std::string> BinaryMetadataFlags[] = {
+ std::make_pair(BinaryMetadataCovered, "covered"),
+ std::make_pair(BinaryMetadataAtomics, "atomics"),
+ std::make_pair(BinaryMetadataUAR, "uar")};
+ for (const auto &F : BinaryMetadataFlags) {
+ if (BinaryMetadataFeatures & F.first)
+ CmdArgs.push_back(
+ Args.MakeArgString("-fexperimental-sanitize-metadata=" + F.second));
+ }
+
if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
// Instruct the code generator to embed linker directives in the object file
// that cause the required runtime libraries to be linked.
@@ -1134,8 +1185,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (MsanUseAfterDtor)
CmdArgs.push_back("-fsanitize-memory-use-after-dtor");
- if (MsanParamRetval)
- CmdArgs.push_back("-fsanitize-memory-param-retval");
+ if (!MsanParamRetval)
+ CmdArgs.push_back("-fno-sanitize-memory-param-retval");
// FIXME: Pass these parameters as function attributes, not as -llvm flags.
if (!TsanMemoryAccess) {
@@ -1186,8 +1237,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (AsanGlobalsDeadStripping)
CmdArgs.push_back("-fsanitize-address-globals-dead-stripping");
- if (AsanUseOdrIndicator)
- CmdArgs.push_back("-fsanitize-address-use-odr-indicator");
+ if (!AsanUseOdrIndicator)
+ CmdArgs.push_back("-fno-sanitize-address-use-odr-indicator");
if (AsanInvalidPointerCmp) {
CmdArgs.push_back("-mllvm");
@@ -1292,7 +1343,7 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
Kinds |= Kind;
else if (DiagnoseErrors)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
return Kinds;
}
@@ -1323,10 +1374,34 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A,
.Case("stack-depth", CoverageStackDepth)
.Case("trace-loads", CoverageTraceLoads)
.Case("trace-stores", CoverageTraceStores)
+ .Case("control-flow", CoverageControlFlow)
+ .Default(0);
+ if (F == 0 && DiagnoseErrors)
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Value;
+ Features |= F;
+ }
+ return Features;
+}
+
+int parseBinaryMetadataFeatures(const Driver &D, const llvm::opt::Arg *A,
+ bool DiagnoseErrors) {
+ assert(
+ A->getOption().matches(options::OPT_fexperimental_sanitize_metadata_EQ) ||
+ A->getOption().matches(
+ options::OPT_fno_experimental_sanitize_metadata_EQ));
+ int Features = 0;
+ for (int i = 0, n = A->getNumValues(); i != n; ++i) {
+ const char *Value = A->getValue(i);
+ int F = llvm::StringSwitch<int>(Value)
+ .Case("covered", BinaryMetadataCovered)
+ .Case("atomics", BinaryMetadataAtomics)
+ .Case("uar", BinaryMetadataUAR)
+ .Case("all", ~0)
.Default(0);
if (F == 0 && DiagnoseErrors)
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
Features |= F;
}
return Features;
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 7a4319ea680f..bc70205a6c01 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -36,6 +36,7 @@
#include "llvm/Option/Option.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/VersionTuple.h"
@@ -88,6 +89,33 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
addIfExists(getFilePaths(), getArchSpecificLibPath());
}
+llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
+ToolChain::executeToolChainProgram(StringRef Executable) const {
+ llvm::SmallString<64> OutputFile;
+ llvm::sys::fs::createTemporaryFile("toolchain-program", "txt", OutputFile);
+ llvm::FileRemover OutputRemover(OutputFile.c_str());
+ std::optional<llvm::StringRef> Redirects[] = {
+ {""},
+ OutputFile.str(),
+ {""},
+ };
+
+ std::string ErrorMessage;
+ if (llvm::sys::ExecuteAndWait(Executable, {}, {}, Redirects,
+ /* SecondsToWait */ 0,
+ /*MemoryLimit*/ 0, &ErrorMessage))
+ return llvm::createStringError(std::error_code(),
+ Executable + ": " + ErrorMessage);
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf =
+ llvm::MemoryBuffer::getFile(OutputFile.c_str());
+ if (!OutputBuf)
+ return llvm::createStringError(OutputBuf.getError(),
+ "Failed to read stdout of " + Executable +
+ ": " + OutputBuf.getError().message());
+ return std::move(*OutputBuf);
+}
+
void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) {
Triple.setEnvironment(Env);
if (EffectiveTriple != llvm::Triple())
@@ -150,9 +178,9 @@ ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const {
}
const XRayArgs& ToolChain::getXRayArgs() const {
- if (!XRayArguments.get())
+ if (!XRayArguments)
XRayArguments.reset(new XRayArgs(*this, Args));
- return *XRayArguments.get();
+ return *XRayArguments;
}
namespace {
@@ -185,11 +213,11 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
{"clang-dxc", "--driver-mode=dxc"},
};
- for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) {
- StringRef Suffix(DriverSuffixes[i].Suffix);
+ for (const auto &DS : DriverSuffixes) {
+ StringRef Suffix(DS.Suffix);
if (ProgName.endswith(Suffix)) {
Pos = ProgName.size() - Suffix.size();
- return &DriverSuffixes[i];
+ return &DS;
}
}
return nullptr;
@@ -198,7 +226,7 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
/// Normalize the program name from argv[0] by stripping the file extension if
/// present and lower-casing the string on Windows.
static std::string normalizeProgramName(llvm::StringRef Argv0) {
- std::string ProgName = std::string(llvm::sys::path::stem(Argv0));
+ std::string ProgName = std::string(llvm::sys::path::filename(Argv0));
if (is_style_windows(llvm::sys::path::Style::native)) {
// Transform to lowercase for case insensitive file systems.
std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(),
@@ -217,6 +245,13 @@ static const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) {
// added via -target as implicit first argument.
const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos);
+ if (!DS && ProgName.endswith(".exe")) {
+ // Try again after stripping the executable suffix:
+ // clang++.exe -> clang++
+ ProgName = ProgName.drop_back(StringRef(".exe").size());
+ DS = FindDriverSuffix(ProgName, Pos);
+ }
+
if (!DS) {
// Try again after stripping any trailing version number:
// clang++3.5 -> clang++
@@ -287,8 +322,9 @@ std::string ToolChain::getInputFilename(const InputInfo &Input) const {
return Input.getFilename();
}
-bool ToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
- return false;
+ToolChain::UnwindTableLevel
+ToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
+ return UnwindTableLevel::None;
}
Tool *ToolChain::getClang() const {
@@ -351,12 +387,6 @@ Tool *ToolChain::getOffloadBundler() const {
return OffloadBundler.get();
}
-Tool *ToolChain::getOffloadWrapper() const {
- if (!OffloadWrapper)
- OffloadWrapper.reset(new tools::OffloadWrapper(*this));
- return OffloadWrapper.get();
-}
-
Tool *ToolChain::getOffloadPackager() const {
if (!OffloadPackager)
OffloadPackager.reset(new tools::OffloadPackager(*this));
@@ -393,7 +423,6 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::CompileJobClass:
case Action::PrecompileJobClass:
- case Action::HeaderModulePrecompileJobClass:
case Action::PreprocessJobClass:
case Action::ExtractAPIJobClass:
case Action::AnalyzeJobClass:
@@ -406,8 +435,6 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::OffloadUnbundlingJobClass:
return getOffloadBundler();
- case Action::OffloadWrapperJobClass:
- return getOffloadWrapper();
case Action::OffloadPackagerJobClass:
return getOffloadPackager();
case Action::LinkerWrapperJobClass:
@@ -422,6 +449,9 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC,
const llvm::Triple &Triple = TC.getTriple();
bool IsWindows = Triple.isOSWindows();
+ if (TC.isBareMetal())
+ return Triple.getArchName();
+
if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb)
return (arm::getARMFloatABI(TC, Args) == arm::FloatABI::Hard && !IsWindows)
? "armhf"
@@ -459,7 +489,10 @@ StringRef ToolChain::getOSLibName() const {
std::string ToolChain::getCompilerRTPath() const {
SmallString<128> Path(getDriver().ResourceDir);
- if (Triple.isOSUnknown()) {
+ if (isBareMetal()) {
+ llvm::sys::path::append(Path, "lib", getOSLibName());
+ Path += SelectedMultilib.gccSuffix();
+ } else if (Triple.isOSUnknown()) {
llvm::sys::path::append(Path, "lib");
} else {
llvm::sys::path::append(Path, "lib", getOSLibName());
@@ -622,13 +655,18 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD) const {
// --ld-path= takes precedence over -fuse-ld= and specifies the executable
// name. -B, COMPILER_PATH and PATH and consulted if the value does not
// contain a path component separator.
+ // -fuse-ld=lld can be used with --ld-path= to inform clang that the binary
+ // that --ld-path= points to is lld.
if (const Arg *A = Args.getLastArg(options::OPT_ld_path_EQ)) {
std::string Path(A->getValue());
if (!Path.empty()) {
if (llvm::sys::path::parent_path(Path).empty())
Path = GetProgramPath(A->getValue());
- if (llvm::sys::fs::can_execute(Path))
+ if (llvm::sys::fs::can_execute(Path)) {
+ if (LinkerIsLLD)
+ *LinkerIsLLD = UseLinker == "lld";
return std::string(Path);
+ }
}
getDriver().Diag(diag::err_drv_invalid_linker_name) << A->getAsString(Args);
return GetProgramPath(getDefaultLinker());
@@ -805,6 +843,9 @@ void ToolChain::addClangTargetOptions(
const ArgList &DriverArgs, ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const {}
+void ToolChain::addClangCC1ASTargetOptions(const ArgList &Args,
+ ArgStringList &CC1ASArgs) const {}
+
void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {}
void ToolChain::addProfileRTLibs(const llvm::opt::ArgList &Args,
@@ -991,8 +1032,15 @@ void ToolChain::AddClangCXXStdlibIsystemArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
DriverArgs.ClaimAllArgs(options::OPT_stdlibxx_isystem);
- if (!DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdincxx,
- options::OPT_nostdlibinc))
+ // This intentionally only looks at -nostdinc++, and not -nostdinc or
+ // -nostdlibinc. The purpose of -stdlib++-isystem is to support toolchain
+ // setups with non-standard search logic for the C++ headers, while still
+ // allowing users of the toolchain to bring their own C++ headers. Such a
+ // toolchain likely also has non-standard search logic for the C headers and
+ // uses -nostdinc to suppress the default logic, but -stdlib++-isystem should
+ // still work in that case and only be suppressed by an explicit -nostdinc++
+ // in a project using the toolchain.
+ if (!DriverArgs.hasArg(options::OPT_nostdincxx))
for (const auto &P :
DriverArgs.getAllArgValues(options::OPT_stdlibxx_isystem))
addSystemInclude(DriverArgs, CC1Args, P);
@@ -1066,6 +1114,11 @@ bool ToolChain::addFastMathRuntimeIfAvailable(const ArgList &Args,
return false;
}
+Expected<SmallVector<std::string>>
+ToolChain::getSystemGPUArchs(const llvm::opt::ArgList &Args) const {
+ return SmallVector<std::string>();
+}
+
SanitizerMask ToolChain::getSupportedSanitizers() const {
// Return sanitizers which don't require runtime support and are not
// platform dependent.
@@ -1075,7 +1128,7 @@ SanitizerMask ToolChain::getSupportedSanitizers() const {
~SanitizerKind::Function) |
(SanitizerKind::CFI & ~SanitizerKind::CFIICall) |
SanitizerKind::CFICastStrict | SanitizerKind::FloatDivideByZero |
- SanitizerKind::UnsignedIntegerOverflow |
+ SanitizerKind::KCFI | SanitizerKind::UnsignedIntegerOverflow |
SanitizerKind::UnsignedShiftBase | SanitizerKind::ImplicitConversion |
SanitizerKind::Nullability | SanitizerKind::LocalBounds;
if (getTriple().getArch() == llvm::Triple::x86 ||
@@ -1098,7 +1151,7 @@ void ToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {}
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
-ToolChain::getHIPDeviceLibs(const ArgList &DriverArgs) const {
+ToolChain::getDeviceLibs(const ArgList &DriverArgs) const {
return {};
}
@@ -1280,17 +1333,17 @@ llvm::opt::DerivedArgList *ToolChain::TranslateXarchArgs(
DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
bool Modified = false;
- bool IsGPU = OFK == Action::OFK_Cuda || OFK == Action::OFK_HIP;
+ bool IsDevice = OFK != Action::OFK_None && OFK != Action::OFK_Host;
for (Arg *A : Args) {
bool NeedTrans = false;
bool Skip = false;
if (A->getOption().matches(options::OPT_Xarch_device)) {
- NeedTrans = IsGPU;
- Skip = !IsGPU;
+ NeedTrans = IsDevice;
+ Skip = !IsDevice;
} else if (A->getOption().matches(options::OPT_Xarch_host)) {
- NeedTrans = !IsGPU;
- Skip = IsGPU;
- } else if (A->getOption().matches(options::OPT_Xarch__) && IsGPU) {
+ NeedTrans = !IsDevice;
+ Skip = IsDevice;
+ } else if (A->getOption().matches(options::OPT_Xarch__) && IsDevice) {
// Do not translate -Xarch_ options for non CUDA/HIP toolchain since
// they may need special translation.
// Skip this argument unless the architecture matches BoundArch
diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp
index 64be5fe23558..abbd3ef6c68f 100644
--- a/clang/lib/Driver/ToolChains/AIX.cpp
+++ b/clang/lib/Driver/ToolChains/AIX.cpp
@@ -13,6 +13,7 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/ProfileData/InstrProf.h"
#include "llvm/Support/Path.h"
using AIX = clang::driver::toolchains::AIX;
@@ -74,6 +75,29 @@ void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
Exec, CmdArgs, Inputs, Output));
}
+// Determine whether there are any linker options that supply an export list
+// (or equivalent information about what to export) being sent to the linker.
+static bool hasExportListLinkerOpts(const ArgStringList &CmdArgs) {
+ for (size_t i = 0, Size = CmdArgs.size(); i < Size; ++i) {
+ llvm::StringRef ArgString(CmdArgs[i]);
+
+ if (ArgString.startswith("-bE:") || ArgString.startswith("-bexport:") ||
+ ArgString == "-bexpall" || ArgString == "-bexpfull")
+ return true;
+
+ // If we split -b option, check the next opt.
+ if (ArgString == "-b" && i + 1 < Size) {
+ ++i;
+ llvm::StringRef ArgNextString(CmdArgs[i]);
+ if (ArgNextString.startswith("E:") ||
+ ArgNextString.startswith("export:") || ArgNextString == "expall" ||
+ ArgNextString == "expfull")
+ return true;
+ }
+ }
+ return false;
+}
+
void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs, const ArgList &Args,
@@ -168,6 +192,46 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Specify linker input file(s).
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+ if (D.isUsingLTO()) {
+ assert(!Inputs.empty() && "Must have at least one input.");
+ addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
+ D.getLTOMode() == LTOK_Thin);
+ }
+
+ if (Args.hasArg(options::OPT_shared) && !hasExportListLinkerOpts(CmdArgs)) {
+
+ const char *CreateExportListExec = Args.MakeArgString(
+ path::parent_path(ToolChain.getDriver().ClangExecutable) +
+ "/llvm-nm");
+ ArgStringList CreateExportCmdArgs;
+
+ std::string CreateExportListPath =
+ C.getDriver().GetTemporaryPath("CreateExportList", "exp");
+ const char *ExportList =
+ C.addTempFile(C.getArgs().MakeArgString(CreateExportListPath));
+
+ for (const auto &II : Inputs)
+ if (II.isFilename())
+ CreateExportCmdArgs.push_back(II.getFilename());
+
+ CreateExportCmdArgs.push_back("--export-symbols");
+ CreateExportCmdArgs.push_back("-X");
+ if (IsArch32Bit) {
+ CreateExportCmdArgs.push_back("32");
+ } else {
+ // Must be 64-bit, otherwise asserted already.
+ CreateExportCmdArgs.push_back("64");
+ }
+
+ auto ExpCommand = std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::None(), CreateExportListExec,
+ CreateExportCmdArgs, Inputs, Output);
+ ExpCommand->setRedirectFiles(
+ {std::nullopt, std::string(ExportList), std::nullopt});
+ C.addCommand(std::move(ExpCommand));
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-bE:") + ExportList));
+ }
+
// Add directory to library search path.
Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
@@ -179,6 +243,25 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
+ // Add OpenMP runtime if -fopenmp is specified.
+ if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
+ options::OPT_fno_openmp, false)) {
+ switch (ToolChain.getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
+ CmdArgs.push_back("-lomp");
+ break;
+ case Driver::OMPRT_IOMP5:
+ CmdArgs.push_back("-liomp5");
+ break;
+ case Driver::OMPRT_GOMP:
+ CmdArgs.push_back("-lgomp");
+ break;
+ case Driver::OMPRT_Unknown:
+ // Already diagnosed.
+ break;
+ }
+ }
+
// Support POSIX threads if "-pthreads" or "-pthread" is present.
if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread))
CmdArgs.push_back("-lpthreads");
@@ -187,6 +270,13 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lm");
CmdArgs.push_back("-lc");
+
+ if (Args.hasArg(options::OPT_pg)) {
+ CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
+ "/lib/profiled"));
+ CmdArgs.push_back(Args.MakeArgString((llvm::Twine("-L") + D.SysRoot) +
+ "/usr/lib/profiled"));
+ }
}
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
@@ -286,6 +376,16 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm_unreachable("Unexpected C++ library type; only libc++ is supported.");
}
+void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const {
+ // Add linker option -u__llvm_profile_runtime to cause runtime
+ // initialization to occur.
+ if (needsProfileRT(Args))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-u", llvm::getInstrProfRuntimeHookVarName())));
+ ToolChain::addProfileRTLibs(Args, CmdArgs);
+}
+
ToolChain::CXXStdlibType AIX::GetDefaultCXXStdlibType() const {
return ToolChain::CST_Libcxx;
}
diff --git a/clang/lib/Driver/ToolChains/AIX.h b/clang/lib/Driver/ToolChains/AIX.h
index e7ec3a5ece4d..e03aebcc3e7f 100644
--- a/clang/lib/Driver/ToolChains/AIX.h
+++ b/clang/lib/Driver/ToolChains/AIX.h
@@ -67,6 +67,7 @@ public:
return false;
}
bool isPICDefaultForced() const override { return true; }
+ bool HasNativeLLVMSupport() const override { return true; }
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
@@ -79,6 +80,9 @@ public:
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
+ void addProfileRTLibs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
+
CXXStdlibType GetDefaultCXXStdlibType() const override;
RuntimeLibType GetDefaultRuntimeLibType() const override;
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index 8718ab53ac1a..5849e9cfdb9b 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -9,20 +9,22 @@
#include "AMDGPU.h"
#include "CommonArgs.h"
#include "clang/Basic/TargetID.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Distro.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/VirtualFileSystem.h"
+#include <optional>
#include <system_error>
-#define AMDGPU_ARCH_PROGRAM_NAME "amdgpu-arch"
-
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
@@ -197,9 +199,10 @@ RocmInstallationDetector::getInstallationPathCandidates() {
ROCmSearchDirs.emplace_back(RocmPathArg.str());
DoPrintROCmSearchDirs();
return ROCmSearchDirs;
- } else if (const char *RocmPathEnv = ::getenv("ROCM_PATH")) {
- if (!StringRef(RocmPathEnv).empty()) {
- ROCmSearchDirs.emplace_back(RocmPathEnv);
+ } else if (std::optional<std::string> RocmPathEnv =
+ llvm::sys::Process::GetEnv("ROCM_PATH")) {
+ if (!RocmPathEnv->empty()) {
+ ROCmSearchDirs.emplace_back(std::move(*RocmPathEnv));
DoPrintROCmSearchDirs();
return ROCmSearchDirs;
}
@@ -306,6 +309,14 @@ RocmInstallationDetector::getInstallationPathCandidates() {
ROCmSearchDirs.emplace_back(D.SysRoot + "/opt/" + LatestROCm,
/*StrictChecking=*/true);
+ Distro Dist(D.getVFS(), llvm::Triple(llvm::sys::getProcessTriple()));
+ if (Dist.IsDebian() || Dist.IsRedhat()) {
+ ROCmSearchDirs.emplace_back(D.SysRoot + "/usr/local",
+ /*StrictChecking=*/true);
+ ROCmSearchDirs.emplace_back(D.SysRoot + "/usr",
+ /*StrictChecking=*/true);
+ }
+
DoPrintROCmSearchDirs();
return ROCmSearchDirs;
}
@@ -364,8 +375,9 @@ void RocmInstallationDetector::detectDeviceLibrary() {
if (!RocmDeviceLibPathArg.empty())
LibDevicePath = RocmDeviceLibPathArg[RocmDeviceLibPathArg.size() - 1];
- else if (const char *LibPathEnv = ::getenv("HIP_DEVICE_LIB_PATH"))
- LibDevicePath = LibPathEnv;
+ else if (std::optional<std::string> LibPathEnv =
+ llvm::sys::Process::GetEnv("HIP_DEVICE_LIB_PATH"))
+ LibDevicePath = std::move(*LibPathEnv);
auto &FS = D.getVFS();
if (!LibDevicePath.empty()) {
@@ -380,61 +392,44 @@ void RocmInstallationDetector::detectDeviceLibrary() {
return;
}
- // The install path situation in old versions of ROCm is a real mess, and
- // use a different install layout. Multiple copies of the device libraries
- // exist for each frontend project, and differ depending on which build
- // system produced the packages. Standalone OpenCL builds also have a
- // different directory structure from the ROCm OpenCL package.
- auto &ROCmDirs = getInstallationPathCandidates();
- for (const auto &Candidate : ROCmDirs) {
- auto CandidatePath = Candidate.Path;
+ // Check device library exists at the given path.
+ auto CheckDeviceLib = [&](StringRef Path, bool StrictChecking) {
+ bool CheckLibDevice = (!NoBuiltinLibs || StrictChecking);
+ if (CheckLibDevice && !FS.exists(Path))
+ return false;
+
+ scanLibDevicePath(Path);
- // Check device library exists at the given path.
- auto CheckDeviceLib = [&](StringRef Path) {
- bool CheckLibDevice = (!NoBuiltinLibs || Candidate.StrictChecking);
- if (CheckLibDevice && !FS.exists(Path))
+ if (!NoBuiltinLibs) {
+ // Check that the required non-target libraries are all available.
+ if (!allGenericLibsValid())
return false;
- scanLibDevicePath(Path);
+ // Check that we have found at least one libdevice that we can link in
+ // if -nobuiltinlib hasn't been specified.
+ if (LibDeviceMap.empty())
+ return false;
+ }
+ return true;
+ };
- if (!NoBuiltinLibs) {
- // Check that the required non-target libraries are all available.
- if (!allGenericLibsValid())
- return false;
+ // Find device libraries in <LLVM_DIR>/lib/clang/<ver>/lib/amdgcn/bitcode
+ LibDevicePath = D.ResourceDir;
+ llvm::sys::path::append(LibDevicePath, CLANG_INSTALL_LIBDIR_BASENAME,
+ "amdgcn", "bitcode");
+ HasDeviceLibrary = CheckDeviceLib(LibDevicePath, true);
+ if (HasDeviceLibrary)
+ return;
- // Check that we have found at least one libdevice that we can link in
- // if -nobuiltinlib hasn't been specified.
- if (LibDeviceMap.empty())
- return false;
- }
- return true;
- };
-
- // The possible structures are:
- // - ${ROCM_ROOT}/amdgcn/bitcode/*
- // - ${ROCM_ROOT}/lib/*
- // - ${ROCM_ROOT}/lib/bitcode/*
- // so try to detect these layouts.
- static constexpr std::array<const char *, 2> SubDirsList[] = {
- {"amdgcn", "bitcode"},
- {"lib", ""},
- {"lib", "bitcode"},
- };
-
- // Make a path by appending sub-directories to InstallPath.
- auto MakePath = [&](const llvm::ArrayRef<const char *> &SubDirs) {
- auto Path = CandidatePath;
- for (auto SubDir : SubDirs)
- llvm::sys::path::append(Path, SubDir);
- return Path;
- };
-
- for (auto SubDirs : SubDirsList) {
- LibDevicePath = MakePath(SubDirs);
- HasDeviceLibrary = CheckDeviceLib(LibDevicePath);
- if (HasDeviceLibrary)
- return;
- }
+ // Find device libraries in a legacy ROCm directory structure
+ // ${ROCM_ROOT}/amdgcn/bitcode/*
+ auto &ROCmDirs = getInstallationPathCandidates();
+ for (const auto &Candidate : ROCmDirs) {
+ LibDevicePath = Candidate.Path;
+ llvm::sys::path::append(LibDevicePath, "amdgcn", "bitcode");
+ HasDeviceLibrary = CheckDeviceLib(LibDevicePath, Candidate.StrictChecking);
+ if (HasDeviceLibrary)
+ return;
}
}
@@ -461,18 +456,30 @@ void RocmInstallationDetector::detectHIPRuntime() {
llvm::sys::path::append(IncludePath, "include");
LibPath = InstallPath;
llvm::sys::path::append(LibPath, "lib");
-
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
- FS.getBufferForFile(BinPath + "/.hipVersion");
- if (!VersionFile && Candidate.StrictChecking)
- continue;
-
- if (HIPVersionArg.empty() && VersionFile)
- if (parseHIPVersionFile((*VersionFile)->getBuffer()))
+ SharePath = InstallPath;
+ llvm::sys::path::append(SharePath, "share");
+
+ // If HIP version file can be found and parsed, use HIP version from there.
+ for (const auto &VersionFilePath :
+ {std::string(SharePath) + "/hip/version",
+ std::string(BinPath) + "/.hipVersion"}) {
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile =
+ FS.getBufferForFile(VersionFilePath);
+ if (!VersionFile)
continue;
+ if (HIPVersionArg.empty() && VersionFile)
+ if (parseHIPVersionFile((*VersionFile)->getBuffer()))
+ continue;
- HasHIPRuntime = true;
- return;
+ HasHIPRuntime = true;
+ return;
+ }
+ // Otherwise, if -rocm-path is specified (no strict checking), use the
+ // default HIP version or specified by --hip-version.
+ if (!Candidate.StrictChecking) {
+ HasHIPRuntime = true;
+ return;
+ }
}
HasHIPRuntime = false;
}
@@ -707,8 +714,7 @@ void AMDGPUToolChain::addClangTargetOptions(
// supported for the foreseeable future.
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
- CC1Args.push_back("-fvisibility");
- CC1Args.push_back("hidden");
+ CC1Args.push_back("-fvisibility=hidden");
CC1Args.push_back("-fapply-global-visibility-to-externs");
}
}
@@ -723,12 +729,12 @@ AMDGPUToolChain::ParsedTargetIDType
AMDGPUToolChain::getParsedTargetID(const llvm::opt::ArgList &DriverArgs) const {
StringRef TargetID = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ);
if (TargetID.empty())
- return {None, None, None};
+ return {std::nullopt, std::nullopt, std::nullopt};
llvm::StringMap<bool> FeatureMap;
auto OptionalGpuArch = parseTargetID(getTriple(), TargetID, &FeatureMap);
if (!OptionalGpuArch)
- return {TargetID.str(), None, None};
+ return {TargetID.str(), std::nullopt, std::nullopt};
return {TargetID.str(), OptionalGpuArch->str(), FeatureMap};
}
@@ -742,76 +748,29 @@ void AMDGPUToolChain::checkTargetID(
}
}
-llvm::Error
-AMDGPUToolChain::detectSystemGPUs(const ArgList &Args,
- SmallVector<std::string, 1> &GPUArchs) const {
+Expected<SmallVector<std::string>>
+AMDGPUToolChain::getSystemGPUArchs(const ArgList &Args) const {
+ // Detect AMD GPUs availible on the system.
std::string Program;
if (Arg *A = Args.getLastArg(options::OPT_amdgpu_arch_tool_EQ))
Program = A->getValue();
else
- Program = GetProgramPath(AMDGPU_ARCH_PROGRAM_NAME);
- llvm::SmallString<64> OutputFile;
- llvm::sys::fs::createTemporaryFile("print-system-gpus", "" /* No Suffix */,
- OutputFile);
- llvm::FileRemover OutputRemover(OutputFile.c_str());
- llvm::Optional<llvm::StringRef> Redirects[] = {
- {""},
- OutputFile.str(),
- {""},
- };
+ Program = GetProgramPath("amdgpu-arch");
- std::string ErrorMessage;
- if (int Result = llvm::sys::ExecuteAndWait(
- Program, {}, {}, Redirects, /* SecondsToWait */ 0,
- /*MemoryLimit*/ 0, &ErrorMessage)) {
- if (Result > 0) {
- ErrorMessage = "Exited with error code " + std::to_string(Result);
- } else if (Result == -1) {
- ErrorMessage = "Execute failed: " + ErrorMessage;
- } else {
- ErrorMessage = "Crashed: " + ErrorMessage;
- }
-
- return llvm::createStringError(std::error_code(),
- Program + ": " + ErrorMessage);
- }
+ auto StdoutOrErr = executeToolChainProgram(Program);
+ if (!StdoutOrErr)
+ return StdoutOrErr.takeError();
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> OutputBuf =
- llvm::MemoryBuffer::getFile(OutputFile.c_str());
- if (!OutputBuf) {
- return llvm::createStringError(OutputBuf.getError(),
- "Failed to read stdout of " + Program +
- ": " + OutputBuf.getError().message());
- }
-
- for (llvm::line_iterator LineIt(**OutputBuf); !LineIt.is_at_end(); ++LineIt) {
- GPUArchs.push_back(LineIt->str());
- }
- return llvm::Error::success();
-}
-
-llvm::Error AMDGPUToolChain::getSystemGPUArch(const ArgList &Args,
- std::string &GPUArch) const {
- // detect the AMDGPU installed in system
SmallVector<std::string, 1> GPUArchs;
- auto Err = detectSystemGPUs(Args, GPUArchs);
- if (Err) {
- return Err;
- }
- if (GPUArchs.empty()) {
+ for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n"))
+ if (!Arch.empty())
+ GPUArchs.push_back(Arch.str());
+
+ if (GPUArchs.empty())
return llvm::createStringError(std::error_code(),
"No AMD GPU detected in the system");
- }
- GPUArch = GPUArchs[0];
- if (GPUArchs.size() > 1) {
- bool AllSame = llvm::all_of(GPUArchs, [&](const StringRef &GPUArch) {
- return GPUArch == GPUArchs.front();
- });
- if (!AllSame)
- return llvm::createStringError(
- std::error_code(), "Multiple AMD GPUs found with different archs");
- }
- return llvm::Error::success();
+
+ return std::move(GPUArchs);
}
void ROCMToolChain::addClangTargetOptions(
@@ -833,7 +792,7 @@ void ROCMToolChain::addClangTargetOptions(
const StringRef GpuArch = getGPUArch(DriverArgs);
auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch);
const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);
- std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
+ StringRef LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion(
getAMDGPUCodeObjectVersion(getDriver(), DriverArgs));
if (!RocmInstallation.checkCommonBitcodeLibs(CanonArch, LibDeviceFile,
@@ -925,7 +884,7 @@ ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs,
auto Kind = llvm::AMDGPU::parseArchAMDGCN(GPUArch);
const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind);
- std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
+ StringRef LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch);
auto ABIVer = DeviceLibABIVersion::fromCodeObjectVersion(
getAMDGPUCodeObjectVersion(getDriver(), DriverArgs));
if (!RocmInstallation.checkCommonBitcodeLibs(CanonArch, LibDeviceFile,
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h
index ddcc124b25ba..cce70da6612b 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.h
+++ b/clang/lib/Driver/ToolChains/AMDGPU.h
@@ -61,10 +61,8 @@ public:
AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
unsigned GetDefaultDwarfVersion() const override { return 5; }
- bool IsIntegratedAssemblerDefault() const override { return true; }
- bool IsMathErrnoDefault() const override { return false; }
- bool useIntegratedAs() const override { return true; }
+ bool IsMathErrnoDefault() const override { return false; }
bool isCrossCompiling() const override { return true; }
bool isPICDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
@@ -102,10 +100,10 @@ public:
/// Should skip argument.
bool shouldSkipArgument(const llvm::opt::Arg *Arg) const;
- /// Uses amdgpu_arch tool to get arch of the system GPU. Will return error
+ /// Uses amdgpu-arch tool to get arch of the system GPU. Will return error
/// if unable to find one.
- llvm::Error getSystemGPUArch(const llvm::opt::ArgList &Args,
- std::string &GPUArch) const;
+ virtual Expected<SmallVector<std::string>>
+ getSystemGPUArchs(const llvm::opt::ArgList &Args) const override;
protected:
/// Check and diagnose invalid target ID specified by -mcpu.
@@ -113,9 +111,9 @@ protected:
/// The struct type returned by getParsedTargetID.
struct ParsedTargetIDType {
- Optional<std::string> OptionalTargetID;
- Optional<std::string> OptionalGPUArch;
- Optional<llvm::StringMap<bool>> OptionalFeatures;
+ std::optional<std::string> OptionalTargetID;
+ std::optional<std::string> OptionalGPUArch;
+ std::optional<llvm::StringMap<bool>> OptionalFeatures;
};
/// Get target ID, GPU arch, and target ID features if the target ID is
@@ -126,8 +124,6 @@ protected:
/// Get GPU arch from -mcpu without checking.
StringRef getGPUArch(const llvm::opt::ArgList &DriverArgs) const;
- llvm::Error detectSystemGPUs(const llvm::opt::ArgList &Args,
- SmallVector<std::string, 1> &GPUArchs) const;
};
class LLVM_LIBRARY_VISIBILITY ROCMToolChain : public AMDGPUToolChain {
diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
index efcd565b510b..1a8e4294713c 100644
--- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp
@@ -29,230 +29,6 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-namespace {
-
-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;
-}
-
-static void addLLCOptArg(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs) {
- if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
- StringRef OOpt = "0";
- if (A->getOption().matches(options::OPT_O4) ||
- A->getOption().matches(options::OPT_Ofast))
- OOpt = "3";
- else if (A->getOption().matches(options::OPT_O0))
- OOpt = "0";
- else if (A->getOption().matches(options::OPT_O)) {
- // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3
- // so we map -Os/-Oz to -O2.
- // Only clang supports -Og, and maps it to -O1.
- // We map anything else to -O2.
- OOpt = llvm::StringSwitch<const char *>(A->getValue())
- .Case("1", "1")
- .Case("2", "2")
- .Case("3", "3")
- .Case("s", "2")
- .Case("z", "2")
- .Case("g", "1")
- .Default("0");
- }
- CmdArgs.push_back(Args.MakeArgString("-O" + OOpt));
- }
-}
-
-static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC,
- std::string &GPUArch) {
- if (auto Err = TC.getSystemGPUArch(Args, GPUArch)) {
- std::string ErrMsg =
- llvm::formatv("{0}", llvm::fmt_consume(std::move(Err)));
- TC.getDriver().Diag(diag::err_drv_undetermined_amdgpu_arch) << ErrMsg;
- return false;
- }
-
- return true;
-}
-} // namespace
-
-const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand(
- const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C,
- const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args,
- StringRef SubArchName, StringRef OutputFilePrefix) const {
- ArgStringList CmdArgs;
-
- for (const auto &II : Inputs)
- if (II.isFilename())
- CmdArgs.push_back(II.getFilename());
-
- bool HasLibm = false;
- if (Args.hasArg(options::OPT_l)) {
- auto Lm = Args.getAllArgValues(options::OPT_l);
- for (auto &Lib : Lm) {
- if (Lib == "m") {
- HasLibm = true;
- break;
- }
- }
-
- if (HasLibm) {
- // This is not certain to work. The device libs added here, and passed to
- // llvm-link, are missing attributes that they expect to be inserted when
- // passed to mlink-builtin-bitcode. The amdgpu backend does not generate
- // conservatively correct code when attributes are missing, so this may
- // be the root cause of miscompilations. Passing via mlink-builtin-bitcode
- // ultimately hits CodeGenModule::addDefaultFunctionDefinitionAttributes
- // on each function, see D28538 for context.
- // Potential workarounds:
- // - unconditionally link all of the device libs to every translation
- // unit in clang via mlink-builtin-bitcode
- // - build a libm bitcode file as part of the DeviceRTL and explictly
- // mlink-builtin-bitcode the rocm device libs components at build time
- // - drop this llvm-link fork in favour or some calls into LLVM, chosen
- // to do basically the same work as llvm-link but with that call first
- // - write an opt pass that sets that on every function it sees and pipe
- // the device-libs bitcode through that on the way to this llvm-link
- SmallVector<std::string, 12> BCLibs =
- AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str());
- for (StringRef BCFile : BCLibs)
- CmdArgs.push_back(Args.MakeArgString(BCFile));
- }
- }
-
- AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn",
- SubArchName, /*isBitCodeSDL=*/true,
- /*postClangLink=*/false);
- // Add an intermediate output file.
- CmdArgs.push_back("-o");
- const char *OutputFileName =
- getOutputFileName(C, OutputFilePrefix, "-linked", "bc");
- CmdArgs.push_back(OutputFileName);
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("llvm-link"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs,
- InputInfo(&JA, Args.MakeArgString(OutputFileName))));
-
- // If we linked in libm definitions late we run another round of optimizations
- // to inline the definitions and fold what is foldable.
- if (HasLibm) {
- ArgStringList OptCmdArgs;
- const char *OptOutputFileName =
- getOutputFileName(C, OutputFilePrefix, "-linked-opt", "bc");
- addLLCOptArg(Args, OptCmdArgs);
- OptCmdArgs.push_back(OutputFileName);
- OptCmdArgs.push_back("-o");
- OptCmdArgs.push_back(OptOutputFileName);
- const char *OptExec =
- Args.MakeArgString(getToolChain().GetProgramPath("opt"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), OptExec, OptCmdArgs,
- InputInfo(&JA, Args.MakeArgString(OutputFileName)),
- InputInfo(&JA, Args.MakeArgString(OptOutputFileName))));
- OutputFileName = OptOutputFileName;
- }
-
- return OutputFileName;
-}
-
-const char *AMDGCN::OpenMPLinker::constructLlcCommand(
- Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
- const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
- llvm::StringRef OutputFilePrefix, const char *InputFileName,
- bool OutputIsAsm) const {
- // Construct llc command.
- ArgStringList LlcArgs;
- // The input to llc is the output from opt.
- LlcArgs.push_back(InputFileName);
- // Pass optimization arg to llc.
- addLLCOptArg(Args, LlcArgs);
- LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa");
- LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName));
- LlcArgs.push_back(
- Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")));
-
- for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
- LlcArgs.push_back(A->getValue(0));
- }
-
- // Add output filename
- LlcArgs.push_back("-o");
- const char *LlcOutputFile =
- getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o");
- LlcArgs.push_back(LlcOutputFile);
- const char *Llc = Args.MakeArgString(getToolChain().GetProgramPath("llc"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), Llc, LlcArgs, Inputs,
- InputInfo(&JA, Args.MakeArgString(LlcOutputFile))));
- return LlcOutputFile;
-}
-
-void AMDGCN::OpenMPLinker::constructLldCommand(
- Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
- const InputInfo &Output, const llvm::opt::ArgList &Args,
- const char *InputFileName) const {
- // Construct lld command.
- // The output from ld.lld is an HSA code object file.
- ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined",
- "-shared", "-o", Output.getFilename(),
- InputFileName};
-
- const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld"));
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::AtFileCurCP(), Lld, LldArgs, Inputs,
- InputInfo(&JA, Args.MakeArgString(Output.getFilename()))));
-}
-
-// For amdgcn the inputs of the linker job are device bitcode and output is
-// object file. It calls llvm-link, opt, llc, then lld steps.
-void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const ToolChain &TC = getToolChain();
- assert(getToolChain().getTriple().isAMDGCN() && "Unsupported target");
-
- const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC =
- static_cast<const toolchains::AMDGPUOpenMPToolChain &>(TC);
-
- std::string GPUArch = Args.getLastArgValue(options::OPT_march_EQ).str();
- if (GPUArch.empty()) {
- if (!checkSystemForAMDGPU(Args, AMDGPUOpenMPTC, GPUArch))
- return;
- }
-
- // Prefix for temporary file name.
- std::string Prefix;
- for (const auto &II : Inputs)
- if (II.isFilename())
- Prefix = llvm::sys::path::stem(II.getFilename()).str() + "-" + GPUArch;
- assert(Prefix.length() && "no linker inputs are files ");
-
- // Each command outputs different files.
- const char *LLVMLinkCommand = constructLLVMLinkCommand(
- AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix);
-
- // Produce readable assembly if save-temps is enabled.
- if (C.getDriver().isSaveTempsEnabled())
- constructLlcCommand(C, JA, Inputs, Args, GPUArch, Prefix, LLVMLinkCommand,
- /*OutputIsAsm=*/true);
- const char *LlcCommand = constructLlcCommand(C, JA, Inputs, Args, GPUArch,
- Prefix, LLVMLinkCommand);
- constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand);
-}
-
AMDGPUOpenMPToolChain::AMDGPUOpenMPToolChain(const Driver &D,
const llvm::Triple &Triple,
const ToolChain &HostTC,
@@ -268,11 +44,8 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions(
Action::OffloadKind DeviceOffloadingKind) const {
HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
- std::string GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ).str();
- if (GPUArch.empty()) {
- if (!checkSystemForAMDGPU(DriverArgs, *this, GPUArch))
- return;
- }
+ StringRef GPUArch = DriverArgs.getLastArgValue(options::OPT_march_EQ);
+ assert(!GPUArch.empty() && "Must have an explicit GPU arch.");
assert(DeviceOffloadingKind == Action::OFK_OpenMP &&
"Only OpenMP offloading kinds are supported.");
@@ -284,11 +57,15 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions(
if (DriverArgs.hasArg(options::OPT_nogpulib))
return;
+ for (auto BCFile : getDeviceLibs(DriverArgs)) {
+ CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode"
+ : "-mlink-bitcode-file");
+ CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path));
+ }
+
// Link the bitcode library late if we're using device LTO.
if (getDriver().isUsingLTO(/* IsOffload */ true))
return;
-
- addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, GPUArch, getTriple());
}
llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
@@ -307,9 +84,19 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
DAL->append(A);
if (!DAL->hasArg(options::OPT_march_EQ)) {
- std::string Arch = BoundArch.str();
- if (BoundArch.empty())
- checkSystemForAMDGPU(Args, *this, Arch);
+ StringRef Arch = BoundArch;
+ if (Arch.empty()) {
+ auto ArchsOrErr = getSystemGPUArchs(Args);
+ if (!ArchsOrErr) {
+ std::string ErrMsg =
+ llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError()));
+ getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march";
+ Arch = CudaArchToString(CudaArch::HIPDefault);
+ } else {
+ Arch = Args.MakeArgString(ArchsOrErr->front());
+ }
+ }
DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch);
}
@@ -329,11 +116,6 @@ llvm::opt::DerivedArgList *AMDGPUOpenMPToolChain::TranslateArgs(
return DAL;
}
-Tool *AMDGPUOpenMPToolChain::buildLinker() const {
- assert(getTriple().isAMDGCN());
- return new tools::AMDGCN::OpenMPLinker(*this);
-}
-
void AMDGPUOpenMPToolChain::addClangWarningOptions(
ArgStringList &CC1Args) const {
HostTC.addClangWarningOptions(CC1Args);
@@ -372,3 +154,24 @@ AMDGPUOpenMPToolChain::computeMSVCVersion(const Driver *D,
const ArgList &Args) const {
return HostTC.computeMSVCVersion(D, Args);
}
+
+llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
+AMDGPUOpenMPToolChain::getDeviceLibs(const llvm::opt::ArgList &Args) const {
+ if (Args.hasArg(options::OPT_nogpulib))
+ return {};
+
+ if (!RocmInstallation.hasDeviceLibrary()) {
+ getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 0;
+ return {};
+ }
+
+ StringRef GpuArch = getProcessorFromTargetID(
+ getTriple(), Args.getLastArgValue(options::OPT_march_EQ));
+
+ SmallVector<BitCodeLibraryInfo, 12> BCLibs;
+ for (auto BCLib : getCommonDeviceLibNames(Args, GpuArch.str(),
+ /*IsOpenMP=*/true))
+ BCLibs.emplace_back(BCLib);
+
+ return BCLibs;
+}
diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h
index 233256bf7378..2be444a42c55 100644
--- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h
+++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h
@@ -20,49 +20,6 @@ namespace toolchains {
class AMDGPUOpenMPToolChain;
}
-namespace tools {
-
-namespace AMDGCN {
-// Runs llvm-link/opt/llc/lld, which links multiple LLVM bitcode, together with
-// device library, then compiles it to ISA in a shared object.
-class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool {
-public:
- OpenMPLinker(const ToolChain &TC)
- : Tool("AMDGCN::OpenMPLinker", "amdgcn-link", 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;
-
-private:
- /// \return llvm-link output file name.
- const char *constructLLVMLinkCommand(
- const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C,
- const JobAction &JA, const InputInfoList &Inputs,
- const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
- llvm::StringRef OutputFilePrefix) const;
-
- /// \return llc output file name.
- const char *constructLlcCommand(Compilation &C, const JobAction &JA,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &Args,
- llvm::StringRef SubArchName,
- llvm::StringRef OutputFilePrefix,
- const char *InputFileName,
- bool OutputIsAsm = false) const;
-
- void constructLldCommand(Compilation &C, const JobAction &JA,
- const InputInfoList &Inputs, const InputInfo &Output,
- const llvm::opt::ArgList &Args,
- const char *InputFileName) const;
-};
-
-} // end namespace AMDGCN
-} // end namespace tools
-
namespace toolchains {
class LLVM_LIBRARY_VISIBILITY AMDGPUOpenMPToolChain final
@@ -97,10 +54,10 @@ public:
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;
- const ToolChain &HostTC;
+ llvm::SmallVector<BitCodeLibraryInfo, 12>
+ getDeviceLibs(const llvm::opt::ArgList &Args) const override;
-protected:
- Tool *buildLinker() const override;
+ const ToolChain &HostTC;
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp
index 89d408823270..91d89f5441a2 100644
--- a/clang/lib/Driver/ToolChains/AVR.cpp
+++ b/clang/lib/Driver/ToolChains/AVR.cpp
@@ -12,13 +12,12 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
using namespace clang::driver;
using namespace clang::driver::toolchains;
@@ -341,18 +340,18 @@ std::string GetMCUSubPath(StringRef MCUName) {
return "";
}
-llvm::Optional<StringRef> GetMCUFamilyName(StringRef MCUName) {
+std::optional<StringRef> GetMCUFamilyName(StringRef MCUName) {
for (const auto &MCU : MCUInfo)
if (MCU.Name == MCUName)
- return Optional<StringRef>(MCU.Family);
- return Optional<StringRef>();
+ return std::optional<StringRef>(MCU.Family);
+ return std::nullopt;
}
-llvm::Optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) {
+std::optional<unsigned> GetMCUSectionAddressData(StringRef MCUName) {
for (const auto &MCU : MCUInfo)
if (MCU.Name == MCUName && MCU.DataAddr > 0)
- return Optional<unsigned>(MCU.DataAddr);
- return Optional<unsigned>();
+ return std::optional<unsigned>(MCU.DataAddr);
+ return std::nullopt;
}
const StringRef PossibleAVRLibcLocations[] = {
@@ -369,8 +368,7 @@ AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
: Generic_ELF(D, Triple, Args) {
GCCInstallation.init(Triple, Args);
- std::string CPU = getCPUName(D, Args, Triple);
- if (CPU.empty())
+ if (getCPUName(D, Args, Triple).empty())
D.Diag(diag::warn_drv_avr_mcu_not_specified);
// Only add default libraries if the user hasn't explicitly opted out.
@@ -389,7 +387,7 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return;
// Omit if there is no avr-libc installed.
- Optional<std::string> AVRLibcRoot = findAVRLibcInstallation();
+ std::optional<std::string> AVRLibcRoot = findAVRLibcInstallation();
if (!AVRLibcRoot)
return;
@@ -418,6 +416,23 @@ Tool *AVRToolChain::buildLinker() const {
return new tools::AVR::Linker(getTriple(), *this);
}
+std::string
+AVRToolChain::getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
+ FileType Type = ToolChain::FT_Static) const {
+ assert(Type == ToolChain::FT_Static && "AVR only supports static libraries");
+ // Since AVR can never be a host environment, its compiler-rt library files
+ // should always have ".a" suffix, even on windows.
+ SmallString<32> File("/libclang_rt.");
+ File += Component.str();
+ File += ".a";
+ // Return the default compiler-rt path appended with
+ // "avr/libclang_rt.$COMPONENT.a".
+ SmallString<256> Path(ToolChain::getCompilerRTPath());
+ llvm::sys::path::append(Path, "avr");
+ llvm::sys::path::append(Path, File.str());
+ return std::string(Path.str());
+}
+
void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs, const ArgList &Args,
@@ -427,9 +442,9 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Compute information about the target AVR.
std::string CPU = getCPUName(D, Args, getToolChain().getTriple());
- llvm::Optional<StringRef> FamilyName = GetMCUFamilyName(CPU);
- llvm::Optional<std::string> AVRLibcRoot = TC.findAVRLibcInstallation();
- llvm::Optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU);
+ std::optional<StringRef> FamilyName = GetMCUFamilyName(CPU);
+ std::optional<std::string> AVRLibcRoot = TC.findAVRLibcInstallation();
+ std::optional<unsigned> SectionAddressData = GetMCUSectionAddressData(CPU);
// Compute the linker program path, and use GNU "avr-ld" as default.
const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ);
@@ -448,6 +463,12 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);
+ // Currently we only support libgcc and compiler-rt.
+ auto RtLib = TC.GetRuntimeLibType(Args);
+ assert(
+ (RtLib == ToolChain::RLT_Libgcc || RtLib == ToolChain::RLT_CompilerRT) &&
+ "unknown runtime library");
+
// Only add default libraries if the user hasn't explicitly opted out.
bool LinkStdlib = false;
if (!Args.hasArg(options::OPT_nostdlib) &&
@@ -463,10 +484,12 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
D.Diag(diag::warn_drv_avr_libc_not_found);
} else {
std::string SubPath = GetMCUSubPath(CPU);
+ // Add path of avr-libc.
CmdArgs.push_back(
Args.MakeArgString(Twine("-L") + *AVRLibcRoot + "/lib/" + SubPath));
- CmdArgs.push_back(
- Args.MakeArgString("-L" + TC.getGCCInstallPath() + "/" + SubPath));
+ if (RtLib == ToolChain::RLT_Libgcc)
+ CmdArgs.push_back(Args.MakeArgString("-L" + TC.getGCCInstallPath() +
+ "/" + SubPath));
LinkStdlib = true;
}
}
@@ -475,9 +498,8 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
if (SectionAddressData) {
- std::string DataSectionArg =
- std::string("-Tdata=0x") + llvm::utohexstr(SectionAddressData.value());
- CmdArgs.push_back(Args.MakeArgString(DataSectionArg));
+ CmdArgs.push_back(Args.MakeArgString(
+ "-Tdata=0x" + Twine::utohexstr(*SectionAddressData)));
} else {
// We do not have an entry for this CPU in the address mapping table yet.
D.Diag(diag::warn_drv_avr_linker_section_addresses_not_implemented) << CPU;
@@ -495,14 +517,29 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o");
CmdArgs.push_back(Args.MakeArgString(CrtFileName));
- CmdArgs.push_back("-lgcc");
+ // Link to libgcc.
+ if (RtLib == ToolChain::RLT_Libgcc)
+ CmdArgs.push_back("-lgcc");
+
+ // Link to generic libraries of avr-libc.
CmdArgs.push_back("-lm");
CmdArgs.push_back("-lc");
// Add the link library specific to the MCU.
CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU));
+ // Add the relocatable inputs.
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ // We directly use libclang_rt.builtins.a as input file, instead of using
+ // '-lclang_rt.builtins'.
+ if (RtLib == ToolChain::RLT_CompilerRT) {
+ std::string RtLib =
+ getToolChain().getCompilerRT(Args, "builtins", ToolChain::FT_Static);
+ if (llvm::sys::fs::exists(RtLib))
+ CmdArgs.push_back(Args.MakeArgString(RtLib));
+ }
+
CmdArgs.push_back("--end-group");
// Add user specified linker script.
@@ -523,7 +560,7 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs, Inputs, Output));
}
-llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const {
+std::optional<std::string> AVRToolChain::findAVRLibcInstallation() const {
// Search avr-libc installation according to avr-gcc installation.
std::string GCCParent(GCCInstallation.getParentLibPath());
std::string Path(GCCParent + "/avr");
@@ -541,5 +578,5 @@ llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const {
return Path;
}
- return llvm::None;
+ return std::nullopt;
}
diff --git a/clang/lib/Driver/ToolChains/AVR.h b/clang/lib/Driver/ToolChains/AVR.h
index ab147d852ad7..ea161fe28f33 100644
--- a/clang/lib/Driver/ToolChains/AVR.h
+++ b/clang/lib/Driver/ToolChains/AVR.h
@@ -31,8 +31,10 @@ public:
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const override;
- llvm::Optional<std::string> findAVRLibcInstallation() const;
+ std::optional<std::string> findAVRLibcInstallation() const;
StringRef getGCCInstallPath() const { return GCCInstallPath; }
+ std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
+ FileType Type) const override;
protected:
Tool *buildLinker() const override;
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index cf7e201b4972..2c559cc8b3b9 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "AArch64.h"
+#include "../CommonArgs.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
@@ -38,6 +39,8 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
CPU = Mcpu.split("+").first.lower();
}
+ CPU = llvm::AArch64::resolveCPUAlias(CPU);
+
// Handle CPU name is 'native'.
if (CPU == "native")
return std::string(llvm::sys::getHostCPUName());
@@ -67,7 +70,7 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args,
// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
static bool DecodeAArch64Features(const Driver &D, StringRef text,
std::vector<StringRef> &Features,
- llvm::AArch64::ArchKind ArchKind) {
+ const llvm::AArch64::ArchInfo &ArchInfo) {
SmallVector<StringRef, 8> Split;
text.split(Split, StringRef("+"), -1, false);
@@ -101,12 +104,14 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text,
// +sve implies +f32mm if the base architecture is >= v8.6A (except v9A)
// It isn't the case in general that sve implies both f64mm and f32mm
- if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV8_7A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV8_8A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_1A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_2A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_3A) &&
+ if ((ArchInfo == llvm::AArch64::ARMV8_6A ||
+ ArchInfo == llvm::AArch64::ARMV8_7A ||
+ ArchInfo == llvm::AArch64::ARMV8_8A ||
+ ArchInfo == llvm::AArch64::ARMV8_9A ||
+ ArchInfo == llvm::AArch64::ARMV9_1A ||
+ ArchInfo == llvm::AArch64::ARMV9_2A ||
+ ArchInfo == llvm::AArch64::ARMV9_3A ||
+ ArchInfo == llvm::AArch64::ARMV9_4A) &&
Feature == "sve")
Features.push_back("+f32mm");
}
@@ -118,8 +123,8 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text,
static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
std::vector<StringRef> &Features) {
std::pair<StringRef, StringRef> Split = Mcpu.split("+");
- CPU = Split.first;
- llvm::AArch64::ArchKind ArchKind = llvm::AArch64::ArchKind::ARMV8A;
+ const llvm::AArch64::ArchInfo *ArchInfo = &llvm::AArch64::ARMV8A;
+ CPU = llvm::AArch64::resolveCPUAlias(Split.first);
if (CPU == "native")
CPU = llvm::sys::getHostCPUName();
@@ -127,20 +132,21 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
if (CPU == "generic") {
Features.push_back("+neon");
} else {
- ArchKind = llvm::AArch64::parseCPUArch(CPU);
- if (!llvm::AArch64::getArchFeatures(ArchKind, Features))
+ ArchInfo = &llvm::AArch64::parseCpu(CPU).Arch;
+ if (*ArchInfo == llvm::AArch64::INVALID)
return false;
+ Features.push_back(ArchInfo->ArchFeature);
- uint64_t Extension = llvm::AArch64::getDefaultExtensions(CPU, ArchKind);
+ uint64_t Extension = llvm::AArch64::getDefaultExtensions(CPU, *ArchInfo);
if (!llvm::AArch64::getExtensionFeatures(Extension, Features))
return false;
- }
+ }
- if (Split.second.size() &&
- !DecodeAArch64Features(D, Split.second, Features, ArchKind))
- return false;
+ if (Split.second.size() &&
+ !DecodeAArch64Features(D, Split.second, Features, *ArchInfo))
+ return false;
- return true;
+ return true;
}
static bool
@@ -150,25 +156,26 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
std::string MarchLowerCase = March.lower();
std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
- llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first);
+ const llvm::AArch64::ArchInfo *ArchInfo =
+ &llvm::AArch64::parseArch(Split.first);
if (Split.first == "native")
- ArchKind = llvm::AArch64::getCPUArchKind(llvm::sys::getHostCPUName().str());
- if (ArchKind == llvm::AArch64::ArchKind::INVALID ||
- !llvm::AArch64::getArchFeatures(ArchKind, Features))
+ ArchInfo = &llvm::AArch64::getArchForCpu(llvm::sys::getHostCPUName().str());
+ if (*ArchInfo == llvm::AArch64::INVALID)
return false;
+ Features.push_back(ArchInfo->ArchFeature);
// Enable SVE2 by default on Armv9-A.
// It can still be disabled if +nosve2 is present.
// We must do this early so that DecodeAArch64Features has the correct state
- if ((ArchKind == llvm::AArch64::ArchKind::ARMV9A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_1A ||
- ArchKind == llvm::AArch64::ArchKind::ARMV9_2A)) {
+ if ((*ArchInfo == llvm::AArch64::ARMV9A ||
+ *ArchInfo == llvm::AArch64::ARMV9_1A ||
+ *ArchInfo == llvm::AArch64::ARMV9_2A)) {
Features.push_back("+sve");
Features.push_back("+sve2");
}
if ((Split.second.size() &&
- !DecodeAArch64Features(D, Split.second, Features, ArchKind)))
+ !DecodeAArch64Features(D, Split.second, Features, *ArchInfo)))
return false;
return true;
@@ -269,9 +276,9 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
// If "-Wa,-march=" is used, 'WaMArch' will contain the argument's value,
// while 'A' is uninitialized. Only dereference 'A' in the other case.
if (!WaMArch.empty())
- Diag << "march=" << WaMArch;
+ Diag << "-march=" << WaMArch;
else
- Diag << A->getOption().getName() << A->getValue();
+ Diag << A->getSpelling() << A->getValue();
}
if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
@@ -325,7 +332,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
continue;
}
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Scope;
+ << A->getSpelling() << Scope;
break;
}
}
@@ -478,18 +485,6 @@ fp16_fml_fallthrough:
}
}
- // FIXME: these insertions should ideally be automated using default
- // extensions support from the backend target parser.
- if (V8Version >= 6 || V9Version >= 1)
- Features.insert(std::next(Features.begin() + ArchFeatPos),
- {"+i8mm", "+bf16"});
-
- // For Armv8.8-a/Armv9.3-a or later, FEAT_HBC and FEAT_MOPS are enabled by
- // default.
- if (V8Version >= 8 || V9Version >= 3)
- Features.insert(std::next(Features.begin() + ArchFeatPos),
- {"+hbc", "+mops"});
-
if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
options::OPT_munaligned_access)) {
if (A->getOption().matches(options::OPT_mno_unaligned_access))
@@ -611,6 +606,10 @@ fp16_fml_fallthrough:
} else if (Triple.isAndroid()) {
// Enabled A53 errata (835769) workaround by default on android
Features.push_back("+fix-cortex-a53-835769");
+ } else if (Triple.isOSFuchsia()) {
+ std::string CPU = getCPUName(D, Args, Triple);
+ if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
+ Features.push_back("+fix-cortex-a53-835769");
}
if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index a64909d9a6e7..b6a9df28500a 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -122,7 +122,7 @@ static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args,
(Split.second.size() && !DecodeARMFeatures(D, Split.second, CPUName,
ArchKind, Features, ArgFPUID)))
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
}
// Check -mcpu=. Needs ArchName to handle -mcpu=generic.
@@ -139,7 +139,7 @@ static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args,
(Split.second.size() &&
!DecodeARMFeatures(D, Split.second, CPU, ArchKind, Features, ArgFPUID)))
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
}
bool arm::useAAPCSForMachO(const llvm::Triple &T) {
@@ -442,8 +442,7 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
bool KernelOrKext =
Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args);
- llvm::Optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv,
- WaArch;
+ std::optional<std::pair<const Arg *, StringRef>> WaCPU, WaFPU, WaHDiv, WaArch;
// This vector will accumulate features from the architecture
// extension suffixes on -mcpu and -march (e.g. the 'bar' in
@@ -776,21 +775,15 @@ fp16_fml_fallthrough:
// This only makes sense for the compiler, not for the assembler.
if (!ForAS) {
// Supported only on ARMv6T2 and ARMv7 and above.
- // Cannot be combined with -mno-movt or -mlong-calls
+ // Cannot be combined with -mno-movt.
if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) {
if (A->getOption().matches(options::OPT_mexecute_only)) {
if (getARMSubArchVersionNumber(Triple) < 7 &&
llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2)
D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName();
else if (Arg *B = Args.getLastArg(options::OPT_mno_movt))
- D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
- // Long calls create constant pool entries and have not yet been fixed up
- // to play nicely with execute-only. Hence, they cannot be used in
- // execute-only code for now
- else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) {
- if (B->getOption().matches(options::OPT_mlong_calls))
- D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
- }
+ D.Diag(diag::err_opt_not_valid_with_opt)
+ << A->getAsString(Args) << B->getAsString(Args);
Features.push_back("+execute-only");
}
}
@@ -885,7 +878,7 @@ fp16_fml_fallthrough:
continue;
}
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Scope;
+ << A->getSpelling() << Scope;
break;
}
}
@@ -944,7 +937,7 @@ StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) {
// We need to return an empty string here on invalid MArch values as the
// various places that call this function can't cope with a null result.
- return Triple.getARMCPUForArch(MArch);
+ return llvm::ARM::getARMCPUForArch(Triple, MArch);
}
/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting.
@@ -977,7 +970,8 @@ llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch,
if (ArchKind == llvm::ARM::ArchKind::INVALID)
// In case of generic Arch, i.e. "arm",
// extract arch from default cpu of the Triple
- ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch));
+ ArchKind =
+ llvm::ARM::parseCPUArch(llvm::ARM::getARMCPUForArch(Triple, ARMArch));
} else {
// FIXME: horrible hack to get around the fact that Cortex-A7 is only an
// armv7k triple if it's actually been specified via "-arch armv7k".
diff --git a/clang/lib/Driver/ToolChains/Arch/CSKY.cpp b/clang/lib/Driver/ToolChains/Arch/CSKY.cpp
index 3a8f92785609..ed8128d829e9 100644
--- a/clang/lib/Driver/ToolChains/Arch/CSKY.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/CSKY.cpp
@@ -12,7 +12,6 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CSKYTargetParser.h"
@@ -25,7 +24,7 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-llvm::Optional<llvm::StringRef>
+std::optional<llvm::StringRef>
csky::getCSKYArchName(const Driver &D, const ArgList &Args,
const llvm::Triple &Triple) {
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
@@ -33,21 +32,21 @@ csky::getCSKYArchName(const Driver &D, const ArgList &Args,
if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
- return llvm::Optional<llvm::StringRef>();
+ return std::nullopt;
}
- return llvm::Optional<llvm::StringRef>(A->getValue());
+ return std::optional<llvm::StringRef>(A->getValue());
}
if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
llvm::CSKY::ArchKind ArchKind = llvm::CSKY::parseCPUArch(A->getValue());
if (ArchKind == llvm::CSKY::ArchKind::INVALID) {
D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
- return llvm::Optional<llvm::StringRef>();
+ return std::nullopt;
}
- return llvm::Optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind));
+ return std::optional<llvm::StringRef>(llvm::CSKY::getArchName(ArchKind));
}
- return llvm::Optional<llvm::StringRef>("ck810");
+ return std::optional<llvm::StringRef>("ck810");
}
csky::FloatABI csky::getCSKYFloatABI(const Driver &D, const ArgList &Args) {
@@ -99,7 +98,7 @@ getCSKYFPUFeatures(const Driver &D, const Arg *A, const ArgList &Args,
auto RemoveTargetFPUFeature =
[&Features](ArrayRef<const char *> FPUFeatures) {
for (auto FPUFeature : FPUFeatures) {
- auto it = std::find(Features.begin(), Features.end(), FPUFeature);
+ auto it = llvm::find(Features, FPUFeature);
if (it != Features.end())
Features.erase(it);
}
diff --git a/clang/lib/Driver/ToolChains/Arch/CSKY.h b/clang/lib/Driver/ToolChains/Arch/CSKY.h
index d23da1d66e35..f3730d2cf4a1 100644
--- a/clang/lib/Driver/ToolChains/Arch/CSKY.h
+++ b/clang/lib/Driver/ToolChains/Arch/CSKY.h
@@ -35,9 +35,9 @@ void getCSKYTargetFeatures(const Driver &D, const llvm::Triple &Triple,
llvm::opt::ArgStringList &CmdArgs,
std::vector<llvm::StringRef> &Features);
-llvm::Optional<llvm::StringRef> getCSKYArchName(const Driver &D,
- const llvm::opt::ArgList &Args,
- const llvm::Triple &Triple);
+std::optional<llvm::StringRef> getCSKYArchName(const Driver &D,
+ const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
} // end namespace csky
} // namespace tools
diff --git a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
new file mode 100644
index 000000000000..576677a5f38e
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
@@ -0,0 +1,115 @@
+//===--- LoongArch.cpp - LoongArch Helpers for Tools ------------*- 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 "LoongArch.h"
+#include "clang/Basic/DiagnosticDriver.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/Support/LoongArchTargetParser.h"
+
+using namespace clang::driver;
+using namespace clang::driver::tools;
+using namespace clang;
+using namespace llvm::opt;
+
+StringRef loongarch::getLoongArchABI(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple) {
+ assert((Triple.getArch() == llvm::Triple::loongarch32 ||
+ Triple.getArch() == llvm::Triple::loongarch64) &&
+ "Unexpected triple");
+ bool IsLA32 = Triple.getArch() == llvm::Triple::loongarch32;
+
+ // Check -m*-float firstly since they have highest priority.
+ if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
+ options::OPT_msingle_float,
+ options::OPT_msoft_float)) {
+ if (A->getOption().matches(options::OPT_mdouble_float))
+ return IsLA32 ? "ilp32d" : "lp64d";
+ if (A->getOption().matches(options::OPT_msingle_float))
+ return IsLA32 ? "ilp32f" : "lp64f";
+ if (A->getOption().matches(options::OPT_msoft_float))
+ return IsLA32 ? "ilp32s" : "lp64s";
+ }
+
+ // If `-mabi=` is specified, use it.
+ if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
+ return A->getValue();
+
+ // Select abi based on -mfpu=xx.
+ if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
+ StringRef FPU = A->getValue();
+ if (FPU == "64")
+ return IsLA32 ? "ilp32d" : "lp64d";
+ if (FPU == "32")
+ return IsLA32 ? "ilp32f" : "lp64f";
+ if (FPU == "0" || FPU == "none")
+ return IsLA32 ? "ilp32s" : "lp64s";
+ D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
+ }
+
+ // Choose a default based on the triple.
+ return IsLA32 ? "ilp32d" : "lp64d";
+}
+
+void loongarch::getLoongArchTargetFeatures(const Driver &D,
+ const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ StringRef ArchName;
+ llvm::LoongArch::ArchKind ArchKind = llvm::LoongArch::ArchKind::AK_INVALID;
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ ArchKind = llvm::LoongArch::parseArch(A->getValue());
+ if (ArchKind == llvm::LoongArch::ArchKind::AK_INVALID) {
+ D.Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args);
+ return;
+ }
+ ArchName = A->getValue();
+ }
+
+ // TODO: handle -march=native and -mtune=xx.
+
+ // Select a default arch name.
+ if (ArchName.empty() && Triple.getArch() == llvm::Triple::loongarch64)
+ ArchName = "loongarch64";
+
+ if (!ArchName.empty())
+ llvm::LoongArch::getArchFeatures(ArchName, Features);
+
+ // Select floating-point features determined by -mdouble-float,
+ // -msingle-float, -msoft-float and -mfpu.
+ // Note: -m*-float wins any other options.
+ if (const Arg *A = Args.getLastArg(options::OPT_mdouble_float,
+ options::OPT_msingle_float,
+ options::OPT_msoft_float)) {
+ if (A->getOption().matches(options::OPT_mdouble_float)) {
+ Features.push_back("+f");
+ Features.push_back("+d");
+ } else if (A->getOption().matches(options::OPT_msingle_float)) {
+ Features.push_back("+f");
+ Features.push_back("-d");
+ } else /*Soft-float*/ {
+ Features.push_back("-f");
+ Features.push_back("-d");
+ }
+ } else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
+ StringRef FPU = A->getValue();
+ if (FPU == "64") {
+ Features.push_back("+f");
+ Features.push_back("+d");
+ } else if (FPU == "32") {
+ Features.push_back("+f");
+ Features.push_back("-d");
+ } else if (FPU == "0" || FPU == "none") {
+ Features.push_back("-f");
+ Features.push_back("-d");
+ } else {
+ D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
+ }
+ }
+}
diff --git a/clang/lib/Driver/ToolChains/Arch/LoongArch.h b/clang/lib/Driver/ToolChains/Arch/LoongArch.h
new file mode 100644
index 000000000000..0084474e7ed3
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/Arch/LoongArch.h
@@ -0,0 +1,31 @@
+//===--- LoongArch.h - LoongArch-specific Tool Helpers ----------*- 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_ARCH_LOONGARCH_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H
+
+#include "clang/Driver/Driver.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Option.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace loongarch {
+void getLoongArchTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ std::vector<llvm::StringRef> &Features);
+
+StringRef getLoongArchABI(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+} // end namespace loongarch
+} // end namespace tools
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_LOONGARCH_H
diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/clang/lib/Driver/ToolChains/Arch/Mips.cpp
index c374d745da38..088eecf79adb 100644
--- a/clang/lib/Driver/ToolChains/Arch/Mips.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp
@@ -306,7 +306,7 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
}
} else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
}
if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) {
@@ -327,7 +327,7 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
}
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
}
}
diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/clang/lib/Driver/ToolChains/Arch/PPC.cpp
index 7817ec595ceb..6ec736bc701b 100644
--- a/clang/lib/Driver/ToolChains/Arch/PPC.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/PPC.cpp
@@ -20,46 +20,50 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
+static std::string getPPCGenericTargetCPU(const llvm::Triple &T) {
+ // LLVM may default to generating code for the native CPU,
+ // but, like gcc, we default to a more generic option for
+ // each architecture. (except on AIX)
+ if (T.isOSAIX())
+ return "pwr7";
+ else if (T.getArch() == llvm::Triple::ppc64le)
+ return "ppc64le";
+ else if (T.getArch() == llvm::Triple::ppc64)
+ return "ppc64";
+ else
+ return "ppc";
+}
+
/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting.
-std::string ppc::getPPCTargetCPU(const ArgList &Args) {
+std::string ppc::getPPCTargetCPU(const ArgList &Args, const llvm::Triple &T) {
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
StringRef CPUName = A->getValue();
+ // Clang/LLVM does not actually support code generation
+ // for the 405 CPU. However, there are uses of this CPU ID
+ // in projects that previously used GCC and rely on Clang
+ // accepting it. Clang has always ignored it and passed the
+ // generic CPU ID to the back end.
+ if (CPUName == "generic" || CPUName == "405")
+ return getPPCGenericTargetCPU(T);
+
if (CPUName == "native") {
std::string CPU = std::string(llvm::sys::getHostCPUName());
if (!CPU.empty() && CPU != "generic")
return CPU;
else
- return "";
+ return getPPCGenericTargetCPU(T);
}
return llvm::StringSwitch<const char *>(CPUName)
.Case("common", "generic")
- .Case("440", "440")
.Case("440fp", "440")
- .Case("450", "450")
- .Case("601", "601")
- .Case("602", "602")
- .Case("603", "603")
- .Case("603e", "603e")
- .Case("603ev", "603ev")
- .Case("604", "604")
- .Case("604e", "604e")
- .Case("620", "620")
.Case("630", "pwr3")
.Case("G3", "g3")
- .Case("7400", "7400")
.Case("G4", "g4")
- .Case("7450", "7450")
.Case("G4+", "g4+")
- .Case("750", "750")
.Case("8548", "e500")
- .Case("970", "970")
.Case("G5", "g5")
- .Case("a2", "a2")
- .Case("e500", "e500")
- .Case("e500mc", "e500mc")
- .Case("e5500", "e5500")
.Case("power3", "pwr3")
.Case("power4", "pwr4")
.Case("power5", "pwr5")
@@ -71,23 +75,13 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) {
.Case("power9", "pwr9")
.Case("power10", "pwr10")
.Case("future", "future")
- .Case("pwr3", "pwr3")
- .Case("pwr4", "pwr4")
- .Case("pwr5", "pwr5")
- .Case("pwr5x", "pwr5x")
- .Case("pwr6", "pwr6")
- .Case("pwr6x", "pwr6x")
- .Case("pwr7", "pwr7")
- .Case("pwr8", "pwr8")
- .Case("pwr9", "pwr9")
- .Case("pwr10", "pwr10")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
.Case("powerpc64le", "ppc64le")
- .Default("");
+ .Default(CPUName.data());
}
- return "";
+ return getPPCGenericTargetCPU(T);
}
const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
@@ -107,10 +101,6 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
- // TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a
- // longstanding behavior.
- (void)Args.getLastArg(options::OPT_mtune_EQ);
-
if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe)
Features.push_back("+spe");
diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.h b/clang/lib/Driver/ToolChains/Arch/PPC.h
index e1c943955e81..cd2b47d392b6 100644
--- a/clang/lib/Driver/ToolChains/Arch/PPC.h
+++ b/clang/lib/Driver/ToolChains/Arch/PPC.h
@@ -35,7 +35,8 @@ enum class ReadGOTPtrMode {
FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
-std::string getPPCTargetCPU(const llvm::opt::ArgList &Args);
+std::string getPPCTargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &T);
const char *getPPCAsmModeForCPU(StringRef Name);
ReadGOTPtrMode getPPCReadGOTPtrMode(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
index de6e045a9447..4c34c09d5589 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -13,12 +13,12 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/RISCVISAInfo.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -43,21 +43,18 @@ static bool getArchFeatures(const Driver &D, StringRef Arch,
}
(*ISAInfo)->toFeatures(
- Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); });
+ Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); },
+ /*AddAllExtensions=*/true);
return true;
}
// Get features except standard extension feature
-static void getRISCFeaturesFromMcpu(const Driver &D, const llvm::Triple &Triple,
- const llvm::opt::ArgList &Args,
- const llvm::opt::Arg *A, StringRef Mcpu,
+static bool getRISCFeaturesFromMcpu(const llvm::Triple &Triple, StringRef Mcpu,
std::vector<StringRef> &Features) {
- bool Is64Bit = (Triple.getArch() == llvm::Triple::riscv64);
+ bool Is64Bit = Triple.isRISCV64();
llvm::RISCV::CPUKind CPUKind = llvm::RISCV::parseCPUKind(Mcpu);
- if (!llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) ||
- !llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features)) {
- D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args);
- }
+ return llvm::RISCV::checkCPUKind(CPUKind, Is64Bit) &&
+ llvm::RISCV::getCPUFeaturesExceptStdExt(CPUKind, Features);
}
void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
@@ -70,8 +67,14 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
// If users give march and mcpu, get std extension feature from MArch
// and other features (ex. mirco architecture feature) from mcpu
- if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- getRISCFeaturesFromMcpu(D, Triple, Args, A, A->getValue(), Features);
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ StringRef CPU = A->getValue();
+ if (CPU == "native")
+ CPU = llvm::sys::getHostCPUName();
+ if (!getRISCFeaturesFromMcpu(Triple, CPU, Features))
+ D.Diag(clang::diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << CPU;
+ }
// Handle features corresponding to "-ffixed-X" options
if (Args.hasArg(options::OPT_ffixed_x1))
@@ -163,9 +166,7 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
}
StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
- assert((Triple.getArch() == llvm::Triple::riscv32 ||
- Triple.getArch() == llvm::Triple::riscv64) &&
- "Unexpected triple");
+ assert(Triple.isRISCV() && "Unexpected triple");
// GCC's logic around choosing a default `-mabi=` is complex. If GCC is not
// configured using `--with-abi=`, then the logic for the default choice is
@@ -213,7 +214,7 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
// We deviate from GCC's defaults here:
// - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.
// - On all other OSs we use the double floating point calling convention.
- if (Triple.getArch() == llvm::Triple::riscv32) {
+ if (Triple.isRISCV32()) {
if (Triple.getOS() == llvm::Triple::UnknownOS)
return "ilp32";
else
@@ -228,9 +229,7 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple) {
- assert((Triple.getArch() == llvm::Triple::riscv32 ||
- Triple.getArch() == llvm::Triple::riscv64) &&
- "Unexpected triple");
+ assert(Triple.isRISCV() && "Unexpected triple");
// GCC's logic around choosing a default `-march=` is complex. If GCC is not
// configured using `--with-arch=`, then the logic for the default choice is
@@ -264,7 +263,10 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
// 2. Get march (isa string) based on `-mcpu=`
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- StringRef MArch = llvm::RISCV::getMArchFromMcpu(A->getValue());
+ StringRef CPU = A->getValue();
+ if (CPU == "native")
+ CPU = llvm::sys::getHostCPUName();
+ StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);
// Bypass if target cpu's default march is empty.
if (MArch != "")
return MArch;
@@ -291,7 +293,7 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
// We deviate from GCC's defaults here:
// - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`
// - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)
- if (Triple.getArch() == llvm::Triple::riscv32) {
+ if (Triple.isRISCV32()) {
if (Triple.getOS() == llvm::Triple::UnknownOS)
return "rv32imac";
else
@@ -303,3 +305,20 @@ StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args,
return "rv64imafdc";
}
}
+
+std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple) {
+ std::string CPU;
+ // If we have -mcpu, use that.
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ CPU = A->getValue();
+
+ // Handle CPU name is 'native'.
+ if (CPU == "native")
+ CPU = llvm::sys::getHostCPUName();
+
+ if (!CPU.empty())
+ return CPU;
+
+ return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";
+}
diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.h b/clang/lib/Driver/ToolChains/Arch/RISCV.h
index d4a519cdab34..c30f1098ddda 100644
--- a/clang/lib/Driver/ToolChains/Arch/RISCV.h
+++ b/clang/lib/Driver/ToolChains/Arch/RISCV.h
@@ -26,6 +26,8 @@ StringRef getRISCVABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
StringRef getRISCVArch(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
+std::string getRISCVTargetCPU(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
} // end namespace riscv
} // namespace tools
} // end namespace driver
diff --git a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp
index 70ba8eb2a7d0..a2e9c7ab023e 100644
--- a/clang/lib/Driver/ToolChains/Arch/Sparc.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/Sparc.cpp
@@ -12,6 +12,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;
@@ -81,12 +82,14 @@ const char *sparc::getSparcAsmModeForCPU(StringRef Name,
sparc::FloatABI sparc::getSparcFloatABI(const Driver &D,
const ArgList &Args) {
sparc::FloatABI ABI = sparc::FloatABI::Invalid;
- if (Arg *A = Args.getLastArg(clang::driver::options::OPT_msoft_float,
- options::OPT_mhard_float,
+ if (Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mno_fpu,
+ options::OPT_mhard_float, options::OPT_mfpu,
options::OPT_mfloat_abi_EQ)) {
- if (A->getOption().matches(clang::driver::options::OPT_msoft_float))
+ if (A->getOption().matches(options::OPT_msoft_float) ||
+ A->getOption().matches(options::OPT_mno_fpu))
ABI = sparc::FloatABI::Soft;
- else if (A->getOption().matches(options::OPT_mhard_float))
+ else if (A->getOption().matches(options::OPT_mhard_float) ||
+ A->getOption().matches(options::OPT_mfpu))
ABI = sparc::FloatABI::Hard;
else {
ABI = llvm::StringSwitch<sparc::FloatABI>(A->getValue())
@@ -113,9 +116,76 @@ sparc::FloatABI sparc::getSparcFloatABI(const Driver &D,
return ABI;
}
+std::string sparc::getSparcTargetCPU(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getSpelling() << Triple.getTriple();
+ return "";
+ }
+
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mcpu_EQ)) {
+ StringRef CPUName = A->getValue();
+ if (CPUName == "native") {
+ std::string CPU = std::string(llvm::sys::getHostCPUName());
+ if (!CPU.empty() && CPU != "generic")
+ return CPU;
+ return "";
+ }
+ return std::string(CPUName);
+ }
+
+ if (Triple.getArch() == llvm::Triple::sparc && Triple.isOSSolaris())
+ return "v9";
+ return "";
+}
+
void sparc::getSparcTargetFeatures(const Driver &D, const ArgList &Args,
std::vector<StringRef> &Features) {
sparc::FloatABI FloatABI = sparc::getSparcFloatABI(D, Args);
if (FloatABI == sparc::FloatABI::Soft)
Features.push_back("+soft-float");
+
+ if (Arg *A = Args.getLastArg(options::OPT_mfsmuld, options::OPT_mno_fsmuld)) {
+ if (A->getOption().matches(options::OPT_mfsmuld))
+ Features.push_back("+fsmuld");
+ else
+ Features.push_back("-fsmuld");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mpopc, options::OPT_mno_popc)) {
+ if (A->getOption().matches(options::OPT_mpopc))
+ Features.push_back("+popc");
+ else
+ Features.push_back("-popc");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mvis, options::OPT_mno_vis)) {
+ if (A->getOption().matches(options::OPT_mvis))
+ Features.push_back("+vis");
+ else
+ Features.push_back("-vis");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mvis2, options::OPT_mno_vis2)) {
+ if (A->getOption().matches(options::OPT_mvis2))
+ Features.push_back("+vis2");
+ else
+ Features.push_back("-vis2");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mvis3, options::OPT_mno_vis3)) {
+ if (A->getOption().matches(options::OPT_mvis3))
+ Features.push_back("+vis3");
+ else
+ Features.push_back("-vis3");
+ }
+
+ if (Arg *A = Args.getLastArg(options::OPT_mhard_quad_float,
+ options::OPT_msoft_quad_float)) {
+ if (A->getOption().matches(options::OPT_mhard_quad_float))
+ Features.push_back("+hard-quad-float");
+ else
+ Features.push_back("-hard-quad-float");
+ }
}
diff --git a/clang/lib/Driver/ToolChains/Arch/Sparc.h b/clang/lib/Driver/ToolChains/Arch/Sparc.h
index d12a9a70e264..44658c4259c6 100644
--- a/clang/lib/Driver/ToolChains/Arch/Sparc.h
+++ b/clang/lib/Driver/ToolChains/Arch/Sparc.h
@@ -28,6 +28,9 @@ enum class FloatABI {
FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
+std::string getSparcTargetCPU(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+
void getSparcTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features);
const char *getSparcAsmModeForCPU(llvm::StringRef Name,
diff --git a/clang/lib/Driver/ToolChains/Arch/VE.cpp b/clang/lib/Driver/ToolChains/Arch/VE.cpp
index 9dfd37c2106d..97d74eb4e5ef 100644
--- a/clang/lib/Driver/ToolChains/Arch/VE.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/VE.cpp
@@ -10,7 +10,6 @@
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
using namespace clang::driver;
diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp
index cd7c014faa5e..3c8adf3cbc40 100644
--- a/clang/lib/Driver/ToolChains/Arch/X86.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp
@@ -13,7 +13,6 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Host.h"
@@ -31,9 +30,6 @@ std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args,
// FIXME: Reject attempts to use -march=native unless the target matches
// the host.
- //
- // FIXME: We should also incorporate the detected target features for use
- // with -native.
CPU = llvm::sys::getHostCPUName();
if (!CPU.empty() && CPU != "generic")
return std::string(CPU);
@@ -259,7 +255,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("+harden-sls-ijmp");
} else if (Scope != "none") {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Scope;
+ << A->getSpelling() << Scope;
}
}
}
diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index 5f1638a159d5..ac9c7036ad6e 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -39,7 +39,7 @@ static bool findRISCVMultilibs(const Driver &D,
StringRef Arch = riscv::getRISCVArch(Args, TargetTriple);
StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
- if (TargetTriple.getArch() == llvm::Triple::riscv64) {
+ if (TargetTriple.isRISCV64()) {
Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
.flag("+march=rv64imafdc")
@@ -57,7 +57,7 @@ static bool findRISCVMultilibs(const Driver &D,
Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
return Result.Multilibs.select(Flags, Result.SelectedMultilib);
}
- if (TargetTriple.getArch() == llvm::Triple::riscv32) {
+ if (TargetTriple.isRISCV32()) {
Multilib Imac =
makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
Multilib I =
@@ -92,7 +92,7 @@ static bool findRISCVMultilibs(const Driver &D,
}
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
+ const ArgList &Args)
: ToolChain(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
@@ -103,6 +103,7 @@ BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
if (!SysRoot.empty()) {
llvm::sys::path::append(SysRoot, "lib");
getFilePaths().push_back(std::string(SysRoot));
+ getLibraryPaths().push_back(std::string(SysRoot));
}
}
@@ -140,8 +141,7 @@ static bool isAArch64BareMetal(const llvm::Triple &Triple) {
}
static bool isRISCVBareMetal(const llvm::Triple &Triple) {
- if (Triple.getArch() != llvm::Triple::riscv32 &&
- Triple.getArch() != llvm::Triple::riscv64)
+ if (!Triple.isRISCV())
return false;
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
@@ -173,21 +173,6 @@ Tool *BareMetal::buildLinker() const {
return new tools::baremetal::Linker(*this);
}
-std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); }
-
-std::string BareMetal::buildCompilerRTBasename(const llvm::opt::ArgList &,
- StringRef, FileType,
- bool) const {
- return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str();
-}
-
-std::string BareMetal::getRuntimesDir() const {
- SmallString<128> Dir(getDriver().ResourceDir);
- llvm::sys::path::append(Dir, "lib", "baremetal");
- Dir += SelectedMultilib.gccSuffix();
- return std::string(Dir.str());
-}
-
std::string BareMetal::computeSysRoot() const {
if (!getDriver().SysRoot.empty())
return getDriver().SysRoot + SelectedMultilib.osSuffix();
@@ -226,19 +211,28 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
CC1Args.push_back("-nostdsysteminc");
}
-void BareMetal::AddClangCXXStdlibIncludeArgs(
- const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdinc) ||
DriverArgs.hasArg(options::OPT_nostdlibinc) ||
DriverArgs.hasArg(options::OPT_nostdincxx))
return;
+ const Driver &D = getDriver();
std::string SysRoot(computeSysRoot());
if (SysRoot.empty())
return;
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libcxx: {
+ // First check sysroot/usr/include/c++/v1 if it exists.
+ SmallString<128> TargetDir(SysRoot);
+ llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
+ if (D.getVFS().exists(TargetDir)) {
+ addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
+ break;
+ }
+ // Add generic path if nothing else succeeded so far.
SmallString<128> Dir(SysRoot);
llvm::sys::path::append(Dir, "include", "c++", "v1");
addSystemInclude(DriverArgs, CC1Args, Dir.str());
@@ -250,9 +244,8 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(
std::error_code EC;
Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
// Walk the subdirs, and find the one with the newest gcc version:
- for (llvm::vfs::directory_iterator
- LI = getDriver().getVFS().dir_begin(Dir.str(), EC),
- LE;
+ for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir.str(), EC),
+ LE;
!EC && LI != LE; LI = LI.increment(EC)) {
StringRef VersionText = llvm::sys::path::filename(LI->path());
auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
@@ -292,10 +285,14 @@ void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
ArgStringList &CmdArgs) const {
ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
switch (RLT) {
- case ToolChain::RLT_CompilerRT:
- CmdArgs.push_back(
- Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName()));
+ case ToolChain::RLT_CompilerRT: {
+ const std::string FileName = getCompilerRT(Args, "builtins");
+ llvm::StringRef BaseName = llvm::sys::path::filename(FileName);
+ BaseName.consume_front("lib");
+ BaseName.consume_back(".a");
+ CmdArgs.push_back(Args.MakeArgString("-l" + BaseName));
return;
+ }
case ToolChain::RLT_Libgcc:
CmdArgs.push_back("-lgcc");
return;
@@ -310,7 +307,7 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
ArgStringList CmdArgs;
- auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
+ auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
@@ -322,10 +319,17 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
TC.AddFilePathLibArgs(Args, CmdArgs);
- CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
+ for (const auto &LibPath : TC.getLibraryPaths())
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
+
+ const std::string FileName = TC.getCompilerRT(Args, "builtins");
+ llvm::SmallString<128> PathBuf{FileName};
+ llvm::sys::path::remove_filename(PathBuf);
+ CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf));
if (TC.ShouldLinkCXXStdlib(Args))
TC.AddCXXStdlibLibArgs(Args, CmdArgs);
+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lm");
diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h
index dc718e09ad43..2a16a5beb08d 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.h
+++ b/clang/lib/Driver/ToolChains/BareMetal.h
@@ -1,4 +1,4 @@
-//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===//
+//===--- BareMetal.h - Bare Metal Tool and ToolChain ------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -33,13 +33,9 @@ public:
protected:
Tool *buildLinker() const override;
- std::string buildCompilerRTBasename(const llvm::opt::ArgList &Args,
- StringRef Component,
- FileType Type = ToolChain::FT_Static,
- bool AddArch = true) const override;
-
public:
bool useIntegratedAs() const override { return true; }
+ bool isBareMetal() const override { return true; }
bool isCrossCompiling() const override { return true; }
bool isPICDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
@@ -50,8 +46,6 @@ public:
StringRef getOSLibName() const override { return "baremetal"; }
- std::string getCompilerRTPath() const override;
-
RuntimeLibType GetDefaultRuntimeLibType() const override {
return ToolChain::RLT_CompilerRT;
}
@@ -61,12 +55,13 @@ public:
const char *getDefaultLinker() const override { return "ld.lld"; }
- std::string getRuntimesDir() const;
- void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- Action::OffloadKind DeviceOffloadKind) const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
void AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index b62a025c5072..3d40e19c83a5 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -11,6 +11,7 @@
#include "Arch/AArch64.h"
#include "Arch/ARM.h"
#include "Arch/CSKY.h"
+#include "Arch/LoongArch.h"
#include "Arch/M68k.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
@@ -26,6 +27,7 @@
#include "clang/Basic/CLWarnings.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/CodeGenOptions.h"
+#include "clang/Basic/HeaderInclude.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/MakeSupport.h"
#include "clang/Basic/ObjCRuntime.h"
@@ -43,6 +45,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/ARMTargetParserCommon.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
@@ -50,7 +53,6 @@
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
-#include "llvm/Support/TargetParser.h"
#include "llvm/Support/YAMLParser.h"
#include <cctype>
@@ -291,94 +293,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 Driver &D, const llvm::Triple &Triple,
- const ArgList &Args, ArgStringList &CmdArgs,
- bool ForAS, bool IsAux = false) {
- 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(D, Triple, Args, Features, ForAS);
- break;
-
- case llvm::Triple::ppc:
- case llvm::Triple::ppcle:
- 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(D, Args, Features);
- break;
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- case llvm::Triple::aarch64_be:
- aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS);
- 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, Triple, Args, Features);
- break;
- case llvm::Triple::nvptx:
- case llvm::Triple::nvptx64:
- NVPTX::getNVPTXTargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::m68k:
- m68k::getM68kTargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::msp430:
- msp430::getMSP430TargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::ve:
- ve::getVETargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::csky:
- csky::getCSKYTargetFeatures(D, Triple, Args, CmdArgs, Features);
- break;
- }
-
- for (auto Feature : unifyTargetFeatures(Features)) {
- CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature");
- CmdArgs.push_back(Feature.data());
- }
-}
-
static bool
shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
const llvm::Triple &Triple) {
@@ -533,9 +447,14 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args,
case llvm::Triple::ppc64le:
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
case llvm::Triple::amdgcn:
case llvm::Triple::r600:
case llvm::Triple::csky:
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
return !areOptimizationsEnabled(Args);
default:
break;
@@ -555,7 +474,7 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args,
case llvm::Triple::thumbeb:
if (Triple.isAndroid())
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
case llvm::Triple::mips:
@@ -951,7 +870,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
CmdArgs.push_back("-fprofile-update=atomic");
else if (Val != "single")
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
} else if (SanArgs.needsTsanRt()) {
CmdArgs.push_back("-fprofile-update=atomic");
}
@@ -1050,26 +969,6 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
RelaxDefault);
}
-// Extract the integer N from a string spelled "-dwarf-N", returning 0
-// on mismatch. The StringRef input (rather than an Arg) allows
-// for use by the "-Xassembler" option parser.
-static unsigned DwarfVersionNum(StringRef ArgValue) {
- return llvm::StringSwitch<unsigned>(ArgValue)
- .Case("-gdwarf-2", 2)
- .Case("-gdwarf-3", 3)
- .Case("-gdwarf-4", 4)
- .Case("-gdwarf-5", 5)
- .Default(0);
-}
-
-// Find a DWARF format version option.
-// This function is a complementary for DwarfVersionNum().
-static const Arg *getDwarfNArg(const ArgList &Args) {
- return Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
- options::OPT_gdwarf_4, options::OPT_gdwarf_5,
- options::OPT_gdwarf);
-}
-
static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
codegenoptions::DebugInfoKind DebugInfoKind,
unsigned DwarfVersion,
@@ -1143,32 +1042,22 @@ static void RenderDebugInfoCompressionArgs(const ArgList &Args,
CmdArgs.push_back(
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
} else {
- D.Diag(diag::warn_debug_compression_unavailable);
+ D.Diag(diag::warn_debug_compression_unavailable) << "zlib";
+ }
+ } else if (Value == "zstd") {
+ if (llvm::compression::zstd::isAvailable()) {
+ CmdArgs.push_back(
+ Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
+ } else {
+ D.Diag(diag::warn_debug_compression_unavailable) << "zstd";
}
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
-static const char *RelocationModelName(llvm::Reloc::Model Model) {
- switch (Model) {
- case llvm::Reloc::Static:
- return "static";
- case llvm::Reloc::PIC_:
- return "pic";
- case llvm::Reloc::DynamicNoPIC:
- return "dynamic-no-pic";
- case llvm::Reloc::ROPI:
- return "ropi";
- case llvm::Reloc::RWPI:
- return "rwpi";
- case llvm::Reloc::ROPI_RWPI:
- return "ropi-rwpi";
- }
- llvm_unreachable("Unknown Reloc::Model kind");
-}
static void handleAMDGPUCodeObjectVersionOptions(const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -1305,6 +1194,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
// openmp_wrappers folder which contains alternative system headers.
if (JA.isDeviceOffloading(Action::OFK_OpenMP) &&
!Args.hasArg(options::OPT_nostdinc) &&
+ !Args.hasArg(options::OPT_nogpuinc) &&
(getToolChain().getTriple().isNVPTX() ||
getToolChain().getTriple().isAMDGCN())) {
if (!Args.hasArg(options::OPT_nobuiltininc)) {
@@ -1485,6 +1375,11 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_ffile_reproducible,
options::OPT_fno_file_reproducible);
+
+ if (const char *Epoch = std::getenv("SOURCE_DATE_EPOCH")) {
+ CmdArgs.push_back("-source-date-epoch");
+ CmdArgs.push_back(Args.MakeArgString(Epoch));
+ }
}
// FIXME: Move to target hook.
@@ -1660,7 +1555,7 @@ void RenderARMABI(const Driver &D, const llvm::Triple &Triple,
void AddUnalignedAccessWarning(ArgStringList &CmdArgs) {
auto StrictAlignIter =
- std::find_if(CmdArgs.rbegin(), CmdArgs.rend(), [](StringRef Arg) {
+ llvm::find_if(llvm::reverse(CmdArgs), [](StringRef Arg) {
return Arg == "+strict-align" || Arg == "-strict-align";
});
if (StrictAlignIter != CmdArgs.rend() &&
@@ -1691,7 +1586,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
Scope = A->getValue();
if (Scope != "none" && Scope != "non-leaf" && Scope != "all")
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Scope;
+ << A->getSpelling() << Scope;
Key = "a_key";
IndirectBranches = false;
} else {
@@ -1699,7 +1594,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
llvm::ARM::ParsedBranchProtection PBP;
if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg))
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << DiagMsg;
+ << A->getSpelling() << DiagMsg;
if (!isAArch64 && PBP.Key == "b_key")
D.Diag(diag::warn_unsupported_branch_protection)
<< "b-key" << A->getAsString(Args);
@@ -1784,14 +1679,17 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple,
case llvm::Triple::thumbeb:
// Use the effective triple, which takes into account the deployment target.
AddARMTargetArgs(EffectiveTriple, Args, CmdArgs, KernelOrKext);
- CmdArgs.push_back("-fallow-half-arguments-and-returns");
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_32:
case llvm::Triple::aarch64_be:
AddAArch64TargetArgs(Args, CmdArgs);
- CmdArgs.push_back("-fallow-half-arguments-and-returns");
+ break;
+
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ AddLoongArchTargetArgs(Args, CmdArgs);
break;
case llvm::Triple::mips:
@@ -1917,7 +1815,7 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
} else if (!Val.equals("scalable"))
// Handle the unsupported values passed to msve-vector-bits.
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
}
AddAAPCSVolatileBitfieldArgs(Args, CmdArgs);
@@ -1933,6 +1831,14 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
AddUnalignedAccessWarning(CmdArgs);
}
+void Clang::AddLoongArchTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-target-abi");
+ CmdArgs.push_back(loongarch::getLoongArchABI(getToolChain().getDriver(), Args,
+ getToolChain().getTriple())
+ .data());
+}
+
void Clang::AddMIPSTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
@@ -2067,7 +1973,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val));
} else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
} else
D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName;
}
@@ -2083,6 +1989,14 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
void Clang::AddPPCTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
+ CmdArgs.push_back("-tune-cpu");
+ if (strcmp(A->getValue(), "native") == 0)
+ CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));
+ else
+ CmdArgs.push_back(A->getValue());
+ }
+
// Select the ABI to use.
const char *ABIName = nullptr;
const llvm::Triple &T = getToolChain().getTriple();
@@ -2181,11 +2095,16 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args,
SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs);
+ if (!Args.hasFlag(options::OPT_mimplicit_float,
+ options::OPT_mno_implicit_float, true))
+ CmdArgs.push_back("-no-implicit-float");
+
if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) {
- StringRef Name =
- llvm::RISCV::resolveTuneCPUAlias(A->getValue(), Triple.isArch64Bit());
CmdArgs.push_back("-tune-cpu");
- CmdArgs.push_back(Name.data());
+ if (strcmp(A->getValue(), "native") == 0)
+ CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName()));
+ else
+ CmdArgs.push_back(A->getValue());
}
}
@@ -2205,6 +2124,18 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
+
+ if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) {
+ StringRef Name = A->getValue();
+ std::string TuneCPU;
+ if (Name == "native")
+ TuneCPU = std::string(llvm::sys::getHostCPUName());
+ else
+ TuneCPU = std::string(Name);
+
+ CmdArgs.push_back("-tune-cpu");
+ CmdArgs.push_back(Args.MakeArgString(TuneCPU));
+ }
}
void Clang::AddSystemZTargetArgs(const ArgList &Args,
@@ -2277,7 +2208,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-inline-asm=" + Value));
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
} else if (D.IsCLMode()) {
CmdArgs.push_back("-mllvm");
@@ -2329,8 +2260,8 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
CmdArgs.push_back("-mllvm");
- CmdArgs.push_back(Args.MakeArgString("-hexagon-small-data-threshold=" +
- Twine(G.value())));
+ CmdArgs.push_back(
+ Args.MakeArgString("-hexagon-small-data-threshold=" + Twine(*G)));
}
if (!Args.hasArg(options::OPT_fno_short_enums))
@@ -2360,7 +2291,7 @@ void Clang::AddLanaiTargetArgs(const ArgList &Args,
if (Mregparm != 4) {
getToolChain().getDriver().Diag(
diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
@@ -2370,10 +2301,8 @@ void Clang::AddWebAssemblyTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Default to "hidden" visibility.
if (!Args.hasArg(options::OPT_fvisibility_EQ,
- options::OPT_fvisibility_ms_compat)) {
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back("hidden");
- }
+ options::OPT_fvisibility_ms_compat))
+ CmdArgs.push_back("-fvisibility=hidden");
}
void Clang::AddVETargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
@@ -2543,7 +2472,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
ImplicitIt = A->getValue();
if (!CheckARMImplicitITArg(ImplicitIt))
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << ImplicitIt;
+ << A->getSpelling() << ImplicitIt;
continue;
default:
break;
@@ -2564,6 +2493,13 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
switch (C.getDefaultToolChain().getArch()) {
default:
break;
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ if (Value == "--no-type-check") {
+ CmdArgs.push_back("-mno-type-check");
+ continue;
+ }
+ break;
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
case llvm::Triple::arm:
@@ -2699,14 +2635,14 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
D.PrintVersion(C, llvm::outs());
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
if (ImplicitIt.size())
AddARMImplicitITArgs(Args, CmdArgs, ImplicitIt);
- if (UseRelaxRelocations)
- CmdArgs.push_back("--mrelax-relocations");
+ if (!UseRelaxRelocations)
+ CmdArgs.push_back("-mrelax-relocations=no");
if (UseNoExecStack)
CmdArgs.push_back("-mnoexecstack");
if (MipsTargetFeature != nullptr) {
@@ -2718,6 +2654,11 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
if (C.getDriver().embedBitcodeEnabled() ||
C.getDriver().embedBitcodeMarkerOnly())
Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ);
+
+ if (const char *AsSecureLogFile = getenv("AS_SECURE_LOG_FILE")) {
+ CmdArgs.push_back("-as-secure-log-file");
+ CmdArgs.push_back(Args.MakeArgString(AsSecureLogFile));
+ }
}
static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
@@ -2758,10 +2699,13 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// CUDA and HIP don't rely on the frontend to pass an ffp-contract option.
// If one wasn't given by the user, don't pass it here.
StringRef FPContract;
+ StringRef LastSeenFfpContractOption;
+ bool SeenUnsafeMathModeOption = false;
if (!JA.isDeviceOffloading(Action::OFK_Cuda) &&
!JA.isOffloading(Action::OFK_HIP))
FPContract = "on";
bool StrictFPModel = false;
+ StringRef Float16ExcessPrecision = "";
if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
@@ -2778,6 +2722,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// If -ffp-model= is seen, reset to fno-fast-math
HonorINFs = true;
HonorNaNs = true;
+ ApproxFunc = false;
// Turning *off* -ffast-math restores the toolchain default.
MathErrno = TC.IsMathErrnoDefault();
AssociativeMath = false;
@@ -2826,7 +2771,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
TrappingMath = true;
} else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
break;
}
}
@@ -2908,11 +2853,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// -ffp-model=precise sets PreciseFPModel to on and Val to
// "precise". FPContract is set.
;
- } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off"))
+ } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) {
FPContract = Val;
- else
+ LastSeenFfpContractOption = Val;
+ } else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
break;
}
@@ -2940,7 +2886,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
TrappingMath = TrappingMathPresent = true;
} else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
break;
}
@@ -2952,10 +2898,31 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
FPEvalMethod = Val;
else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
break;
}
+ case options::OPT_fexcess_precision_EQ: {
+ StringRef Val = A->getValue();
+ const llvm::Triple::ArchType Arch = TC.getArch();
+ if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
+ if (Val.equals("standard") || Val.equals("fast"))
+ Float16ExcessPrecision = Val;
+ // To make it GCC compatible, allow the value of "16" which
+ // means disable excess precision, the same meaning than clang's
+ // equivalent value "none".
+ else if (Val.equals("16"))
+ Float16ExcessPrecision = "none";
+ else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ } else {
+ if (!(Val.equals("standard") || Val.equals("fast")))
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ }
+ break;
+ }
case options::OPT_ffinite_math_only:
HonorINFs = false;
HonorNaNs = false;
@@ -2972,6 +2939,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
ApproxFunc = true;
TrappingMath = false;
FPExceptionBehavior = "";
+ FPContract = "fast";
+ SeenUnsafeMathModeOption = true;
break;
case options::OPT_fno_unsafe_math_optimizations:
AssociativeMath = false;
@@ -2984,13 +2953,20 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
// The target may have opted to flush by default, so force IEEE.
DenormalFPMath = llvm::DenormalMode::getIEEE();
DenormalFP32Math = llvm::DenormalMode::getIEEE();
+ if (!JA.isDeviceOffloading(Action::OFK_Cuda) &&
+ !JA.isOffloading(Action::OFK_HIP)) {
+ if (LastSeenFfpContractOption != "") {
+ FPContract = LastSeenFfpContractOption;
+ } else if (SeenUnsafeMathModeOption)
+ FPContract = "on";
+ }
break;
case options::OPT_Ofast:
// If -Ofast is the optimization level, then -ffast-math should be enabled
if (!OFastEnabled)
continue;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case options::OPT_ffast_math:
HonorINFs = false;
HonorNaNs = false;
@@ -3001,8 +2977,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
SignedZeros = false;
TrappingMath = false;
RoundingFPMath = false;
+ FPExceptionBehavior = "";
// If fast-math is set then set the fp-contract mode to fast.
FPContract = "fast";
+ SeenUnsafeMathModeOption = true;
break;
case options::OPT_fno_fast_math:
HonorINFs = true;
@@ -3019,13 +2997,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
DenormalFPMath = DefaultDenormalFPMath;
DenormalFP32Math = llvm::DenormalMode::getIEEE();
if (!JA.isDeviceOffloading(Action::OFK_Cuda) &&
- !JA.isOffloading(Action::OFK_HIP))
- if (FPContract == "fast") {
+ !JA.isOffloading(Action::OFK_HIP)) {
+ if (LastSeenFfpContractOption != "") {
+ FPContract = LastSeenFfpContractOption;
+ } else if (SeenUnsafeMathModeOption)
FPContract = "on";
- D.Diag(clang::diag::warn_drv_overriding_flag_option)
- << "-ffp-contract=fast"
- << "-ffp-contract=on";
- }
+ }
break;
}
if (StrictFPModel) {
@@ -3041,10 +3018,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
else {
StrictFPModel = false;
FPModel = "";
- D.Diag(clang::diag::warn_drv_overriding_flag_option)
- << "-ffp-model=strict" <<
- ((A->getNumValues() == 0) ? A->getSpelling()
- : Args.MakeArgString(A->getSpelling() + A->getValue()));
+ auto RHS = (A->getNumValues() == 0)
+ ? A->getSpelling()
+ : Args.MakeArgString(A->getSpelling() + A->getValue());
+ if (RHS != "-ffp-model=strict")
+ D.Diag(clang::diag::warn_drv_overriding_flag_option)
+ << "-ffp-model=strict" << RHS;
}
}
@@ -3064,9 +3043,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (MathErrno)
CmdArgs.push_back("-fmath-errno");
- if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros &&
- ApproxFunc && !TrappingMath)
- CmdArgs.push_back("-menable-unsafe-fp-math");
+ if (AssociativeMath && ReciprocalMath && !SignedZeros && ApproxFunc &&
+ !TrappingMath)
+ CmdArgs.push_back("-funsafe-math-optimizations");
if (!SignedZeros)
CmdArgs.push_back("-fno-signed-zeros");
@@ -3114,6 +3093,10 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
if (!FPEvalMethod.empty())
CmdArgs.push_back(Args.MakeArgString("-ffp-eval-method=" + FPEvalMethod));
+ if (!Float16ExcessPrecision.empty())
+ CmdArgs.push_back(Args.MakeArgString("-ffloat16-excess-precision=" +
+ Float16ExcessPrecision));
+
ParseMRecip(D, Args, CmdArgs);
// -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the
@@ -3256,6 +3239,12 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
StackProtectorLevel = LangOptions::SSPStrong;
else if (A->getOption().matches(options::OPT_fstack_protector_all))
StackProtectorLevel = LangOptions::SSPReq;
+
+ if (EffectiveTriple.isBPF() && StackProtectorLevel != LangOptions::SSPOff) {
+ D.Diag(diag::warn_drv_unsupported_option_for_target)
+ << A->getSpelling() << EffectiveTriple.getTriple();
+ StackProtectorLevel = DefaultStackProtectorLevel;
+ }
} else {
StackProtectorLevel = DefaultStackProtectorLevel;
}
@@ -3406,7 +3395,7 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D,
TrivialAutoVarInit = Val;
else
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
break;
}
}
@@ -3425,8 +3414,6 @@ static void RenderTrivialAutoVarInitOptions(const Driver &D,
}
if (!TrivialAutoVarInit.empty()) {
- if (TrivialAutoVarInit == "zero" && !Args.hasArg(options::OPT_enable_trivial_var_init_zero))
- D.Diag(diag::err_drv_trivial_auto_var_init_zero_disabled);
CmdArgs.push_back(
Args.MakeArgString("-ftrivial-auto-var-init=" + TrivialAutoVarInit));
}
@@ -3492,17 +3479,21 @@ static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs,
options::OPT_D,
options::OPT_I,
options::OPT_S,
+ options::OPT_O,
options::OPT_emit_llvm,
+ options::OPT_emit_obj,
options::OPT_disable_llvm_passes,
- options::OPT_fnative_half_type};
-
+ options::OPT_fnative_half_type,
+ options::OPT_hlsl_entrypoint};
+ if (!types::isHLSL(InputType))
+ return;
for (const auto &Arg : ForwardedArguments)
if (const auto *A = Args.getLastArg(Arg))
A->renderAsInput(Args, CmdArgs);
// Add the default headers if dxc_no_stdinc is not set.
- if (!Args.hasArg(options::OPT_dxc_no_stdinc))
+ if (!Args.hasArg(options::OPT_dxc_no_stdinc) &&
+ !Args.hasArg(options::OPT_nostdinc))
CmdArgs.push_back("-finclude-default-header");
- CmdArgs.push_back("-fallow-half-arguments-and-returns");
}
static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args,
@@ -3621,10 +3612,19 @@ bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) {
return false;
}
-static void RenderModulesOptions(Compilation &C, const Driver &D,
+static bool RenderModulesOptions(Compilation &C, const Driver &D,
const ArgList &Args, const InputInfo &Input,
- const InputInfo &Output,
- ArgStringList &CmdArgs, bool &HaveModules) {
+ const InputInfo &Output, const Arg *Std,
+ ArgStringList &CmdArgs) {
+ bool IsCXX = types::isCXX(Input.getType());
+ // FIXME: Find a better way to determine whether the input has standard c++
+ // modules support by default.
+ bool HaveStdCXXModules =
+ IsCXX && Std &&
+ (Std->containsValue("c++2a") || Std->containsValue("c++20") ||
+ Std->containsValue("c++2b") || Std->containsValue("c++latest"));
+ bool HaveModules = HaveStdCXXModules;
+
// -fmodules enables the use of precompiled modules (off by default).
// Users can pass -fno-cxx-modules to turn off modules support for
// C++/Objective-C++ programs.
@@ -3632,7 +3632,7 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
options::OPT_fno_cxx_modules, true);
- if (AllowedInCXX || !types::isCXX(Input.getType())) {
+ if (AllowedInCXX || !IsCXX) {
CmdArgs.push_back("-fmodules");
HaveClangModules = true;
}
@@ -3640,6 +3640,7 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
HaveModules |= HaveClangModules;
if (Args.hasArg(options::OPT_fmodules_ts)) {
+ D.Diag(diag::warn_deprecated_fmodules_ts_flag);
CmdArgs.push_back("-fmodules-ts");
HaveModules = true;
}
@@ -3803,6 +3804,12 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
Args.ClaimAllArgs(options::OPT_fno_modules_validate_system_headers);
Args.ClaimAllArgs(options::OPT_fmodules_disable_diagnostic_validation);
}
+
+ // Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings.
+ Args.ClaimAllArgs(options::OPT_fmodule_output);
+ Args.ClaimAllArgs(options::OPT_fmodule_output_EQ);
+
+ return HaveModules;
}
static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T,
@@ -4051,7 +4058,7 @@ DwarfFissionKind tools::getDebugFissionKind(const Driver &D,
return DwarfFissionKind::Single;
D.Diag(diag::err_drv_unsupported_option_argument)
- << Arg->getOption().getName() << Arg->getValue();
+ << Arg->getSpelling() << Arg->getValue();
return DwarfFissionKind::None;
}
@@ -4137,8 +4144,10 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
}
// If a debugger tuning argument appeared, remember it.
+ bool HasDebuggerTuning = false;
if (const Arg *A =
Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) {
+ HasDebuggerTuning = true;
if (checkDebugInfoOption(A, Args, D, TC)) {
if (A->getOption().matches(options::OPT_glldb))
DebuggerTuning = llvm::DebuggerKind::LLDB;
@@ -4152,19 +4161,12 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
}
// If a -gdwarf argument appeared, remember it.
- const Arg *GDwarfN = getDwarfNArg(Args);
bool EmitDwarf = false;
- if (GDwarfN) {
- if (checkDebugInfoOption(GDwarfN, Args, D, TC))
- EmitDwarf = true;
- else
- GDwarfN = nullptr;
- }
+ if (const Arg *A = getDwarfNArg(Args))
+ EmitDwarf = checkDebugInfoOption(A, Args, D, TC);
- if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) {
- if (checkDebugInfoOption(A, Args, D, TC))
- EmitCodeView = true;
- }
+ if (const Arg *A = Args.getLastArg(options::OPT_gcodeview))
+ EmitCodeView = checkDebugInfoOption(A, Args, D, TC);
// If the user asked for debug info but did not explicitly specify -gcodeview
// or -gdwarf, ask the toolchain for the default format.
@@ -4183,25 +4185,13 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
unsigned RequestedDWARFVersion = 0; // DWARF version requested by the user
unsigned EffectiveDWARFVersion = 0; // DWARF version TC can generate. It may
// be lower than what the user wanted.
- unsigned DefaultDWARFVersion = ParseDebugDefaultVersion(TC, Args);
if (EmitDwarf) {
- // Start with the platform default DWARF version
- RequestedDWARFVersion = TC.GetDefaultDwarfVersion();
- assert(RequestedDWARFVersion &&
- "toolchain default DWARF version must be nonzero");
-
- // If the user specified a default DWARF version, that takes precedence
- // over the platform default.
- if (DefaultDWARFVersion)
- RequestedDWARFVersion = DefaultDWARFVersion;
-
- // Override with a user-specified DWARF version
- if (GDwarfN)
- if (auto ExplicitVersion = DwarfVersionNum(GDwarfN->getSpelling()))
- RequestedDWARFVersion = ExplicitVersion;
+ RequestedDWARFVersion = getDwarfVersion(TC, Args);
// Clamp effective DWARF version to the max supported by the toolchain.
EffectiveDWARFVersion =
std::min(RequestedDWARFVersion, TC.getMaxDwarfVersion());
+ } else {
+ Args.ClaimAllArgs(options::OPT_fdebug_default_version);
}
// -gline-directives-only supported only for the DWARF debug info.
@@ -4235,9 +4225,11 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
CmdArgs.push_back("-gno-column-info");
// FIXME: Move backend command line options to the module.
- // If -gline-tables-only or -gline-directives-only is the last option it wins.
- if (const Arg *A = Args.getLastArg(options::OPT_gmodules))
- if (checkDebugInfoOption(A, Args, D, TC)) {
+ if (Args.hasFlag(options::OPT_gmodules, options::OPT_gno_modules, false)) {
+ // If -gline-tables-only or -gline-directives-only is the last option it
+ // wins.
+ if (checkDebugInfoOption(Args.getLastArg(options::OPT_gmodules), Args, D,
+ TC)) {
if (DebugInfoKind != codegenoptions::DebugLineTablesOnly &&
DebugInfoKind != codegenoptions::DebugDirectivesOnly) {
DebugInfoKind = codegenoptions::DebugInfoConstructor;
@@ -4245,6 +4237,7 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
CmdArgs.push_back("-fmodule-format=obj");
}
}
+ }
if (T.isOSBinFormatELF() && SplitDWARFInlining)
CmdArgs.push_back("-fsplit-dwarf-inlining");
@@ -4293,19 +4286,16 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
if (EmitCodeView) {
CmdArgs.push_back("-gcodeview");
- // Emit codeview type hashes if requested.
- if (Args.hasFlag(options::OPT_gcodeview_ghash,
- options::OPT_gno_codeview_ghash, false)) {
- CmdArgs.push_back("-gcodeview-ghash");
- }
- }
+ Args.addOptInFlag(CmdArgs, options::OPT_gcodeview_ghash,
+ options::OPT_gno_codeview_ghash);
- // Omit inline line tables if requested.
- if (Args.hasFlag(options::OPT_gno_inline_line_tables,
- options::OPT_ginline_line_tables, false)) {
- CmdArgs.push_back("-gno-inline-line-tables");
+ Args.addOptOutFlag(CmdArgs, options::OPT_gcodeview_command_line,
+ options::OPT_gno_codeview_command_line);
}
+ Args.addOptOutFlag(CmdArgs, options::OPT_ginline_line_tables,
+ options::OPT_gno_inline_line_tables);
+
// When emitting remarks, we need at least debug lines in the output.
if (willEmitRemarks(Args) &&
DebugInfoKind <= codegenoptions::DebugDirectivesOnly)
@@ -4314,8 +4304,12 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
// Adjust the debug info kind for the given toolchain.
TC.adjustDebugInfoKind(DebugInfoKind, Args);
+ // On AIX, the debugger tuning option can be omitted if it is not explicitly
+ // set.
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, EffectiveDWARFVersion,
- DebuggerTuning);
+ T.isOSAIX() && !HasDebuggerTuning
+ ? llvm::DebuggerKind::Default
+ : DebuggerTuning);
// -fdebug-macro turns on macro debug info generation.
if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro,
@@ -4350,11 +4344,14 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
}
}
- if (Args.hasFlag(options::OPT_fdebug_ranges_base_address,
- options::OPT_fno_debug_ranges_base_address, false)) {
- CmdArgs.push_back("-fdebug-ranges-base-address");
+ if (const Arg *A = Args.getLastArg(options::OPT_gsrc_hash_EQ)) {
+ StringRef v = A->getValue();
+ CmdArgs.push_back(Args.MakeArgString("-gsrc-hash=" + v));
}
+ Args.addOptInFlag(CmdArgs, options::OPT_fdebug_ranges_base_address,
+ options::OPT_fno_debug_ranges_base_address);
+
// -gdwarf-aranges turns on the emission of the aranges section in the
// backend.
// Always enabled for SCE tuning.
@@ -4366,9 +4363,8 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
CmdArgs.push_back("-generate-arange-section");
}
- if (Args.hasFlag(options::OPT_fforce_dwarf_frame,
- options::OPT_fno_force_dwarf_frame, false))
- CmdArgs.push_back("-fforce-dwarf-frame");
+ Args.addOptInFlag(CmdArgs, options::OPT_fforce_dwarf_frame,
+ options::OPT_fno_force_dwarf_frame);
if (Args.hasFlag(options::OPT_fdebug_types_section,
options::OPT_fno_debug_types_section, false)) {
@@ -4407,6 +4403,71 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D,
RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC);
}
+static void ProcessVSRuntimeLibrary(const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ unsigned RTOptionID = options::OPT__SLASH_MT;
+
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ // The /LDd option implies /MTd. The dependent lib part can be overridden,
+ // but defining _DEBUG is sticky.
+ RTOptionID = options::OPT__SLASH_MTd;
+
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group))
+ RTOptionID = A->getOption().getID();
+
+ if (Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) {
+ RTOptionID = llvm::StringSwitch<unsigned>(A->getValue())
+ .Case("static", options::OPT__SLASH_MT)
+ .Case("static_dbg", options::OPT__SLASH_MTd)
+ .Case("dll", options::OPT__SLASH_MD)
+ .Case("dll_dbg", options::OPT__SLASH_MDd)
+ .Default(options::OPT__SLASH_MT);
+ }
+
+ StringRef FlagForCRT;
+ switch (RTOptionID) {
+ case options::OPT__SLASH_MD:
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ FlagForCRT = "--dependent-lib=msvcrt";
+ break;
+ case options::OPT__SLASH_MDd:
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-D_DLL");
+ FlagForCRT = "--dependent-lib=msvcrtd";
+ break;
+ case options::OPT__SLASH_MT:
+ if (Args.hasArg(options::OPT__SLASH_LDd))
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-flto-visibility-public-std");
+ FlagForCRT = "--dependent-lib=libcmt";
+ break;
+ case options::OPT__SLASH_MTd:
+ CmdArgs.push_back("-D_DEBUG");
+ CmdArgs.push_back("-D_MT");
+ CmdArgs.push_back("-flto-visibility-public-std");
+ FlagForCRT = "--dependent-lib=libcmtd";
+ break;
+ default:
+ llvm_unreachable("Unexpected option ID.");
+ }
+
+ if (Args.hasArg(options::OPT_fms_omit_default_lib)) {
+ CmdArgs.push_back("-D_VC_NODEFAULTLIB");
+ } else {
+ CmdArgs.push_back(FlagForCRT.data());
+
+ // This provides POSIX compatibility (maps 'open' to '_open'), which most
+ // users want. The /Za flag to cl.exe turns this off, but it's not
+ // implemented in clang.
+ CmdArgs.push_back("--dependent-lib=oldnames");
+ }
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args, const char *LinkingOutput) const {
@@ -4432,14 +4493,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
bool IsHIP = JA.isOffloading(Action::OFK_HIP);
bool IsHIPDevice = JA.isDeviceOffloading(Action::OFK_HIP);
bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
- bool IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA);
bool IsExtractAPI = isa<ExtractAPIJobAction>(JA);
bool IsDeviceOffloadAction = !(JA.isDeviceOffloading(Action::OFK_None) ||
JA.isDeviceOffloading(Action::OFK_Host));
bool IsHostOffloadingAction =
- (JA.isHostOffloading(Action::OFK_OpenMP) &&
- Args.hasFlag(options::OPT_fopenmp_new_driver,
- options::OPT_no_offload_new_driver, true)) ||
+ JA.isHostOffloading(Action::OFK_OpenMP) ||
(JA.isHostOffloading(C.getActiveOffloadKinds()) &&
Args.hasFlag(options::OPT_offload_new_driver,
options::OPT_no_offload_new_driver, false));
@@ -4449,44 +4507,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction);
auto LTOMode = D.getLTOMode(IsDeviceOffloadAction);
- // A header module compilation doesn't have a main input file, so invent a
- // fake one as a placeholder.
- const char *ModuleName = [&] {
- auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ);
- return ModuleNameArg ? ModuleNameArg->getValue() : "";
- }();
- InputInfo HeaderModuleInput(Inputs[0].getType(), ModuleName, ModuleName);
-
// Extract API doesn't have a main input file, so invent a fake one as a
// placeholder.
InputInfo ExtractAPIPlaceholderInput(Inputs[0].getType(), "extract-api",
"extract-api");
- const InputInfo &Input = [&]() -> const InputInfo & {
- if (IsHeaderModulePrecompile)
- return HeaderModuleInput;
- if (IsExtractAPI)
- return ExtractAPIPlaceholderInput;
- return Inputs[0];
- }();
+ const InputInfo &Input =
+ IsExtractAPI ? ExtractAPIPlaceholderInput : Inputs[0];
- InputInfoList ModuleHeaderInputs;
InputInfoList ExtractAPIInputs;
InputInfoList HostOffloadingInputs;
const InputInfo *CudaDeviceInput = nullptr;
const InputInfo *OpenMPDeviceInput = nullptr;
for (const InputInfo &I : Inputs) {
- if (&I == &Input) {
- // This is the primary input.
- } else if (IsHeaderModulePrecompile &&
- types::getPrecompiledType(I.getType()) == types::TY_PCH) {
- types::ID Expected = HeaderModuleInput.getType();
- if (I.getType() != Expected) {
- D.Diag(diag::err_drv_module_header_wrong_kind)
- << I.getFilename() << types::getTypeName(I.getType())
- << types::getTypeName(Expected);
- }
- ModuleHeaderInputs.push_back(I);
+ if (&I == &Input || I.getType() == types::TY_Nothing) {
+ // This is the primary input or contains nothing.
} else if (IsExtractAPI) {
auto ExpectedInputType = ExtractAPIPlaceholderInput.getType();
if (I.getType() != ExpectedInputType) {
@@ -4674,9 +4709,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (JA.getType() == types::TY_Nothing)
CmdArgs.push_back("-fsyntax-only");
else if (JA.getType() == types::TY_ModuleFile)
- CmdArgs.push_back(IsHeaderModulePrecompile
- ? "-emit-header-module"
- : "-emit-module-interface");
+ CmdArgs.push_back("-emit-module-interface");
else if (JA.getType() == types::TY_HeaderUnit)
CmdArgs.push_back("-emit-header-unit");
else
@@ -4689,6 +4722,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-extract-api");
if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ))
ProductNameArg->render(Args, CmdArgs);
+ if (Arg *ExtractAPIIgnoresFileArg =
+ Args.getLastArg(options::OPT_extract_api_ignores_EQ))
+ ExtractAPIIgnoresFileArg->render(Args, CmdArgs);
} else {
assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) &&
"Invalid action for clang tool.");
@@ -4739,10 +4775,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-emit-llvm-uselists");
if (IsUsingLTO) {
- // Only AMDGPU supports device-side LTO.
- if (IsDeviceOffloadAction &&
- !Args.hasFlag(options::OPT_fopenmp_new_driver,
- options::OPT_no_offload_new_driver, true) &&
+ if (IsDeviceOffloadAction && !JA.isDeviceOffloading(Action::OFK_OpenMP) &&
!Args.hasFlag(options::OPT_offload_new_driver,
options::OPT_no_offload_new_driver, false) &&
!Triple.isAMDGPU()) {
@@ -4751,6 +4784,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_foffload_lto_EQ)
->getAsString(Args)
<< Triple.getTriple();
+ } else if (Triple.isNVPTX() && !IsRDCMode &&
+ JA.isDeviceOffloading(Action::OFK_Cuda)) {
+ D.Diag(diag::err_drv_unsupported_opt_for_language_mode)
+ << Args.getLastArg(options::OPT_foffload_lto,
+ options::OPT_foffload_lto_EQ)
+ ->getAsString(Args)
+ << "-fno-gpu-rdc";
} else {
assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin);
CmdArgs.push_back(Args.MakeArgString(
@@ -4952,13 +4992,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Since we can't access frontend flags through hasArg, let's manually iterate
// through them.
bool FoundAnalyzerConfig = false;
- for (auto Arg : Args.filtered(options::OPT_Xclang))
+ for (auto *Arg : Args.filtered(options::OPT_Xclang))
if (StringRef(Arg->getValue()) == "-analyzer-config") {
FoundAnalyzerConfig = true;
break;
}
if (!FoundAnalyzerConfig)
- for (auto Arg : Args.filtered(options::OPT_Xanalyzer))
+ for (auto *Arg : Args.filtered(options::OPT_Xanalyzer))
if (StringRef(Arg->getValue()) == "-analyzer-config") {
FoundAnalyzerConfig = true;
break;
@@ -4995,6 +5035,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
unsigned PICLevel;
bool IsPIE;
std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(TC, Args);
+ Arg *LastPICDataRelArg =
+ Args.getLastArg(options::OPT_mno_pic_data_is_text_relative,
+ options::OPT_mpic_data_is_text_relative);
+ bool NoPICDataIsTextRelative = false;
+ if (LastPICDataRelArg) {
+ if (LastPICDataRelArg->getOption().matches(
+ options::OPT_mno_pic_data_is_text_relative)) {
+ NoPICDataIsTextRelative = true;
+ if (!PICLevel)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-mno-pic-data-is-text-relative"
+ << "-fpic/-fpie";
+ }
+ if (!Triple.isSystemZ())
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << (NoPICDataIsTextRelative ? "-mno-pic-data-is-text-relative"
+ : "-mpic-data-is-text-relative")
+ << RawTriple.str();
+ }
bool IsROPI = RelocationModel == llvm::Reloc::ROPI ||
RelocationModel == llvm::Reloc::ROPI_RWPI;
@@ -5023,6 +5082,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
if (IsPIE)
CmdArgs.push_back("-pic-is-pie");
+ if (NoPICDataIsTextRelative)
+ CmdArgs.push_back("-mcmodel=medium");
}
if (RelocationModel == llvm::Reloc::ROPI ||
@@ -5079,15 +5140,33 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- Args.AddLastArg(CmdArgs, options::OPT_fveclib);
+ if (Arg *A = Args.getLastArg(options::OPT_fveclib)) {
+ StringRef Name = A->getValue();
+ if (Name == "SVML") {
+ if (Triple.getArch() != llvm::Triple::x86 &&
+ Triple.getArch() != llvm::Triple::x86_64)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ } else if (Name == "LIBMVEC-X86") {
+ if (Triple.getArch() != llvm::Triple::x86 &&
+ Triple.getArch() != llvm::Triple::x86_64)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ } else if (Name == "SLEEF") {
+ if (Triple.getArch() != llvm::Triple::aarch64 &&
+ Triple.getArch() != llvm::Triple::aarch64_be)
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << Name << Triple.getArchName();
+ }
+ A->render(Args, CmdArgs);
+ }
if (Args.hasFlag(options::OPT_fmerge_all_constants,
options::OPT_fno_merge_all_constants, false))
CmdArgs.push_back("-fmerge-all-constants");
- if (Args.hasFlag(options::OPT_fno_delete_null_pointer_checks,
- options::OPT_fdelete_null_pointer_checks, false))
- CmdArgs.push_back("-fno-delete-null-pointer-checks");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fdelete_null_pointer_checks,
+ options::OPT_fno_delete_null_pointer_checks);
// LLVM Code Generator Options.
@@ -5242,9 +5321,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_experimental_relative_cxx_abi_vtables);
// Handle segmented stacks.
- if (Args.hasFlag(options::OPT_fsplit_stack, options::OPT_fno_split_stack,
- false))
- CmdArgs.push_back("-fsplit-stack");
+ Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack,
+ options::OPT_fno_split_stack);
// -fprotect-parens=0 is default.
if (Args.hasFlag(options::OPT_fprotect_parens,
@@ -5367,17 +5445,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
// complicated ways.
auto SanitizeArgs = TC.getSanitizerArgs(Args);
+
+ bool IsAsyncUnwindTablesDefault =
+ TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Asynchronous;
+ bool IsSyncUnwindTablesDefault =
+ TC.getDefaultUnwindTableLevel(Args) == ToolChain::UnwindTableLevel::Synchronous;
+
bool AsyncUnwindTables = Args.hasFlag(
options::OPT_fasynchronous_unwind_tables,
options::OPT_fno_asynchronous_unwind_tables,
- (TC.IsUnwindTablesDefault(Args) || SanitizeArgs.needsUnwindTables()) &&
+ (IsAsyncUnwindTablesDefault || SanitizeArgs.needsUnwindTables()) &&
!Freestanding);
- bool UnwindTables = Args.hasFlag(options::OPT_funwind_tables,
- options::OPT_fno_unwind_tables, false);
+ bool UnwindTables =
+ Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
+ IsSyncUnwindTablesDefault && !Freestanding);
if (AsyncUnwindTables)
CmdArgs.push_back("-funwind-tables=2");
else if (UnwindTables)
- CmdArgs.push_back("-funwind-tables=1");
+ CmdArgs.push_back("-funwind-tables=1");
// Prepare `-aux-target-cpu` and `-aux-target-feature` unless
// `--gpu-use-aux-triple-only` is specified.
@@ -5403,6 +5488,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CM == "tiny") {
if (Triple.isOSAIX() && CM == "medium")
CmdArgs.push_back("-mcmodel=large");
+ else if (Triple.isAArch64() && (CM == "kernel" || CM == "medium"))
+ D.Diag(diag::err_drv_invalid_argument_to_option)
+ << CM << A->getOption().getName();
else
A->render(Args, CmdArgs);
} else {
@@ -5528,12 +5616,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
Args.AddAllArgs(CmdArgs, options::OPT_fshow_skipped_includes);
- if (D.CCPrintHeaders && !D.CCGenDiagnostics) {
+ if (D.CCPrintHeadersFormat && !D.CCGenDiagnostics) {
CmdArgs.push_back("-header-include-file");
CmdArgs.push_back(!D.CCPrintHeadersFilename.empty()
? D.CCPrintHeadersFilename.c_str()
: "-");
CmdArgs.push_back("-sys-header-deps");
+ CmdArgs.push_back(Args.MakeArgString(
+ "-header-include-format=" +
+ std::string(headerIncludeFormatKindToString(D.CCPrintHeadersFormat))));
+ CmdArgs.push_back(
+ Args.MakeArgString("-header-include-filtering=" +
+ std::string(headerIncludeFilteringKindToString(
+ D.CCPrintHeadersFiltering))));
}
Args.AddLastArg(CmdArgs, options::OPT_P);
Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout);
@@ -5622,6 +5717,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ);
+ if (getLastProfileSampleUseArg(Args) &&
+ Args.hasArg(options::OPT_fsample_profile_use_profi)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-sample-profile-use-profi");
+ }
+
// Add runtime flag for PS4/PS5 when PGO, coverage, or sanitizers are enabled.
if (RawTriple.isPS() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
@@ -5713,10 +5814,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors);
Args.AddLastArg(CmdArgs, options::OPT_w);
- // Fixed point flags
- if (Args.hasFlag(options::OPT_ffixed_point, options::OPT_fno_fixed_point,
- /*Default=*/false))
- Args.AddLastArg(CmdArgs, options::OPT_ffixed_point);
+ Args.addOptInFlag(CmdArgs, options::OPT_ffixed_point,
+ options::OPT_fno_fixed_point);
if (Arg *A = Args.getLastArg(options::OPT_fcxx_abi_EQ))
A->render(Args, CmdArgs);
@@ -5769,11 +5868,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs,
options::OPT_fno_trigraphs);
-
- // HIP headers has minimum C++ standard requirements. Therefore set the
- // default language standard.
- if (IsHIP)
- CmdArgs.push_back(IsWindowsMSVC ? "-std=c++14" : "-std=c++11");
}
// GCC's behavior for -Wwrite-strings is a bit strange:
@@ -5886,9 +5980,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
- if (Args.hasFlag(options::OPT_fstack_size_section,
- options::OPT_fno_stack_size_section, RawTriple.isPS4()))
- CmdArgs.push_back("-fstack-size-section");
+ Args.addOptInFlag(CmdArgs, options::OPT_fstack_size_section,
+ options::OPT_fno_stack_size_section);
if (Args.hasArg(options::OPT_fstack_usage)) {
CmdArgs.push_back("-stack-usage-file");
@@ -5956,24 +6049,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back(A->getValue());
+ A->render(Args, CmdArgs);
} else {
assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back("hidden");
- CmdArgs.push_back("-ftype-visibility");
- CmdArgs.push_back("default");
+ CmdArgs.push_back("-fvisibility=hidden");
+ CmdArgs.push_back("-ftype-visibility=default");
}
} else if (IsOpenMPDevice) {
// When compiling for the OpenMP device we want protected visibility by
- // default. This prevents the device from accidenally preempting code on the
- // host, makes the system more robust, and improves performance.
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back("protected");
+ // default. This prevents the device from accidentally preempting code on
+ // the host, makes the system more robust, and improves performance.
+ CmdArgs.push_back("-fvisibility=protected");
}
- if (!RawTriple.isPS4())
+ // PS4/PS5 process these options in addClangTargetOptions.
+ if (!RawTriple.isPS()) {
if (const Arg *A =
Args.getLastArg(options::OPT_fvisibility_from_dllstorageclass,
options::OPT_fno_visibility_from_dllstorageclass)) {
@@ -5987,6 +6077,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fvisibility_externs_nodllstorageclass_EQ);
}
}
+ }
if (const Arg *A = Args.getLastArg(options::OPT_mignore_xcoff_visibility)) {
if (Triple.isOSAIX())
@@ -6092,13 +6183,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_openmp_target_debug, /*Default=*/false))
CmdArgs.push_back("-fopenmp-target-debug");
- // When in OpenMP offloading mode with NVPTX target, check if full runtime
- // is required.
- if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime,
- options::OPT_fno_openmp_cuda_force_full_runtime,
- /*Default=*/false))
- CmdArgs.push_back("-fopenmp-cuda-force-full-runtime");
-
// When in OpenMP offloading mode, forward assumptions information about
// thread and team counts in the device.
if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription,
@@ -6111,6 +6195,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fopenmp-assume-threads-oversubscription");
if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state))
CmdArgs.push_back("-fopenmp-assume-no-thread-state");
+ if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism))
+ CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism");
if (Args.hasArg(options::OPT_fopenmp_offload_mandatory))
CmdArgs.push_back("-fopenmp-offload-mandatory");
break;
@@ -6132,7 +6218,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// Forward the new driver to change offloading code generation.
- if (Args.hasArg(options::OPT_offload_new_driver))
+ if (Args.hasFlag(options::OPT_offload_new_driver,
+ options::OPT_no_offload_new_driver, false))
CmdArgs.push_back("--offload-new-driver");
SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType);
@@ -6196,6 +6283,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
<< A->getAsString(Args) << TripleStr;
}
}
+ if (Arg *A = Args.getLastArgNoClaim(options::OPT_p)) {
+ if (!TC.getTriple().isOSAIX() && !TC.getTriple().isOSOpenBSD()) {
+ D.Diag(diag::err_drv_unsupported_opt_for_target)
+ << A->getAsString(Args) << TripleStr;
+ }
+ }
if (Args.getLastArg(options::OPT_fapple_kext) ||
(Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType)))
@@ -6249,9 +6342,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_pthread);
- if (Args.hasFlag(options::OPT_mspeculative_load_hardening,
- options::OPT_mno_speculative_load_hardening, false))
- CmdArgs.push_back(Args.MakeArgString("-mspeculative-load-hardening"));
+ Args.addOptInFlag(CmdArgs, options::OPT_mspeculative_load_hardening,
+ options::OPT_mno_speculative_load_hardening);
RenderSSPOptions(D, TC, Args, CmdArgs, KernelOrKext);
RenderSCPOptions(TC, Args, CmdArgs);
@@ -6259,10 +6351,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ);
- // Translate -mstackrealign
- if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign,
- false))
- CmdArgs.push_back(Args.MakeArgString("-mstackrealign"));
+ Args.addOptInFlag(CmdArgs, options::OPT_mstackrealign,
+ options::OPT_mno_stackrealign);
if (Args.hasArg(options::OPT_mstack_alignment)) {
StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
@@ -6296,8 +6386,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
RenderOpenCLOptions(Args, CmdArgs, InputType);
// Forward hlsl options to -cc1
- if (C.getDriver().IsDXCMode())
- RenderHLSLOptions(Args, CmdArgs, InputType);
+ RenderHLSLOptions(Args, CmdArgs, InputType);
if (IsHIP) {
if (Args.hasFlag(options::OPT_fhip_new_launch_api,
@@ -6333,13 +6422,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
}
- if (IsUsingLTO)
- Args.AddLastArg(CmdArgs, options::OPT_mibt_seal);
-
if (Arg *A = Args.getLastArg(options::OPT_mfunction_return_EQ))
CmdArgs.push_back(
Args.MakeArgString(Twine("-mfunction-return=") + A->getValue()));
+ Args.AddLastArg(CmdArgs, options::OPT_mindirect_branch_cs_prefix);
+
// Forward -f options with positive and negative forms; we translate these by
// hand. Do not propagate PGO options to the GPU-side compilations as the
// profile info is for the host-side compilation only.
@@ -6396,9 +6484,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts,
false) &&
types::isCXX(InputType)) {
+ D.Diag(diag::warn_deperecated_fcoroutines_ts_flag);
CmdArgs.push_back("-fcoroutines-ts");
}
+ if (Args.hasFlag(options::OPT_fcoro_aligned_allocation,
+ options::OPT_fno_coro_aligned_allocation, false) &&
+ types::isCXX(InputType))
+ CmdArgs.push_back("-fcoro-aligned-allocation");
+
Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes,
options::OPT_fno_double_square_bracket_attributes);
@@ -6460,6 +6554,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (IsMSVCCompat)
CmdArgs.push_back("-fms-compatibility");
+ if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode() &&
+ Args.hasArg(options::OPT_fms_runtime_lib_EQ))
+ ProcessVSRuntimeLibrary(Args, CmdArgs);
+
// Handle -fgcc-version, if present.
VersionTuple GNUCVer;
if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) {
@@ -6572,12 +6670,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
InlineArg->render(Args, CmdArgs);
}
- // FIXME: Find a better way to determine whether the language has modules
- // support by default, or just assume that all languages do.
+ Args.AddLastArg(CmdArgs, options::OPT_finline_max_stacksize_EQ);
+
bool HaveModules =
- Std && (Std->containsValue("c++2a") || Std->containsValue("c++20") ||
- Std->containsValue("c++latest"));
- RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);
+ RenderModulesOptions(C, D, Args, Input, Output, Std, CmdArgs);
if (Args.hasFlag(options::OPT_fpch_validate_input_files_content,
options::OPT_fno_pch_validate_input_files_content, false))
@@ -6592,9 +6688,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
false))
CmdArgs.push_back("-fmodules-debuginfo");
- if (!CLANG_ENABLE_OPAQUE_POINTERS_INTERNAL)
- CmdArgs.push_back("-no-opaque-pointers");
-
ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind);
RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None,
Input, CmdArgs);
@@ -6753,10 +6846,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.addOptInFlag(CmdArgs, options::OPT_fasm_blocks,
options::OPT_fno_asm_blocks);
- // -fgnu-inline-asm is default.
- if (!Args.hasFlag(options::OPT_fgnu_inline_asm,
- options::OPT_fno_gnu_inline_asm, true))
- CmdArgs.push_back("-fno-gnu-inline-asm");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fgnu_inline_asm,
+ options::OPT_fno_gnu_inline_asm);
// Enable vectorization per default according to the optimization level
// selected. For optimization levels that want vectorization we use the alias
@@ -6808,9 +6899,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (RewriteImports)
CmdArgs.push_back("-frewrite-imports");
- if (Args.hasFlag(options::OPT_fdirectives_only,
- options::OPT_fno_directives_only, false))
- CmdArgs.push_back("-fdirectives-only");
+ Args.addOptInFlag(CmdArgs, options::OPT_fdirectives_only,
+ options::OPT_fno_directives_only);
// Enable rewrite includes if the user's asked for it or if we're generating
// diagnostics.
@@ -6900,18 +6990,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
- // -finclude-default-header flag is for preprocessor,
- // do not pass it to other cc1 commands when save-temps is enabled
- if (C.getDriver().isSaveTempsEnabled() &&
- !isa<PreprocessJobAction>(JA)) {
- for (auto Arg : Args.filtered(options::OPT_Xclang)) {
- Arg->claim();
- if (StringRef(Arg->getValue()) != "-finclude-default-header")
- CmdArgs.push_back(Arg->getValue());
+ for (auto Arg : Args.filtered(options::OPT_Xclang)) {
+ Arg->claim();
+ // -finclude-default-header flag is for preprocessor,
+ // do not pass it to other cc1 commands when save-temps is enabled
+ if (C.getDriver().isSaveTempsEnabled() &&
+ !isa<PreprocessJobAction>(JA)) {
+ if (StringRef(Arg->getValue()) == "-finclude-default-header")
+ continue;
}
- }
- else {
- Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
+ CmdArgs.push_back(Arg->getValue());
}
for (const Arg *A : Args.filtered(options::OPT_mllvm)) {
A->claim();
@@ -7168,10 +7256,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_keep_static_consts);
Args.addOptInFlag(CmdArgs, options::OPT_fcomplete_member_pointers,
options::OPT_fno_complete_member_pointers);
-
- if (!Args.hasFlag(options::OPT_fcxx_static_destructors,
- options::OPT_fno_cxx_static_destructors, true))
- CmdArgs.push_back("-fno-c++-static-destructors");
+ Args.addOptOutFlag(CmdArgs, options::OPT_fcxx_static_destructors,
+ options::OPT_fno_cxx_static_destructors);
addMachineOutlinerArgs(D, Args, CmdArgs, Triple, /*IsLTO=*/false);
@@ -7196,6 +7282,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("+outline-atomics");
}
+ if (Triple.isAArch64() &&
+ (Args.hasArg(options::OPT_mno_fmv) ||
+ getToolChain().GetRuntimeLibType(Args) != ToolChain::RLT_CompilerRT)) {
+ // Disable Function Multiversioning on AArch64 target.
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-fmv");
+ }
+
if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig,
(TC.getTriple().isOSBinFormatELF() ||
TC.getTriple().isOSBinFormatCOFF()) &&
@@ -7206,7 +7300,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-faddrsig");
if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) &&
- (EH || AsyncUnwindTables || UnwindTables ||
+ (EH || UnwindTables || AsyncUnwindTables ||
DebugInfoKind != codegenoptions::NoDebugInfo))
CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1");
@@ -7245,9 +7339,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
addDashXForInput(Args, Input, CmdArgs);
ArrayRef<InputInfo> FrontendInputs = Input;
- if (IsHeaderModulePrecompile)
- FrontendInputs = ModuleHeaderInputs;
- else if (IsExtractAPI)
+ if (IsExtractAPI)
FrontendInputs = ExtractAPIInputs;
else if (Input.isNothing())
FrontendInputs = {};
@@ -7513,59 +7605,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
ArgStringList &CmdArgs,
codegenoptions::DebugInfoKind *DebugInfoKind,
bool *EmitCodeView) const {
- unsigned RTOptionID = options::OPT__SLASH_MT;
bool isNVPTX = getToolChain().getTriple().isNVPTX();
- if (Args.hasArg(options::OPT__SLASH_LDd))
- // The /LDd option implies /MTd. The dependent lib part can be overridden,
- // but defining _DEBUG is sticky.
- RTOptionID = options::OPT__SLASH_MTd;
-
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group))
- RTOptionID = A->getOption().getID();
-
- StringRef FlagForCRT;
- switch (RTOptionID) {
- case options::OPT__SLASH_MD:
- if (Args.hasArg(options::OPT__SLASH_LDd))
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-D_DLL");
- FlagForCRT = "--dependent-lib=msvcrt";
- break;
- case options::OPT__SLASH_MDd:
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-D_DLL");
- FlagForCRT = "--dependent-lib=msvcrtd";
- break;
- case options::OPT__SLASH_MT:
- if (Args.hasArg(options::OPT__SLASH_LDd))
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-flto-visibility-public-std");
- FlagForCRT = "--dependent-lib=libcmt";
- break;
- case options::OPT__SLASH_MTd:
- CmdArgs.push_back("-D_DEBUG");
- CmdArgs.push_back("-D_MT");
- CmdArgs.push_back("-flto-visibility-public-std");
- FlagForCRT = "--dependent-lib=libcmtd";
- break;
- default:
- llvm_unreachable("Unexpected option ID.");
- }
-
- if (Args.hasArg(options::OPT__SLASH_Zl)) {
- CmdArgs.push_back("-D_VC_NODEFAULTLIB");
- } else {
- CmdArgs.push_back(FlagForCRT.data());
-
- // This provides POSIX compatibility (maps 'open' to '_open'), which most
- // users want. The /Za flag to cl.exe turns this off, but it's not
- // implemented in clang.
- CmdArgs.push_back("--dependent-lib=oldnames");
- }
+ ProcessVSRuntimeLibrary(Args, CmdArgs);
if (Arg *ShowIncludes =
Args.getLastArg(options::OPT__SLASH_showIncludes,
@@ -7818,7 +7860,7 @@ void ClangAs::AddX86TargetArgs(const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
} else {
getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
@@ -7843,8 +7885,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
const std::string &TripleStr = Triple.getTriple();
- const Optional<llvm::Triple> TargetVariantTriple =
- getToolChain().getTargetVariantTriple();
const auto &D = getToolChain().getDriver();
// Don't warn about "clang -w -c foo.s"
@@ -7862,10 +7902,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// Add the "effective" target triple.
CmdArgs.push_back("-triple");
CmdArgs.push_back(Args.MakeArgString(TripleStr));
- if (TargetVariantTriple) {
- CmdArgs.push_back("-darwin-target-variant-triple");
- CmdArgs.push_back(Args.MakeArgString(TargetVariantTriple->getTriple()));
- }
+
+ getToolChain().addClangCC1ASTargetOptions(Args, CmdArgs);
// Set the output mode, we currently only expect to be used as a real
// assembler.
@@ -7911,13 +7949,6 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
WantDebug = !A->getOption().matches(options::OPT_g0) &&
!A->getOption().matches(options::OPT_ggdb0);
- unsigned DwarfVersion = ParseDebugDefaultVersion(getToolChain(), Args);
- if (const Arg *GDwarfN = getDwarfNArg(Args))
- DwarfVersion = DwarfVersionNum(GDwarfN->getSpelling());
-
- if (DwarfVersion == 0)
- DwarfVersion = getToolChain().GetDefaultDwarfVersion();
-
codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo;
// Add the -fdebug-compilation-dir flag if needed.
@@ -7944,6 +7975,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// And pass along -I options
Args.AddAllArgs(CmdArgs, options::OPT_I);
}
+ const unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args);
RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
llvm::DebuggerKind::Default);
renderDwarfFormat(D, Triple, Args, CmdArgs, DwarfVersion);
@@ -8199,7 +8231,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::None(),
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
- CmdArgs, None, Output));
+ CmdArgs, std::nullopt, Output));
}
void OffloadBundler::ConstructJobMultipleOutputs(
@@ -8283,37 +8315,7 @@ void OffloadBundler::ConstructJobMultipleOutputs(
C.addCommand(std::make_unique<Command>(
JA, *this, ResponseFileSupport::None(),
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
- CmdArgs, None, Outputs));
-}
-
-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, ResponseFileSupport::None(),
- Args.MakeArgString(getToolChain().GetProgramPath(getShortName())),
- CmdArgs, Inputs, Output));
+ CmdArgs, std::nullopt, Outputs));
}
void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA,
@@ -8376,7 +8378,6 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const Driver &D = getToolChain().getDriver();
const llvm::Triple TheTriple = getToolChain().getTriple();
- auto OpenMPTCRange = C.getOffloadToolChains<Action::OFK_OpenMP>();
ArgStringList CmdArgs;
// Pass the CUDA path to the linker wrapper tool.
@@ -8394,29 +8395,6 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // Get the AMDGPU math libraries.
- // FIXME: This method is bad, remove once AMDGPU has a proper math library
- // (see AMDGCN::OpenMPLinker::constructLLVMLinkCommand).
- for (auto &I : llvm::make_range(OpenMPTCRange.first, OpenMPTCRange.second)) {
- const ToolChain *TC = I.second;
-
- if (!TC->getTriple().isAMDGPU() || Args.hasArg(options::OPT_nogpulib))
- continue;
-
- const ArgList &TCArgs = C.getArgsForToolChain(TC, "", Action::OFK_OpenMP);
- StringRef Arch = TCArgs.getLastArgValue(options::OPT_march_EQ);
- const toolchains::ROCMToolChain RocmTC(TC->getDriver(), TC->getTriple(),
- TCArgs);
-
- SmallVector<std::string, 12> BCLibs =
- RocmTC.getCommonDeviceLibNames(TCArgs, Arch.str());
-
- for (StringRef LibName : BCLibs)
- CmdArgs.push_back(Args.MakeArgString(
- "--bitcode-library=" + Action::GetOffloadKindName(Action::OFK_OpenMP) +
- "-" + TC->getTripleString() + "-" + Arch + "=" + LibName));
- }
-
if (D.isUsingLTO(/* IsOffload */ true)) {
// Pass in the optimization level to use for LTO.
if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) {
@@ -8440,7 +8418,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(
Args.MakeArgString("--host-triple=" + TheTriple.getTriple()));
if (Args.hasArg(options::OPT_v))
- CmdArgs.push_back("--verbose");
+ CmdArgs.push_back("--wrapper-verbose");
if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) {
if (!A->getOption().matches(options::OPT_g0))
@@ -8448,7 +8426,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
}
for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
- CmdArgs.push_back(Args.MakeArgString("--ptxas-args=" + A));
+ CmdArgs.push_back(Args.MakeArgString("--ptxas-arg=" + A));
// Forward remarks passes to the LLVM backend in the wrapper.
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
@@ -8481,6 +8459,11 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
}
Args.ClaimAllArgs(options::OPT_Xoffload_linker);
+ // Embed bitcode instead of an object in JIT mode.
+ if (Args.hasFlag(options::OPT_fopenmp_target_jit,
+ options::OPT_fno_openmp_target_jit, false))
+ CmdArgs.push_back("--embed-bitcode");
+
// Forward `-mllvm` arguments to the LLVM invocations if present.
for (Arg *A : Args.filtered(options::OPT_mllvm)) {
CmdArgs.push_back("-mllvm");
diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h
index 5209c6687599..a7625dba6646 100644
--- a/clang/lib/Driver/ToolChains/Clang.h
+++ b/clang/lib/Driver/ToolChains/Clang.h
@@ -57,6 +57,8 @@ private:
bool KernelOrKext) const;
void AddARM64TargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ void AddLoongArchTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
void AddPPCTargetArgs(const llvm::opt::ArgList &Args,
@@ -157,19 +159,6 @@ public:
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;
-};
-
/// Offload binary tool.
class LLVM_LIBRARY_VISIBILITY OffloadPackager final : public Tool {
public:
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 1d2c085d683e..0883631dfe98 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -9,14 +9,19 @@
#include "CommonArgs.h"
#include "Arch/AArch64.h"
#include "Arch/ARM.h"
+#include "Arch/CSKY.h"
+#include "Arch/LoongArch.h"
#include "Arch/M68k.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
+#include "Arch/RISCV.h"
+#include "Arch/Sparc.h"
#include "Arch/SystemZ.h"
#include "Arch/VE.h"
#include "Arch/X86.h"
#include "HIPAMD.h"
#include "Hexagon.h"
+#include "MSP430.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/ObjCRuntime.h"
@@ -39,6 +44,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
@@ -57,30 +63,33 @@
#include "llvm/Support/Threading.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLParser.h"
+#include <optional>
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs) {
+static void renderRpassOptions(const ArgList &Args, ArgStringList &CmdArgs,
+ const StringRef PluginOptPrefix) {
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
- CmdArgs.push_back(Args.MakeArgString(Twine("--plugin-opt=-pass-remarks=") +
- A->getValue()));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "-pass-remarks=" + A->getValue()));
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ))
CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=-pass-remarks-missed=") + A->getValue()));
+ Twine(PluginOptPrefix) + "-pass-remarks-missed=" + A->getValue()));
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ))
CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=-pass-remarks-analysis=") + A->getValue()));
+ Twine(PluginOptPrefix) + "-pass-remarks-analysis=" + A->getValue()));
}
static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
const llvm::Triple &Triple,
const InputInfo &Input,
- const InputInfo &Output) {
+ const InputInfo &Output,
+ const StringRef PluginOptPrefix) {
StringRef Format = "yaml";
if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ))
Format = A->getValue();
@@ -94,29 +103,32 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
assert(!F.empty() && "Cannot determine remarks output name.");
// Append "opt.ld.<format>" to the end of the file name.
- CmdArgs.push_back(
- Args.MakeArgString(Twine("--plugin-opt=opt-remarks-filename=") + F +
- Twine(".opt.ld.") + Format));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "opt-remarks-filename=" + F +
+ ".opt.ld." + Format));
if (const Arg *A =
Args.getLastArg(options::OPT_foptimization_record_passes_EQ))
CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=opt-remarks-passes=") + A->getValue()));
+ Twine(PluginOptPrefix) + "opt-remarks-passes=" + A->getValue()));
- CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=opt-remarks-format=") + Format.data()));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "opt-remarks-format=" + Format.data()));
}
static void renderRemarksHotnessOptions(const ArgList &Args,
- ArgStringList &CmdArgs) {
+ ArgStringList &CmdArgs,
+ const StringRef PluginOptPrefix) {
if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
options::OPT_fno_diagnostics_show_hotness, false))
- CmdArgs.push_back("--plugin-opt=opt-remarks-with-hotness");
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "opt-remarks-with-hotness"));
if (const Arg *A =
Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ))
- CmdArgs.push_back(Args.MakeArgString(
- Twine("--plugin-opt=opt-remarks-hotness-threshold=") + A->getValue()));
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) +
+ "opt-remarks-hotness-threshold=" + A->getValue()));
}
void tools::addPathIfExists(const Driver &D, const Twine &Path,
@@ -284,11 +296,11 @@ void tools::addLinkerCompressDebugSectionsOption(
// argument.
if (const Arg *A = Args.getLastArg(options::OPT_gz_EQ)) {
StringRef V = A->getValue();
- if (V == "none" || V == "zlib")
+ if (V == "none" || V == "zlib" || V == "zstd")
CmdArgs.push_back(Args.MakeArgString("--compress-debug-sections=" + V));
else
TC.getDriver().Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << V;
+ << A->getSpelling() << V;
}
}
@@ -397,25 +409,9 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args,
case llvm::Triple::ppc:
case llvm::Triple::ppcle:
case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le: {
- std::string TargetCPUName = ppc::getPPCTargetCPU(Args);
- // LLVM may default to generating code for the native CPU,
- // but, like gcc, we default to a more generic option for
- // each architecture. (except on AIX)
- if (!TargetCPUName.empty())
- return TargetCPUName;
-
- if (T.isOSAIX())
- TargetCPUName = "pwr7";
- else if (T.getArch() == llvm::Triple::ppc64le)
- TargetCPUName = "ppc64le";
- else if (T.getArch() == llvm::Triple::ppc64)
- TargetCPUName = "ppc64";
- else
- TargetCPUName = "ppc";
+ case llvm::Triple::ppc64le:
+ return ppc::getPPCTargetCPU(Args, T);
- return TargetCPUName;
- }
case llvm::Triple::csky:
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
return A->getValue();
@@ -425,20 +421,18 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args,
return "ck810";
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
+ return riscv::getRISCVTargetCPU(Args, T);
+
+ case llvm::Triple::bpfel:
+ case llvm::Triple::bpfeb:
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
return A->getValue();
return "";
- case llvm::Triple::bpfel:
- case llvm::Triple::bpfeb:
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::sparcv9:
- if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
- return A->getValue();
- if (T.getArch() == llvm::Triple::sparc && T.isOSSolaris())
- return "v9";
- return "";
+ return sparc::getSparcTargetCPU(D, Args, T);
case llvm::Triple::x86:
case llvm::Triple::x86_64:
@@ -464,6 +458,96 @@ std::string tools::getCPUName(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);
+}
+
+void tools::getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args, ArgStringList &CmdArgs,
+ bool ForAS, bool IsAux) {
+ 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(D, Triple, Args, Features, ForAS);
+ break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppcle:
+ 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(D, Args, Features);
+ break;
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_32:
+ case llvm::Triple::aarch64_be:
+ aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS);
+ 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, Triple, Args, Features);
+ break;
+ case llvm::Triple::nvptx:
+ case llvm::Triple::nvptx64:
+ NVPTX::getNVPTXTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::m68k:
+ m68k::getM68kTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::msp430:
+ msp430::getMSP430TargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::ve:
+ ve::getVETargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::csky:
+ csky::getCSKYTargetFeatures(D, Triple, Args, CmdArgs, Features);
+ break;
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ loongarch::getLoongArchTargetFeatures(D, Triple, Args, Features);
+ break;
+ }
+
+ for (auto Feature : unifyTargetFeatures(Features)) {
+ CmdArgs.push_back(IsAux ? "-aux-target-feature" : "-target-feature");
+ CmdArgs.push_back(Feature.data());
+ }
+}
+
llvm::StringRef tools::getLTOParallelism(const ArgList &Args, const Driver &D) {
Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ);
if (!LtoJobsArg)
@@ -482,14 +566,19 @@ bool tools::isUseSeparateSections(const llvm::Triple &Triple) {
void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
ArgStringList &CmdArgs, const InputInfo &Output,
const InputInfo &Input, bool IsThinLTO) {
+ const bool IsOSAIX = ToolChain.getTriple().isOSAIX();
const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath());
const Driver &D = ToolChain.getDriver();
if (llvm::sys::path::filename(Linker) != "ld.lld" &&
llvm::sys::path::stem(Linker) != "ld.lld") {
// Tell the linker to load the plugin. This has to come before
- // AddLinkerInputs as gold requires -plugin to come before any -plugin-opt
- // that -Wl might forward.
- CmdArgs.push_back("-plugin");
+ // AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to
+ // come before any -plugin-opt/-bplugin_opt that -Wl might forward.
+ const char *PluginPrefix = IsOSAIX ? "-bplugin:" : "";
+ const char *PluginName = IsOSAIX ? "/libLTO" : "/LLVMgold";
+
+ if (!IsOSAIX)
+ CmdArgs.push_back("-plugin");
#if defined(_WIN32)
const char *Suffix = ".dll";
@@ -500,10 +589,22 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
#endif
SmallString<1024> Plugin;
- llvm::sys::path::native(
- Twine(D.Dir) + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + Suffix,
- Plugin);
- CmdArgs.push_back(Args.MakeArgString(Plugin));
+ llvm::sys::path::native(Twine(D.Dir) +
+ "/../" CLANG_INSTALL_LIBDIR_BASENAME +
+ PluginName + Suffix,
+ Plugin);
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginPrefix) + Plugin));
+ }
+
+ const char *PluginOptPrefix = IsOSAIX ? "-bplugin_opt:" : "-plugin-opt=";
+ const char *ExtraDash = IsOSAIX ? "-" : "";
+
+ // Note, this solution is far from perfect, better to encode it into IR
+ // metadata, but this may not be worth it, since it looks like aranges is on
+ // the way out.
+ if (Args.hasArg(options::OPT_gdwarf_aranges)) {
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "-generate-arange-section"));
}
// Try to pass driver level flags relevant to LTO code generation down to
@@ -512,7 +613,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
// Handle flags for selecting CPU variants.
std::string CPU = getCPUName(D, Args, ToolChain.getTriple());
if (!CPU.empty())
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU));
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "mcpu=" + CPU));
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
// The optimization level matches
@@ -530,57 +632,80 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
} else if (A->getOption().matches(options::OPT_O0))
OOpt = "0";
if (!OOpt.empty())
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt));
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "O" + OOpt));
}
- if (Args.hasArg(options::OPT_gsplit_dwarf)) {
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=dwo_dir=") +
- Output.getFilename() + "_dwo"));
- }
+ if (Args.hasArg(options::OPT_gsplit_dwarf))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine(PluginOptPrefix) + "dwo_dir=" + Output.getFilename() + "_dwo"));
if (IsThinLTO)
- CmdArgs.push_back("-plugin-opt=thinlto");
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + "thinlto"));
StringRef Parallelism = getLTOParallelism(Args, D);
if (!Parallelism.empty())
CmdArgs.push_back(
- Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism)));
-
- if (!CLANG_ENABLE_OPAQUE_POINTERS_INTERNAL)
- CmdArgs.push_back(Args.MakeArgString("-plugin-opt=no-opaque-pointers"));
+ Args.MakeArgString(Twine(PluginOptPrefix) + "jobs=" + Parallelism));
// If an explicit debugger tuning argument appeared, pass it along.
- if (Arg *A = Args.getLastArg(options::OPT_gTune_Group,
- options::OPT_ggdbN_Group)) {
+ if (Arg *A =
+ Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) {
if (A->getOption().matches(options::OPT_glldb))
- CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=lldb"));
else if (A->getOption().matches(options::OPT_gsce))
- CmdArgs.push_back("-plugin-opt=-debugger-tune=sce");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=sce"));
else if (A->getOption().matches(options::OPT_gdbx))
- CmdArgs.push_back("-plugin-opt=-debugger-tune=dbx");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=dbx"));
else
- CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb");
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-debugger-tune=gdb"));
+ }
+
+ if (IsOSAIX) {
+ // On AIX, clang assumes strict-dwarf is true if any debug option is
+ // specified, unless it is told explicitly not to assume so.
+ Arg *A = Args.getLastArg(options::OPT_g_Group);
+ bool EnableDebugInfo = A && !A->getOption().matches(options::OPT_g0) &&
+ !A->getOption().matches(options::OPT_ggdb0);
+ if (EnableDebugInfo && Args.hasFlag(options::OPT_gstrict_dwarf,
+ options::OPT_gno_strict_dwarf, true))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-strict-dwarf=true"));
+
+ if (Args.getLastArg(options::OPT_mabi_EQ_vec_extabi))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-vec-extabi"));
}
bool UseSeparateSections =
isUseSeparateSections(ToolChain.getEffectiveTriple());
if (Args.hasFlag(options::OPT_ffunction_sections,
- options::OPT_fno_function_sections, UseSeparateSections)) {
- CmdArgs.push_back("-plugin-opt=-function-sections");
- }
+ options::OPT_fno_function_sections, UseSeparateSections))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=1"));
+ else if (Args.hasArg(options::OPT_fno_function_sections))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-function-sections=0"));
if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections,
- UseSeparateSections)) {
- CmdArgs.push_back("-plugin-opt=-data-sections");
- }
+ UseSeparateSections))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=1"));
+ else if (Args.hasArg(options::OPT_fno_data_sections))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-data-sections=0"));
// Pass an option to enable split machine functions.
if (auto *A = Args.getLastArg(options::OPT_fsplit_machine_functions,
options::OPT_fno_split_machine_functions)) {
if (A->getOption().matches(options::OPT_fsplit_machine_functions))
- CmdArgs.push_back("-plugin-opt=-split-machine-functions");
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "-split-machine-functions"));
}
if (Arg *A = getLastProfileSampleUseArg(Args)) {
@@ -588,8 +713,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
if (!llvm::sys::fs::exists(FName))
D.Diag(diag::err_drv_no_such_file) << FName;
else
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "sample-profile=" + FName));
}
auto *CSPGOGenerateArg = Args.getLastArg(options::OPT_fcs_profile_generate,
@@ -602,47 +727,68 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
auto *ProfileUseArg = getLastProfileUseArg(Args);
if (CSPGOGenerateArg) {
- CmdArgs.push_back(Args.MakeArgString("-plugin-opt=cs-profile-generate"));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
+ "cs-profile-generate"));
if (CSPGOGenerateArg->getOption().matches(
options::OPT_fcs_profile_generate_EQ)) {
SmallString<128> Path(CSPGOGenerateArg->getValue());
llvm::sys::path::append(Path, "default_%m.profraw");
- CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") + Path));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
+ "cs-profile-path=" + Path));
} else
CmdArgs.push_back(
- Args.MakeArgString("-plugin-opt=cs-profile-path=default_%m.profraw"));
+ Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
+ "cs-profile-path=default_%m.profraw"));
} else if (ProfileUseArg) {
SmallString<128> Path(
ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue());
if (Path.empty() || llvm::sys::fs::is_directory(Path))
llvm::sys::path::append(Path, "default.profdata");
- CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=cs-profile-path=") +
- Path));
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash +
+ "cs-profile-path=" + Path));
}
+ // This controls whether or not we perform JustMyCode instrumentation.
+ if (Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false)) {
+ if (ToolChain.getEffectiveTriple().isOSBinFormatELF())
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) +
+ "-enable-jmc-instrument"));
+ else
+ D.Diag(clang::diag::warn_drv_fjmc_for_elf_only);
+ }
+
+ if (Args.hasFlag(options::OPT_fstack_size_section,
+ options::OPT_fno_stack_size_section, false))
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine(PluginOptPrefix) + "-stack-size-section"));
+
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
if (!StatsFile.empty())
CmdArgs.push_back(
- Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile));
+ Args.MakeArgString(Twine(PluginOptPrefix) + "stats-file=" + StatsFile));
+
+ // Setup crash diagnostics dir.
+ if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine(PluginOptPrefix) + "-crash-diagnostics-dir=" + A->getValue()));
- addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true);
+ addX86AlignBranchArgs(D, Args, CmdArgs, /*IsLTO=*/true, PluginOptPrefix);
// Handle remark diagnostics on screen options: '-Rpass-*'.
- renderRpassOptions(Args, CmdArgs);
+ renderRpassOptions(Args, CmdArgs, PluginOptPrefix);
// Handle serialized remarks options: '-fsave-optimization-record'
// and '-foptimization-record-*'.
if (willEmitRemarks(Args))
renderRemarksOptions(Args, CmdArgs, ToolChain.getEffectiveTriple(), Input,
- Output);
+ Output, PluginOptPrefix);
// Handle remarks hotness/threshold related options.
- renderRemarksHotnessOptions(Args, CmdArgs);
+ renderRemarksHotnessOptions(Args, CmdArgs, PluginOptPrefix);
addMachineOutlinerArgs(D, Args, CmdArgs, ToolChain.getEffectiveTriple(),
- /*IsLTO=*/true);
+ /*IsLTO=*/true, PluginOptPrefix);
}
void tools::addOpenMPRuntimeSpecificRPath(const ToolChain &TC,
@@ -655,7 +801,7 @@ void tools::addOpenMPRuntimeSpecificRPath(const ToolChain &TC,
// runtime
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
- llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
CmdArgs.push_back("-rpath");
CmdArgs.push_back(Args.MakeArgString(DefaultLibPath));
}
@@ -668,7 +814,7 @@ void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC,
// runtime.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
- llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
CmdArgs.push_back(Args.MakeArgString("-L" + DefaultLibPath));
}
@@ -727,8 +873,7 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
if (IsOffloadingHost)
CmdArgs.push_back("-lomptarget");
- if (IsOffloadingHost && TC.getDriver().isUsingLTO(/* IsOffload */ true) &&
- !Args.hasArg(options::OPT_nogpulib))
+ if (IsOffloadingHost && !Args.hasArg(options::OPT_nogpulib))
CmdArgs.push_back("-lomptarget.devicertl");
addArchSpecificRPath(TC, Args, CmdArgs);
@@ -878,10 +1023,7 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
SharedRuntimes.push_back("ubsan_standalone");
}
if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) {
- if (SanArgs.requiresMinimalRuntime())
- SharedRuntimes.push_back("scudo_minimal");
- else
- SharedRuntimes.push_back("scudo");
+ SharedRuntimes.push_back("scudo_standalone");
}
if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
SharedRuntimes.push_back("tsan");
@@ -978,15 +1120,9 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
RequiredSymbols.push_back("__sanitizer_stats_register");
}
if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) {
- if (SanArgs.requiresMinimalRuntime()) {
- StaticRuntimes.push_back("scudo_minimal");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("scudo_cxx_minimal");
- } else {
- StaticRuntimes.push_back("scudo");
- if (SanArgs.linkCXXRuntimes())
- StaticRuntimes.push_back("scudo_cxx");
- }
+ StaticRuntimes.push_back("scudo_standalone");
+ if (SanArgs.linkCXXRuntimes())
+ StaticRuntimes.push_back("scudo_standalone_cxx");
}
}
@@ -1197,6 +1333,24 @@ Arg *tools::getLastProfileSampleUseArg(const ArgList &Args) {
options::OPT_fauto_profile_EQ);
}
+const char *tools::RelocationModelName(llvm::Reloc::Model Model) {
+ switch (Model) {
+ case llvm::Reloc::Static:
+ return "static";
+ case llvm::Reloc::PIC_:
+ return "pic";
+ case llvm::Reloc::DynamicNoPIC:
+ return "dynamic-no-pic";
+ case llvm::Reloc::ROPI:
+ return "ropi";
+ case llvm::Reloc::RWPI:
+ return "rwpi";
+ case llvm::Reloc::ROPI_RWPI:
+ return "ropi-rwpi";
+ }
+ llvm_unreachable("Unknown Reloc::Model kind");
+}
+
/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then,
/// smooshes them together with platform defaults, to decide whether
/// this compile should be using PIC mode or not. Returns a tuple of
@@ -1442,7 +1596,7 @@ unsigned tools::ParseFunctionAlignment(const ToolChain &TC,
return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value;
}
-unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC,
+static unsigned ParseDebugDefaultVersion(const ToolChain &TC,
const ArgList &Args) {
const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version);
@@ -1457,6 +1611,34 @@ unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC,
return Value;
}
+unsigned tools::DwarfVersionNum(StringRef ArgValue) {
+ return llvm::StringSwitch<unsigned>(ArgValue)
+ .Case("-gdwarf-2", 2)
+ .Case("-gdwarf-3", 3)
+ .Case("-gdwarf-4", 4)
+ .Case("-gdwarf-5", 5)
+ .Default(0);
+}
+
+const Arg *tools::getDwarfNArg(const ArgList &Args) {
+ return Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3,
+ options::OPT_gdwarf_4, options::OPT_gdwarf_5,
+ options::OPT_gdwarf);
+}
+
+unsigned tools::getDwarfVersion(const ToolChain &TC,
+ const llvm::opt::ArgList &Args) {
+ unsigned DwarfVersion = ParseDebugDefaultVersion(TC, Args);
+ if (const Arg *GDwarfN = getDwarfNArg(Args))
+ if (int N = DwarfVersionNum(GDwarfN->getSpelling()))
+ DwarfVersion = N;
+ if (DwarfVersion == 0) {
+ DwarfVersion = TC.GetDefaultDwarfVersion();
+ assert(DwarfVersion && "toolchain default DWARF version must be nonzero");
+ }
+ return DwarfVersion;
+}
+
void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args,
ArgStringList &CmdArgs) {
llvm::Reloc::Model RelocationModel;
@@ -1507,7 +1689,7 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D,
// Targets that don't use unwind libraries.
if ((TC.getTriple().isAndroid() && UNW == ToolChain::UNW_Libgcc) ||
TC.getTriple().isOSIAMCU() || TC.getTriple().isOSBinFormatWasm() ||
- UNW == ToolChain::UNW_None)
+ TC.getTriple().isWindowsMSVCEnvironment() || UNW == ToolChain::UNW_None)
return;
LibGccType LGT = getLibGccType(TC, D, Args);
@@ -1580,9 +1762,10 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D,
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
// Issue error diagnostic if libgcc is explicitly specified
// through command line as --rtlib option argument.
- if (Args.hasArg(options::OPT_rtlib_EQ)) {
+ Arg *A = Args.getLastArg(options::OPT_rtlib_EQ);
+ if (A && A->getValue() != StringRef("platform")) {
TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform)
- << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC";
+ << A->getValue() << "MSVC";
}
} else
AddLibgcc(TC, D, CmdArgs, Args);
@@ -1627,10 +1810,12 @@ void tools::addMultilibFlag(bool Enabled, const char *const Flag,
}
void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args,
- ArgStringList &CmdArgs, bool IsLTO) {
+ ArgStringList &CmdArgs, bool IsLTO,
+ const StringRef PluginOptPrefix) {
auto addArg = [&, IsLTO](const Twine &Arg) {
if (IsLTO) {
- CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg));
+ assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!");
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg));
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString(Arg));
@@ -1775,8 +1960,7 @@ bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs,
/// Search if a user provided archive file lib<libname>.a exists in any of
/// the library paths. If so, add a new command to clang-offload-bundler to
/// unbundle this archive and create a temporary device specific archive. Name
-/// of this SDL is passed to the llvm-link (for amdgcn) or to the
-/// clang-nvlink-wrapper (for nvptx) commands by the driver.
+/// of this SDL is passed to the llvm-link tool.
bool tools::GetSDLFromOffloadArchive(
Compilation &C, const Driver &D, const Tool &T, const JobAction &JA,
const InputInfoList &Inputs, const llvm::opt::ArgList &DriverArgs,
@@ -1789,85 +1973,103 @@ bool tools::GetSDLFromOffloadArchive(
return false;
bool FoundAOB = false;
- SmallVector<std::string, 2> AOBFileNames;
std::string ArchiveOfBundles;
- for (auto LPath : LibraryPaths) {
- ArchiveOfBundles.clear();
-
- llvm::Triple Triple(D.getTargetTriple());
- bool IsMSVC = Triple.isWindowsMSVCEnvironment();
- for (auto Prefix : {"/libdevice/", "/"}) {
- if (IsMSVC)
- AOBFileNames.push_back(Twine(LPath + Prefix + Lib + ".lib").str());
- AOBFileNames.push_back(Twine(LPath + Prefix + "lib" + Lib + ".a").str());
- }
- for (auto AOB : AOBFileNames) {
- if (llvm::sys::fs::exists(AOB)) {
- ArchiveOfBundles = AOB;
- FoundAOB = true;
- break;
+ llvm::Triple Triple(D.getTargetTriple());
+ bool IsMSVC = Triple.isWindowsMSVCEnvironment();
+ auto Ext = IsMSVC ? ".lib" : ".a";
+ if (!Lib.startswith(":") && !Lib.startswith("-l")) {
+ if (llvm::sys::fs::exists(Lib)) {
+ ArchiveOfBundles = Lib;
+ FoundAOB = true;
+ }
+ } else {
+ if (Lib.startswith("-l"))
+ Lib = Lib.drop_front(2);
+ for (auto LPath : LibraryPaths) {
+ ArchiveOfBundles.clear();
+ SmallVector<std::string, 2> AOBFileNames;
+ auto LibFile =
+ (Lib.startswith(":") ? Lib.drop_front()
+ : IsMSVC ? Lib + Ext : "lib" + Lib + Ext)
+ .str();
+ for (auto Prefix : {"/libdevice/", "/"}) {
+ auto AOB = Twine(LPath + Prefix + LibFile).str();
+ if (llvm::sys::fs::exists(AOB)) {
+ ArchiveOfBundles = AOB;
+ FoundAOB = true;
+ break;
+ }
}
+ if (FoundAOB)
+ break;
}
+ }
- if (!FoundAOB)
- continue;
-
- StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib";
- std::string OutputLib = D.GetTemporaryPath(
- Twine(Prefix + Lib + "-" + Arch + "-" + Target).str(), "a");
+ if (!FoundAOB)
+ return false;
- C.addTempFile(C.getArgs().MakeArgString(OutputLib));
+ llvm::file_magic Magic;
+ auto EC = llvm::identify_magic(ArchiveOfBundles, Magic);
+ if (EC || Magic != llvm::file_magic::archive)
+ return false;
- ArgStringList CmdArgs;
- SmallString<128> DeviceTriple;
- DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind());
+ StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib";
+ std::string OutputLib =
+ D.GetTemporaryPath(Twine(Prefix + llvm::sys::path::filename(Lib) + "-" +
+ Arch + "-" + Target)
+ .str(),
+ "a");
+
+ C.addTempFile(C.getArgs().MakeArgString(OutputLib));
+
+ ArgStringList CmdArgs;
+ SmallString<128> DeviceTriple;
+ DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind());
+ DeviceTriple += '-';
+ std::string NormalizedTriple = T.getToolChain().getTriple().normalize();
+ DeviceTriple += NormalizedTriple;
+ if (!Target.empty()) {
DeviceTriple += '-';
- std::string NormalizedTriple = T.getToolChain().getTriple().normalize();
- DeviceTriple += NormalizedTriple;
- if (!Target.empty()) {
- DeviceTriple += '-';
- DeviceTriple += Target;
- }
+ DeviceTriple += Target;
+ }
- std::string UnbundleArg("-unbundle");
- std::string TypeArg("-type=a");
- std::string InputArg("-input=" + ArchiveOfBundles);
- std::string OffloadArg("-targets=" + std::string(DeviceTriple));
- std::string OutputArg("-output=" + OutputLib);
-
- const char *UBProgram = DriverArgs.MakeArgString(
- T.getToolChain().GetProgramPath("clang-offload-bundler"));
-
- ArgStringList UBArgs;
- UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg));
- UBArgs.push_back(C.getArgs().MakeArgString(TypeArg));
- UBArgs.push_back(C.getArgs().MakeArgString(InputArg));
- UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg));
- UBArgs.push_back(C.getArgs().MakeArgString(OutputArg));
-
- // Add this flag to not exit from clang-offload-bundler if no compatible
- // code object is found in heterogenous archive library.
- std::string AdditionalArgs("-allow-missing-bundles");
- UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs));
-
- // Add this flag to treat hip and hipv4 offload kinds as compatible with
- // openmp offload kind while extracting code objects from a heterogenous
- // archive library. Vice versa is also considered compatible.
- std::string HipCompatibleArgs("-hip-openmp-compatible");
- UBArgs.push_back(C.getArgs().MakeArgString(HipCompatibleArgs));
-
- C.addCommand(std::make_unique<Command>(
- JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs,
- InputInfo(&JA, C.getArgs().MakeArgString(OutputLib))));
- if (postClangLink)
- CC1Args.push_back("-mlink-builtin-bitcode");
+ std::string UnbundleArg("-unbundle");
+ std::string TypeArg("-type=a");
+ std::string InputArg("-input=" + ArchiveOfBundles);
+ std::string OffloadArg("-targets=" + std::string(DeviceTriple));
+ std::string OutputArg("-output=" + OutputLib);
- CC1Args.push_back(DriverArgs.MakeArgString(OutputLib));
- break;
- }
+ const char *UBProgram = DriverArgs.MakeArgString(
+ T.getToolChain().GetProgramPath("clang-offload-bundler"));
+
+ ArgStringList UBArgs;
+ UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(TypeArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(InputArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg));
+ UBArgs.push_back(C.getArgs().MakeArgString(OutputArg));
+
+ // Add this flag to not exit from clang-offload-bundler if no compatible
+ // code object is found in heterogenous archive library.
+ std::string AdditionalArgs("-allow-missing-bundles");
+ UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs));
+
+ // Add this flag to treat hip and hipv4 offload kinds as compatible with
+ // openmp offload kind while extracting code objects from a heterogenous
+ // archive library. Vice versa is also considered compatible.
+ std::string HipCompatibleArgs("-hip-openmp-compatible");
+ UBArgs.push_back(C.getArgs().MakeArgString(HipCompatibleArgs));
+
+ C.addCommand(std::make_unique<Command>(
+ JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs,
+ InputInfo(&JA, C.getArgs().MakeArgString(OutputLib))));
+ if (postClangLink)
+ CC1Args.push_back("-mlink-builtin-bitcode");
+
+ CC1Args.push_back(DriverArgs.MakeArgString(OutputLib));
- return FoundAOB;
+ return true;
}
// Wrapper function used by driver for adding SDLs during link phase.
@@ -1882,17 +2084,6 @@ void tools::AddStaticDeviceLibsLinking(Compilation &C, const Tool &T,
Arch, Target, isBitCodeSDL, postClangLink);
}
-// Wrapper function used for post clang linking of bitcode SDLS for nvptx by
-// the CUDA toolchain.
-void tools::AddStaticDeviceLibsPostLinking(const Driver &D,
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- StringRef Arch, StringRef Target,
- bool isBitCodeSDL, bool postClangLink) {
- AddStaticDeviceLibs(nullptr, nullptr, nullptr, nullptr, D, DriverArgs,
- CC1Args, Arch, Target, isBitCodeSDL, postClangLink);
-}
-
// User defined Static Device Libraries(SDLs) can be passed to clang for
// offloading GPU compilers. Like static host libraries, the use of a SDL is
// specified with the -l command line option. The primary difference between
@@ -1905,11 +2096,9 @@ void tools::AddStaticDeviceLibsPostLinking(const Driver &D,
// compilation. For AMDGPU, these libraries are linked one time
// during the application link phase.
//
-// * Machine-code SDLs: They are archive files. For NVPTX, the archive members
-// contain cubin for Nvidia GPUs and are linked one time during the
-// link phase by the CUDA SDK linker called nvlink. For AMDGPU, the
-// process for machine code SDLs is still in development. But they
-// will be linked by the LLVM tool lld.
+// * Machine-code SDLs: They are archive files. For AMDGPU, the process for
+// machine code SDLs is still in development. But they will be linked
+// by the LLVM tool lld.
//
// * Bundled objects that contain both host and device codes: Bundled objects
// may also contain library code compiled from source. For NVPTX, the
@@ -1928,7 +2117,7 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T,
SmallVector<std::string, 8> LibraryPaths;
// Add search directories from LIBRARY_PATH env variable
- llvm::Optional<std::string> LibPath =
+ std::optional<std::string> LibPath =
llvm::sys::Process::GetEnv("LIBRARY_PATH");
if (LibPath) {
SmallVector<StringRef, 8> Frags;
@@ -1944,7 +2133,7 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T,
// Add path to lib-debug folders
SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir);
- llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
LibraryPaths.emplace_back(DefaultLibPath.c_str());
// Build list of Static Device Libraries SDLs specified by -l option
@@ -1953,15 +2142,30 @@ void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T,
"omp", "cudart", "m", "gcc", "gcc_s", "pthread", "hip_hcc"};
for (auto SDLName : DriverArgs.getAllArgValues(options::OPT_l)) {
if (!HostOnlyArchives->contains(SDLName)) {
- SDLNames.insert(SDLName);
+ SDLNames.insert(std::string("-l") + SDLName);
}
}
+ for (auto Input : DriverArgs.getAllArgValues(options::OPT_INPUT)) {
+ auto FileName = StringRef(Input);
+ // Clang treats any unknown file types as archives and passes them to the
+ // linker. Files with extension 'lib' are classified as TY_Object by clang
+ // but they are usually archives. It is OK if the file is not really an
+ // archive since GetSDLFromOffloadArchive will check the magic of the file
+ // and only unbundle it if it is really an archive.
+ const StringRef LibFileExt = ".lib";
+ if (!llvm::sys::path::has_extension(FileName) ||
+ types::lookupTypeForExtension(
+ llvm::sys::path::extension(FileName).drop_front()) ==
+ types::TY_INVALID ||
+ llvm::sys::path::extension(FileName) == LibFileExt)
+ SDLNames.insert(Input);
+ }
+
// The search stops as soon as an SDL file is found. The driver then provides
- // the full filename of the SDL to the llvm-link or clang-nvlink-wrapper
- // command. If no SDL is found after searching each LINKPATH with
- // SEARCH-ORDER, it is possible that an archive file lib<libname>.a exists
- // and may contain bundled object files.
+ // the full filename of the SDL to the llvm-link command. If no SDL is found
+ // after searching each LINKPATH with SEARCH-ORDER, it is possible that an
+ // archive file lib<libname>.a exists and may contain bundled object files.
for (auto SDLName : SDLNames) {
// This is the only call to SDLSearch
if (!SDLSearch(D, DriverArgs, CC1Args, LibraryPaths, SDLName, Arch, Target,
@@ -2034,10 +2238,12 @@ bool tools::haveAMDGPUCodeObjectVersionArgument(
void tools::addMachineOutlinerArgs(const Driver &D,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
- const llvm::Triple &Triple, bool IsLTO) {
+ const llvm::Triple &Triple, bool IsLTO,
+ const StringRef PluginOptPrefix) {
auto addArg = [&, IsLTO](const Twine &Arg) {
if (IsLTO) {
- CmdArgs.push_back(Args.MakeArgString("-plugin-opt=" + Arg));
+ assert(!PluginOptPrefix.empty() && "Cannot have empty PluginOptPrefix!");
+ CmdArgs.push_back(Args.MakeArgString(Twine(PluginOptPrefix) + Arg));
} else {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString(Arg));
@@ -2073,11 +2279,11 @@ void tools::addOpenMPDeviceRTL(const Driver &D,
// Add path to clang lib / lib64 folder.
SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir);
- llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
LibraryPaths.emplace_back(DefaultLibPath.c_str());
// Add user defined library paths from LIBRARY_PATH.
- llvm::Optional<std::string> LibPath =
+ std::optional<std::string> LibPath =
llvm::sys::Process::GetEnv("LIBRARY_PATH");
if (LibPath) {
SmallVector<StringRef, 8> Frags;
@@ -2138,7 +2344,7 @@ void tools::addHIPRuntimeLibArgs(const ToolChain &TC,
TC.AddHIPRuntimeLibArgs(Args, CmdArgs);
} else {
// Claim "no HIP libraries" arguments if any
- for (auto Arg : Args.filtered(options::OPT_no_hip_rt)) {
+ for (auto *Arg : Args.filtered(options::OPT_no_hip_rt)) {
Arg->claim();
}
}
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h
index 8e62af70ff7f..d44d9214c08b 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.h
+++ b/clang/lib/Driver/ToolChains/CommonArgs.h
@@ -14,6 +14,9 @@
#include "clang/Driver/Multilib.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
namespace clang {
@@ -93,14 +96,22 @@ void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output,
const InputInfo &Input, bool IsThinLTO);
+const char *RelocationModelName(llvm::Reloc::Model Model);
+
std::tuple<llvm::Reloc::Model, unsigned, bool>
ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args);
unsigned ParseFunctionAlignment(const ToolChain &TC,
const llvm::opt::ArgList &Args);
-unsigned ParseDebugDefaultVersion(const ToolChain &TC,
- const llvm::opt::ArgList &Args);
+// Extract the integer N from a string spelled "-dwarf-N", returning 0
+// on mismatch. The StringRef input (rather than an Arg) allows
+// for use by the "-Xassembler" option parser.
+unsigned DwarfVersionNum(StringRef ArgValue);
+// Find a DWARF format version option.
+// This function is a complementary for DwarfVersionNum().
+const llvm::opt::Arg *getDwarfNArg(const llvm::opt::ArgList &Args);
+unsigned getDwarfVersion(const ToolChain &TC, const llvm::opt::ArgList &Args);
void AddAssemblerKPIC(const ToolChain &ToolChain,
const llvm::opt::ArgList &Args,
@@ -163,6 +174,11 @@ void AddTargetFeature(const llvm::opt::ArgList &Args,
std::string getCPUName(const Driver &D, const llvm::opt::ArgList &Args,
const llvm::Triple &T, bool FromAs = false);
+void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, bool ForAS,
+ bool IsAux = false);
+
/// Iterate \p Args and convert -mxxx to +xxx and -mno-xxx to -xxx and
/// append it to \p Features.
///
@@ -188,7 +204,8 @@ void addMultilibFlag(bool Enabled, const char *const Flag,
Multilib::flags_list &Flags);
void addX86AlignBranchArgs(const Driver &D, const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs, bool IsLTO);
+ llvm::opt::ArgStringList &CmdArgs, bool IsLTO,
+ const StringRef PluginOptPrefix = "");
void checkAMDGPUCodeObjectVersion(const Driver &D,
const llvm::opt::ArgList &Args);
@@ -201,7 +218,8 @@ bool haveAMDGPUCodeObjectVersionArgument(const Driver &D,
void addMachineOutlinerArgs(const Driver &D, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
- const llvm::Triple &Triple, bool IsLTO);
+ const llvm::Triple &Triple, bool IsLTO,
+ const StringRef PluginOptPrefix = "");
void addOpenMPDeviceRTL(const Driver &D, const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
diff --git a/clang/lib/Driver/ToolChains/CrossWindows.cpp b/clang/lib/Driver/ToolChains/CrossWindows.cpp
index 681a6824dad1..bc91449326a5 100644
--- a/clang/lib/Driver/ToolChains/CrossWindows.cpp
+++ b/clang/lib/Driver/ToolChains/CrossWindows.cpp
@@ -213,10 +213,11 @@ CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D,
const llvm::opt::ArgList &Args)
: Generic_GCC(D, T, Args) {}
-bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel
+CrossWindowsToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
// FIXME: all non-x86 targets need unwind tables, however, LLVM currently does
// not know how to emit them.
- return getArch() == llvm::Triple::x86_64;
+ return getArch() == llvm::Triple::x86_64 ? UnwindTableLevel::Asynchronous : UnwindTableLevel::None;
}
bool CrossWindowsToolChain::isPICDefault() const {
diff --git a/clang/lib/Driver/ToolChains/CrossWindows.h b/clang/lib/Driver/ToolChains/CrossWindows.h
index bab690ea34d0..165dcdfd5d3a 100644
--- a/clang/lib/Driver/ToolChains/CrossWindows.h
+++ b/clang/lib/Driver/ToolChains/CrossWindows.h
@@ -55,7 +55,8 @@ public:
const llvm::opt::ArgList &Args);
bool IsIntegratedAssemblerDefault() const override { return true; }
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp
index 5e59677947e6..484c8c070264 100644
--- a/clang/lib/Driver/ToolChains/Cuda.cpp
+++ b/clang/lib/Driver/ToolChains/Cuda.cpp
@@ -16,10 +16,11 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/InputInfo.h"
#include "clang/Driver/Options.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
@@ -67,15 +68,21 @@ CudaVersion getCudaVersion(uint32_t raw_version) {
return CudaVersion::CUDA_114;
if (raw_version < 11060)
return CudaVersion::CUDA_115;
+ if (raw_version < 11070)
+ return CudaVersion::CUDA_116;
+ if (raw_version < 11080)
+ return CudaVersion::CUDA_117;
+ if (raw_version < 11090)
+ return CudaVersion::CUDA_118;
return CudaVersion::NEW;
}
CudaVersion parseCudaHFile(llvm::StringRef Input) {
// Helper lambda which skips the words if the line starts with them or returns
- // None otherwise.
+ // std::nullopt otherwise.
auto StartsWithWords =
[](llvm::StringRef Line,
- const SmallVector<StringRef, 3> words) -> llvm::Optional<StringRef> {
+ const SmallVector<StringRef, 3> words) -> std::optional<StringRef> {
for (StringRef word : words) {
if (!Line.consume_front(word))
return {};
@@ -189,19 +196,6 @@ CudaInstallationDetector::CudaInstallationDetector(
if (CheckLibDevice && !FS.exists(LibDevicePath))
continue;
- // On Linux, we have both lib and lib64 directories, and we need to choose
- // based on our triple. On MacOS, we have only a lib directory.
- //
- // It's sufficient for our purposes to be flexible: If both lib and lib64
- // exist, we choose whichever one matches our triple. Otherwise, if only
- // lib exists, we use it.
- if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64"))
- LibPath = InstallPath + "/lib64";
- else if (FS.exists(InstallPath + "/lib"))
- LibPath = InstallPath + "/lib";
- else
- continue;
-
Version = CudaVersion::UNKNOWN;
if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h"))
Version = parseCudaHFile((*CudaHFile)->getBuffer());
@@ -375,18 +369,20 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
const auto &TC =
- static_cast<const toolchains::CudaToolChain &>(getToolChain());
+ static_cast<const toolchains::NVPTXToolChain &>(getToolChain());
assert(TC.getTriple().isNVPTX() && "Wrong platform");
StringRef GPUArchName;
- // If this is an OpenMP action we need to extract the device architecture
- // from the -march=arch option. This option may come from -Xopenmp-target
- // flag or the default value.
- if (JA.isDeviceOffloading(Action::OFK_OpenMP)) {
+ // If this is a CUDA action we need to extract the device architecture
+ // from the Job's associated architecture, otherwise use the -march=arch
+ // option. This option may come from -Xopenmp-target flag or the default
+ // value.
+ if (JA.isDeviceOffloading(Action::OFK_Cuda)) {
+ GPUArchName = JA.getOffloadingArch();
+ } else {
GPUArchName = Args.getLastArgValue(options::OPT_march_EQ);
assert(!GPUArchName.empty() && "Must have an architecture passed in.");
- } else
- GPUArchName = JA.getOffloadingArch();
+ }
// Obtain architecture from the action.
CudaArch gpu_arch = StringToCudaArch(GPUArchName);
@@ -448,24 +444,42 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch)));
CmdArgs.push_back("--output-file");
const char *OutputFileName = Args.MakeArgString(TC.getInputFilename(Output));
- if (std::string(OutputFileName) != std::string(Output.getFilename()))
+
+ // If we are invoking `nvlink` internally we need to output a `.cubin` file.
+ // Checking if the output is a temporary is the cleanest way to determine
+ // this. Putting this logic in `getInputFilename` isn't an option because it
+ // relies on the compilation.
+ // FIXME: This should hopefully be removed if NVIDIA updates their tooling.
+ if (Output.isFilename() &&
+ llvm::find(C.getTempFiles(), Output.getFilename()) !=
+ C.getTempFiles().end()) {
+ SmallString<256> Filename(Output.getFilename());
+ llvm::sys::path::replace_extension(Filename, "cubin");
+ OutputFileName = Args.MakeArgString(Filename);
+ }
+ if (Output.isFilename() && OutputFileName != Output.getFilename())
C.addTempFile(OutputFileName);
+
CmdArgs.push_back(OutputFileName);
- for (const auto& II : Inputs)
+ for (const auto &II : Inputs)
CmdArgs.push_back(Args.MakeArgString(II.getFilename()));
- for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
+ for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
CmdArgs.push_back(Args.MakeArgString(A));
- bool Relocatable = false;
+ bool Relocatable;
if (JA.isOffloading(Action::OFK_OpenMP))
// In OpenMP we need to generate relocatable code.
Relocatable = Args.hasFlag(options::OPT_fopenmp_relocatable_target,
options::OPT_fnoopenmp_relocatable_target,
/*Default=*/true);
else if (JA.isOffloading(Action::OFK_Cuda))
- Relocatable = Args.hasFlag(options::OPT_fgpu_rdc,
- options::OPT_fno_gpu_rdc, /*Default=*/false);
+ // In CUDA we generate relocatable code by default.
+ Relocatable = Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc,
+ /*Default=*/false);
+ else
+ // Otherwise, we are compiling directly and should create linkable output.
+ Relocatable = true;
if (Relocatable)
CmdArgs.push_back("-c");
@@ -501,11 +515,11 @@ static bool shouldIncludePTX(const ArgList &Args, const char *gpu_arch) {
// All inputs to this linker must be from CudaDeviceActions, as we need to look
// at the Inputs' Actions in order to figure out which GPU architecture they
// correspond to.
-void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void NVPTX::FatBinary::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
const auto &TC =
static_cast<const toolchains::CudaToolChain &>(getToolChain());
assert(TC.getTriple().isNVPTX() && "Wrong platform");
@@ -519,7 +533,7 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost)
CmdArgs.push_back("-g");
- for (const auto& II : Inputs) {
+ for (const auto &II : Inputs) {
auto *A = II.getAction();
assert(A->getInputs().size() == 1 &&
"Device offload action is expected to have a single input");
@@ -541,7 +555,7 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
",file=" + getToolChain().getInputFilename(II)));
}
- for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary))
+ for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary))
CmdArgs.push_back(Args.MakeArgString(A));
const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary"));
@@ -552,36 +566,31 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Exec, CmdArgs, Inputs, Output));
}
-void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
const auto &TC =
- static_cast<const toolchains::CudaToolChain &>(getToolChain());
+ static_cast<const toolchains::NVPTXToolChain &>(getToolChain());
assert(TC.getTriple().isNVPTX() && "Wrong platform");
ArgStringList CmdArgs;
-
- // OpenMP uses nvlink to link cubin files. The result will be embedded in the
- // host binary by the host linker.
- assert(!JA.isHostOffloading(Action::OFK_OpenMP) &&
- "CUDA toolchain not expected for an OpenMP host device.");
-
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- } else
+ } else {
assert(Output.isNothing() && "Invalid output.");
+ }
+
if (mustEmitDebugInfo(Args) == EmitSameDebugInfoAsHost)
CmdArgs.push_back("-g");
if (Args.hasArg(options::OPT_v))
CmdArgs.push_back("-v");
- StringRef GPUArch =
- Args.getLastArgValue(options::OPT_march_EQ);
- assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas.");
+ StringRef GPUArch = Args.getLastArgValue(options::OPT_march_EQ);
+ assert(!GPUArch.empty() && "At least one GPU Arch required for nvlink.");
CmdArgs.push_back("-arch");
CmdArgs.push_back(Args.MakeArgString(GPUArch));
@@ -592,14 +601,12 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
// Add paths for the default clang library path.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
- llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX);
+ llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath));
for (const auto &II : Inputs) {
- if (II.getType() == types::TY_LLVM_IR ||
- II.getType() == types::TY_LTO_IR ||
- II.getType() == types::TY_LTO_BC ||
- II.getType() == types::TY_LLVM_BC) {
+ if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
+ II.getType() == types::TY_LTO_BC || II.getType() == types::TY_LLVM_BC) {
C.getDriver().Diag(diag::err_drv_no_linker_llvm_support)
<< getToolChain().getTripleString();
continue;
@@ -610,28 +617,40 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
if (!II.isFilename())
continue;
- const char *CubinF =
- C.getArgs().MakeArgString(getToolChain().getInputFilename(II));
+ // The 'nvlink' application performs RDC-mode linking when given a '.o'
+ // file and device linking when given a '.cubin' file. We always want to
+ // perform device linking, so just rename any '.o' files.
+ // FIXME: This should hopefully be removed if NVIDIA updates their tooling.
+ auto InputFile = getToolChain().getInputFilename(II);
+ if (llvm::sys::path::extension(InputFile) != ".cubin") {
+ // If there are no actions above this one then this is direct input and we
+ // can copy it. Otherwise the input is internal so a `.cubin` file should
+ // exist.
+ if (II.getAction() && II.getAction()->getInputs().size() == 0) {
+ const char *CubinF =
+ Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath(
+ llvm::sys::path::stem(InputFile), "cubin"));
+ if (std::error_code EC =
+ llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF)))
+ continue;
- CmdArgs.push_back(CubinF);
+ CmdArgs.push_back(CubinF);
+ } else {
+ SmallString<256> Filename(InputFile);
+ llvm::sys::path::replace_extension(Filename, "cubin");
+ CmdArgs.push_back(Args.MakeArgString(Filename));
+ }
+ } else {
+ CmdArgs.push_back(Args.MakeArgString(InputFile));
+ }
}
- AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx",
- GPUArch, /*isBitCodeSDL=*/false,
- /*postClangLink=*/false);
-
- // Find nvlink and pass it as "--nvlink-path=" argument of
- // clang-nvlink-wrapper.
- CmdArgs.push_back(Args.MakeArgString(
- Twine("--nvlink-path=" + getToolChain().GetProgramPath("nvlink"))));
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("clang-nvlink-wrapper"));
C.addCommand(std::make_unique<Command>(
JA, *this,
ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8,
"--options-file"},
- Exec, CmdArgs, Inputs, Output));
+ Args.MakeArgString(getToolChain().GetProgramPath("nvlink")), CmdArgs,
+ Inputs, Output));
}
void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
@@ -654,6 +673,9 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
case CudaVersion::CUDA_##CUDA_VER: \
PtxFeature = "+ptx" #PTX_VER; \
break;
+ CASE_CUDA_VERSION(118, 78);
+ CASE_CUDA_VERSION(117, 77);
+ CASE_CUDA_VERSION(116, 76);
CASE_CUDA_VERSION(115, 75);
CASE_CUDA_VERSION(114, 74);
CASE_CUDA_VERSION(113, 73);
@@ -673,15 +695,13 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back(PtxFeature);
}
-/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary,
-/// which isn't properly a linker but nonetheless performs the step of stitching
-/// together object files from the assembler into a single blob.
-
-CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple,
- const ToolChain &HostTC, const ArgList &Args,
- const Action::OffloadKind OK)
- : ToolChain(D, Triple, Args), HostTC(HostTC),
- CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) {
+/// NVPTX toolchain. Our assembler is ptxas, and our linker is nvlink. This
+/// operates as a stand-alone version of the NVPTX tools without the host
+/// toolchain.
+NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::Triple &HostTriple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args), CudaInstallation(D, HostTriple, Args) {
if (CudaInstallation.isValid()) {
CudaInstallation.WarnIfUnsupportedVersion();
getProgramPaths().push_back(std::string(CudaInstallation.getBinPath()));
@@ -691,22 +711,72 @@ CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple,
getProgramPaths().push_back(getDriver().Dir);
}
-std::string CudaToolChain::getInputFilename(const InputInfo &Input) const {
- // Only object files are changed, for example assembly files keep their .s
- // extensions.
- if (Input.getType() != types::TY_Object)
- return ToolChain::getInputFilename(Input);
+/// We only need the host triple to locate the CUDA binary utilities, use the
+/// system's default triple if not provided.
+NVPTXToolChain::NVPTXToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : NVPTXToolChain(D, Triple,
+ llvm::Triple(llvm::sys::getDefaultTargetTriple()), Args) {}
- // Replace extension for object files with cubin because nvlink relies on
- // these particular file names.
- SmallString<256> Filename(ToolChain::getInputFilename(Input));
- llvm::sys::path::replace_extension(Filename, "cubin");
- return std::string(Filename.str());
+llvm::opt::DerivedArgList *
+NVPTXToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
+ StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const {
+ DerivedArgList *DAL =
+ ToolChain::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
+ if (!DAL)
+ DAL = new DerivedArgList(Args.getBaseArgs());
+
+ const OptTable &Opts = getDriver().getOpts();
+
+ for (Arg *A : Args)
+ if (!llvm::is_contained(*DAL, A))
+ DAL->append(A);
+
+ if (!DAL->hasArg(options::OPT_march_EQ))
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
+ CudaArchToString(CudaArch::CudaDefault));
+
+ return DAL;
+}
+
+bool NVPTXToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const {
+ const Option &O = A->getOption();
+ return (O.matches(options::OPT_gN_Group) &&
+ !O.matches(options::OPT_gmodules)) ||
+ O.matches(options::OPT_g_Flag) ||
+ O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) ||
+ O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) ||
+ O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) ||
+ O.matches(options::OPT_gdwarf_5) ||
+ O.matches(options::OPT_gcolumn_info);
}
+void NVPTXToolChain::adjustDebugInfoKind(
+ codegenoptions::DebugInfoKind &DebugInfoKind, const ArgList &Args) const {
+ switch (mustEmitDebugInfo(Args)) {
+ case DisableDebugInfo:
+ DebugInfoKind = codegenoptions::NoDebugInfo;
+ break;
+ case DebugDirectivesOnly:
+ DebugInfoKind = codegenoptions::DebugDirectivesOnly;
+ break;
+ case EmitSameDebugInfoAsHost:
+ // Use same debug info level as the host.
+ break;
+ }
+}
+
+/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary,
+/// which isn't properly a linker but nonetheless performs the step of stitching
+/// together object files from the assembler into a single blob.
+
+CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const ArgList &Args)
+ : NVPTXToolChain(D, Triple, HostTC.getTriple(), Args), HostTC(HostTC) {}
+
void CudaToolChain::addClangTargetOptions(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadingKind) const {
HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind);
@@ -766,9 +836,6 @@ void CudaToolChain::addClangTargetOptions(
addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, GpuArch.str(),
getTriple());
- AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx",
- GpuArch, /*isBitCodeSDL=*/true,
- /*postClangLink=*/true);
}
}
@@ -786,33 +853,6 @@ llvm::DenormalMode CudaToolChain::getDefaultDenormalModeForType(
return llvm::DenormalMode::getIEEE();
}
-bool CudaToolChain::supportsDebugInfoOption(const llvm::opt::Arg *A) const {
- const Option &O = A->getOption();
- return (O.matches(options::OPT_gN_Group) &&
- !O.matches(options::OPT_gmodules)) ||
- O.matches(options::OPT_g_Flag) ||
- O.matches(options::OPT_ggdbN_Group) || O.matches(options::OPT_ggdb) ||
- O.matches(options::OPT_gdwarf) || O.matches(options::OPT_gdwarf_2) ||
- O.matches(options::OPT_gdwarf_3) || O.matches(options::OPT_gdwarf_4) ||
- O.matches(options::OPT_gdwarf_5) ||
- O.matches(options::OPT_gcolumn_info);
-}
-
-void CudaToolChain::adjustDebugInfoKind(
- codegenoptions::DebugInfoKind &DebugInfoKind, const ArgList &Args) const {
- switch (mustEmitDebugInfo(Args)) {
- case DisableDebugInfo:
- DebugInfoKind = codegenoptions::NoDebugInfo;
- break;
- case DebugDirectivesOnly:
- DebugInfoKind = codegenoptions::DebugDirectivesOnly;
- break;
- case EmitSameDebugInfoAsHost:
- // Use same debug info level as the host.
- break;
- }
-}
-
void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
// Check our CUDA version if we're going to include the CUDA headers.
@@ -825,6 +865,19 @@ void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs,
CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
}
+std::string CudaToolChain::getInputFilename(const InputInfo &Input) const {
+ // Only object files are changed, for example assembly files keep their .s
+ // extensions. If the user requested device-only compilation don't change it.
+ if (Input.getType() != types::TY_Object || getDriver().offloadDeviceOnly())
+ return ToolChain::getInputFilename(Input);
+
+ // Replace extension for object files with cubin because nvlink relies on
+ // these particular file names.
+ SmallString<256> Filename(ToolChain::getInputFilename(Input));
+ llvm::sys::path::replace_extension(Filename, "cubin");
+ return std::string(Filename.str());
+}
+
llvm::opt::DerivedArgList *
CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
StringRef BoundArch,
@@ -844,10 +897,22 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
if (!llvm::is_contained(*DAL, A))
DAL->append(A);
- if (!DAL->hasArg(options::OPT_march_EQ))
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
- !BoundArch.empty() ? BoundArch
- : CLANG_OPENMP_NVPTX_DEFAULT_ARCH);
+ if (!DAL->hasArg(options::OPT_march_EQ)) {
+ StringRef Arch = BoundArch;
+ if (Arch.empty()) {
+ auto ArchsOrErr = getSystemGPUArchs(Args);
+ if (!ArchsOrErr) {
+ std::string ErrMsg =
+ llvm::formatv("{0}", llvm::fmt_consume(ArchsOrErr.takeError()));
+ getDriver().Diag(diag::err_drv_undetermined_gpu_arch)
+ << llvm::Triple::getArchTypeName(getArch()) << ErrMsg << "-march";
+ Arch = CudaArchToString(CudaArch::CudaDefault);
+ } else {
+ Arch = Args.MakeArgString(ArchsOrErr->front());
+ }
+ }
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), Arch);
+ }
return DAL;
}
@@ -858,19 +923,51 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
if (!BoundArch.empty()) {
DAL->eraseArg(options::OPT_march_EQ);
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch);
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ),
+ BoundArch);
}
return DAL;
}
+Expected<SmallVector<std::string>>
+CudaToolChain::getSystemGPUArchs(const ArgList &Args) const {
+ // Detect NVIDIA GPUs availible on the system.
+ std::string Program;
+ if (Arg *A = Args.getLastArg(options::OPT_nvptx_arch_tool_EQ))
+ Program = A->getValue();
+ else
+ Program = GetProgramPath("nvptx-arch");
+
+ auto StdoutOrErr = executeToolChainProgram(Program);
+ if (!StdoutOrErr)
+ return StdoutOrErr.takeError();
+
+ SmallVector<std::string, 1> GPUArchs;
+ for (StringRef Arch : llvm::split((*StdoutOrErr)->getBuffer(), "\n"))
+ if (!Arch.empty())
+ GPUArchs.push_back(Arch.str());
+
+ if (GPUArchs.empty())
+ return llvm::createStringError(std::error_code(),
+ "No NVIDIA GPU detected in the system");
+
+ return std::move(GPUArchs);
+}
+
+Tool *NVPTXToolChain::buildAssembler() const {
+ return new tools::NVPTX::Assembler(*this);
+}
+
+Tool *NVPTXToolChain::buildLinker() const {
+ return new tools::NVPTX::Linker(*this);
+}
+
Tool *CudaToolChain::buildAssembler() const {
return new tools::NVPTX::Assembler(*this);
}
Tool *CudaToolChain::buildLinker() const {
- if (OK == Action::OFK_OpenMP)
- return new tools::NVPTX::OpenMPLinker(*this);
- return new tools::NVPTX::Linker(*this);
+ return new tools::NVPTX::FatBinary(*this);
}
void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {
diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h
index 809a25227ac4..bf2f369d405c 100644
--- a/clang/lib/Driver/ToolChains/Cuda.h
+++ b/clang/lib/Driver/ToolChains/Cuda.h
@@ -14,7 +14,6 @@
#include "clang/Driver/Multilib.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/VersionTuple.h"
#include <bitset>
@@ -32,7 +31,6 @@ private:
CudaVersion Version = CudaVersion::UNKNOWN;
std::string InstallPath;
std::string BinPath;
- std::string LibPath;
std::string LibDevicePath;
std::string IncludePath;
llvm::StringMap<std::string> LibDeviceMap;
@@ -70,8 +68,6 @@ public:
StringRef getBinPath() const { return BinPath; }
/// Get the detected Cuda Include path.
StringRef getIncludePath() const { return IncludePath; }
- /// Get the detected Cuda library path.
- StringRef getLibPath() const { return LibPath; }
/// Get the detected Cuda device library path.
StringRef getLibDevicePath() const { return LibDevicePath; }
/// Get libdevice file for given architecture
@@ -86,42 +82,42 @@ namespace NVPTX {
// Run ptxas, the NVPTX assembler.
class LLVM_LIBRARY_VISIBILITY Assembler : public Tool {
- public:
- Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {}
+public:
+ Assembler(const ToolChain &TC) : Tool("NVPTX::Assembler", "ptxas", TC) {}
- bool hasIntegratedCPP() const override { return false; }
+ 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;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
// Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX
// assembly into a single output file.
-class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
- public:
- Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {}
+class LLVM_LIBRARY_VISIBILITY FatBinary : public Tool {
+public:
+ FatBinary(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {}
- bool hasIntegratedCPP() const override { return false; }
+ 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;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
-class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool {
- public:
- OpenMPLinker(const ToolChain &TC)
- : Tool("NVPTX::OpenMPLinker", "nvlink", TC) {}
+// Runs nvlink, which links GPU object files ("cubin" files) into a single file.
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+ Linker(const ToolChain &TC) : Tool("NVPTX::Linker", "fatbinary", TC) {}
- bool hasIntegratedCPP() const override { return false; }
+ 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;
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
};
void getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
@@ -133,28 +129,18 @@ void getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
namespace toolchains {
-class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain {
+class LLVM_LIBRARY_VISIBILITY NVPTXToolChain : public ToolChain {
public:
- CudaToolChain(const Driver &D, const llvm::Triple &Triple,
- const ToolChain &HostTC, const llvm::opt::ArgList &Args,
- const Action::OffloadKind OK);
-
- const llvm::Triple *getAuxTriple() const override {
- return &HostTC.getTriple();
- }
+ NVPTXToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::Triple &HostTriple,
+ const llvm::opt::ArgList &Args);
- std::string getInputFilename(const InputInfo &Input) const override;
+ NVPTXToolChain(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args);
llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) const override;
- void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- Action::OffloadKind DeviceOffloadKind) const override;
-
- llvm::DenormalMode getDefaultDenormalModeForType(
- const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
- const llvm::fltSemantics *FPType = nullptr) const override;
// Never try to use the integrated assembler with CUDA; always fork out to
// ptxas.
@@ -166,10 +152,46 @@ public:
}
bool isPICDefaultForced() const override { return false; }
bool SupportsProfiling() const override { return false; }
+
+ bool IsMathErrnoDefault() const override { return false; }
+
bool supportsDebugInfoOption(const llvm::opt::Arg *A) const override;
void adjustDebugInfoKind(codegenoptions::DebugInfoKind &DebugInfoKind,
const llvm::opt::ArgList &Args) const override;
- bool IsMathErrnoDefault() const override { return false; }
+
+ // NVPTX supports only DWARF2.
+ unsigned GetDefaultDwarfVersion() const override { return 2; }
+ unsigned getMaxDwarfVersion() const override { return 2; }
+
+ CudaInstallationDetector CudaInstallation;
+
+protected:
+ Tool *buildAssembler() const override; // ptxas.
+ Tool *buildLinker() const override; // nvlink.
+};
+
+class LLVM_LIBRARY_VISIBILITY CudaToolChain : public NVPTXToolChain {
+public:
+ CudaToolChain(const Driver &D, const llvm::Triple &Triple,
+ const ToolChain &HostTC, const llvm::opt::ArgList &Args);
+
+ const llvm::Triple *getAuxTriple() const override {
+ return &HostTC.getTriple();
+ }
+
+ std::string getInputFilename(const InputInfo &Input) const override;
+
+ llvm::opt::DerivedArgList *
+ TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
+ Action::OffloadKind DeviceOffloadKind) const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
+
+ llvm::DenormalMode getDefaultDenormalModeForType(
+ const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
+ const llvm::fltSemantics *FPType = nullptr) const override;
void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -191,19 +213,16 @@ public:
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;
- unsigned GetDefaultDwarfVersion() const override { return 2; }
- // NVPTX supports only DWARF2.
- unsigned getMaxDwarfVersion() const override { return 2; }
-
const ToolChain &HostTC;
- CudaInstallationDetector CudaInstallation;
-protected:
- Tool *buildAssembler() const override; // ptxas
- Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
+ /// Uses nvptx-arch tool to get arch of the system GPU. Will return error
+ /// if unable to find one.
+ virtual Expected<SmallVector<std::string>>
+ getSystemGPUArchs(const llvm::opt::ArgList &Args) const override;
-private:
- const Action::OffloadKind OK;
+protected:
+ Tool *buildAssembler() const override; // ptxas
+ Tool *buildLinker() const override; // fatbinary (ok, not really a linker)
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index bada811daadf..9f95c962ee9a 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -44,7 +44,7 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
// The matching this routine does is fairly pointless, since it is neither the
// complete architecture list, nor a reasonable subset. The problem is that
- // historically the driver driver accepts this and also ties its -march=
+ // historically the driver accepts this and also ties its -march=
// handling to the architecture name, so we need to be careful before removing
// support for it.
@@ -59,7 +59,7 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) {
.Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4",
llvm::Triple::x86)
.Cases("x86_64", "x86_64h", llvm::Triple::x86_64)
- // This is derived from the driver driver.
+ // This is derived from the driver.
.Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
.Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm)
.Cases("armv7s", "xscale", llvm::Triple::arm)
@@ -522,6 +522,8 @@ static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs,
}
}
+static void AppendPlatformPrefix(SmallString<128> &Path, const llvm::Triple &T);
+
void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -548,8 +550,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("touch"));
CmdArgs.push_back(Output.getFilename());
- C.addCommand(std::make_unique<Command>(
- JA, *this, ResponseFileSupport::None(), Exec, CmdArgs, None, Output));
+ C.addCommand(std::make_unique<Command>(JA, *this,
+ ResponseFileSupport::None(), Exec,
+ CmdArgs, std::nullopt, Output));
return;
}
@@ -719,22 +722,31 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // DriverKit's framework doesn't have the same layout as other frameworks.
- // Add missing search paths if necessary.
- if (getToolChain().getTriple().getOS() == llvm::Triple::DriverKit) {
- if (const Arg *Root = Args.getLastArg(options::OPT_isysroot)) {
+ // Add non-standard, platform-specific search paths, e.g., for DriverKit:
+ // -L<sysroot>/System/DriverKit/usr/lib
+ // -F<sysroot>/System/DriverKit/System/Library/Framework
+ {
+ bool NonStandardSearchPath = false;
+ const auto &Triple = getToolChain().getTriple();
+ if (Triple.isDriverKit()) {
// ld64 fixed the implicit -F and -L paths in ld64-605.1+.
- if (Version.getMajor() < 605 ||
- (Version.getMajor() == 605 && Version.getMinor().value_or(0) < 1)) {
-
- SmallString<128> L(Root->getValue());
- llvm::sys::path::append(L, "System", "DriverKit", "usr", "lib");
- CmdArgs.push_back(Args.MakeArgString(std::string("-L") + L));
+ NonStandardSearchPath =
+ Version.getMajor() < 605 ||
+ (Version.getMajor() == 605 && Version.getMinor().value_or(0) < 1);
+ }
- SmallString<128> F(Root->getValue());
- llvm::sys::path::append(F, "System", "DriverKit");
- llvm::sys::path::append(F, "System", "Library", "Frameworks");
- CmdArgs.push_back(Args.MakeArgString(std::string("-F") + F));
+ if (NonStandardSearchPath) {
+ if (auto *Sysroot = Args.getLastArg(options::OPT_isysroot)) {
+ auto AddSearchPath = [&](StringRef Flag, StringRef SearchPath) {
+ SmallString<128> P(Sysroot->getValue());
+ AppendPlatformPrefix(P, Triple);
+ llvm::sys::path::append(P, SearchPath);
+ if (getToolChain().getVFS().exists(P)) {
+ CmdArgs.push_back(Args.MakeArgString(Flag + P));
+ }
+ };
+ AddSearchPath("-L", "/usr/lib");
+ AddSearchPath("-F", "/System/Library/Frameworks");
}
}
}
@@ -896,12 +908,7 @@ types::ID MachO::LookupTypeForExtension(StringRef Ext) const {
bool MachO::HasNativeLLVMSupport() const { return true; }
ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const {
- // Use libstdc++ on old targets (OSX < 10.9 and iOS < 7)
- if ((isTargetMacOSBased() && isMacosxVersionLT(10, 9)) ||
- (isTargetIOSBased() && isIPhoneOSVersionLT(7, 0)))
- return ToolChain::CST_Libstdcxx;
-
- // On all other targets, use libc++
+ // Always use libc++ by default
return ToolChain::CST_Libcxx;
}
@@ -1347,16 +1354,11 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
// If we have a symbol export directive and we're linking in the profile
// runtime, automatically export symbols necessary to implement some of the
// runtime's functionality.
- if (hasExportSymbolDirective(Args)) {
- if (ForGCOV) {
- addExportedSymbol(CmdArgs, "___gcov_dump");
- addExportedSymbol(CmdArgs, "___gcov_reset");
- addExportedSymbol(CmdArgs, "_writeout_fn_list");
- addExportedSymbol(CmdArgs, "_reset_fn_list");
- } else {
- addExportedSymbol(CmdArgs, "___llvm_profile_filename");
- addExportedSymbol(CmdArgs, "___llvm_profile_raw_version");
- }
+ if (hasExportSymbolDirective(Args) && ForGCOV) {
+ addExportedSymbol(CmdArgs, "___gcov_dump");
+ addExportedSymbol(CmdArgs, "___gcov_reset");
+ addExportedSymbol(CmdArgs, "_writeout_fn_list");
+ addExportedSymbol(CmdArgs, "_reset_fn_list");
}
// Align __llvm_prf_{cnts,data} sections to the maximum expected page
@@ -1390,7 +1392,7 @@ ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType(
const ArgList &Args) const {
if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) {
StringRef Value = A->getValue();
- if (Value != "compiler-rt")
+ if (Value != "compiler-rt" && Value != "platform")
getDriver().Diag(clang::diag::err_drv_unsupported_rtlib_for_platform)
<< Value << "darwin";
}
@@ -1423,15 +1425,22 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
}
const SanitizerArgs &Sanitize = getSanitizerArgs(Args);
+
+ if (!Sanitize.needsSharedRt() && Sanitize.needsUbsanRt()) {
+ getDriver().Diag(diag::err_drv_unsupported_static_ubsan_darwin);
+ return;
+ }
+
if (Sanitize.needsAsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "asan");
if (Sanitize.needsLsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan");
- if (Sanitize.needsUbsanRt())
+ if (Sanitize.needsUbsanRt()) {
+ assert(Sanitize.needsSharedRt() && "Static sanitizer runtimes not supported");
AddLinkSanitizerLibArgs(Args, CmdArgs,
Sanitize.requiresMinimalRuntime() ? "ubsan_minimal"
- : "ubsan",
- Sanitize.needsSharedRt());
+ : "ubsan");
+ }
if (Sanitize.needsTsanRt())
AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan");
if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) {
@@ -1479,17 +1488,19 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
/// If the macOS SDK version is the same or earlier than the system version,
/// then the SDK version is returned. Otherwise the system version is returned.
static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) {
- unsigned Major, Minor, Micro;
llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
if (!SystemTriple.isMacOSX())
return std::string(MacOSSDKVersion);
VersionTuple SystemVersion;
SystemTriple.getMacOSXVersion(SystemVersion);
+
+ unsigned Major, Minor, Micro;
bool HadExtra;
if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro,
HadExtra))
return std::string(MacOSSDKVersion);
VersionTuple SDKVersion(Major, Minor, Micro);
+
if (SDKVersion > SystemVersion)
return SystemVersion.getAsString();
return std::string(MacOSSDKVersion);
@@ -1551,7 +1562,7 @@ struct DarwinPlatform {
/// Returns true if the simulator environment can be inferred from the arch.
bool canInferSimulatorFromArch() const { return InferSimulatorFromArch; }
- const Optional<llvm::Triple> &getTargetVariantTriple() const {
+ const std::optional<llvm::Triple> &getTargetVariantTriple() const {
return TargetVariantTriple;
}
@@ -1602,7 +1613,7 @@ struct DarwinPlatform {
void setEnvironment(llvm::Triple::EnvironmentType EnvType,
const VersionTuple &OSVersion,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
switch (EnvType) {
case llvm::Triple::Simulator:
Environment = DarwinEnvironmentKind::Simulator;
@@ -1615,7 +1626,7 @@ struct DarwinPlatform {
if (const auto *MacCatalystToMacOSMapping = SDKInfo->getVersionMapping(
DarwinSDKInfo::OSEnvPair::macCatalystToMacOSPair())) {
if (auto MacOSVersion = MacCatalystToMacOSMapping->map(
- OSVersion, NativeTargetVersion, None)) {
+ OSVersion, NativeTargetVersion, std::nullopt)) {
NativeTargetVersion = *MacOSVersion;
}
}
@@ -1639,8 +1650,8 @@ struct DarwinPlatform {
static DarwinPlatform
createFromTarget(const llvm::Triple &TT, StringRef OSVersion, Arg *A,
- Optional<llvm::Triple> TargetVariantTriple,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ std::optional<llvm::Triple> TargetVariantTriple,
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
DarwinPlatform Result(TargetArg, getPlatformFromOS(TT.getOS()), OSVersion,
A);
VersionTuple OsVersion = TT.getOSVersion();
@@ -1653,16 +1664,19 @@ struct DarwinPlatform {
static DarwinPlatform
createFromMTargetOS(llvm::Triple::OSType OS, VersionTuple OSVersion,
llvm::Triple::EnvironmentType Environment, Arg *A,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
DarwinPlatform Result(MTargetOSArg, getPlatformFromOS(OS),
OSVersion.getAsString(), A);
Result.InferSimulatorFromArch = false;
Result.setEnvironment(Environment, OSVersion, SDKInfo);
return Result;
}
- static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform,
- Arg *A) {
- return DarwinPlatform(OSVersionArg, Platform, A);
+ static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, Arg *A,
+ bool IsSimulator) {
+ DarwinPlatform Result{OSVersionArg, Platform, A};
+ if (IsSimulator)
+ Result.Environment = DarwinEnvironmentKind::Simulator;
+ return Result;
}
static DarwinPlatform createDeploymentTargetEnv(DarwinPlatformKind Platform,
StringRef EnvVarName,
@@ -1732,12 +1746,12 @@ private:
bool HasOSVersion = true, InferSimulatorFromArch = true;
Arg *Argument;
StringRef EnvVarName;
- Optional<llvm::Triple> TargetVariantTriple;
+ std::optional<llvm::Triple> TargetVariantTriple;
};
/// Returns the deployment target that's specified using the -m<os>-version-min
/// argument.
-Optional<DarwinPlatform>
+std::optional<DarwinPlatform>
getDeploymentTargetFromOSVersionArg(DerivedArgList &Args,
const Driver &TheDriver) {
Arg *macOSVersion = Args.getLastArg(options::OPT_mmacos_version_min_EQ);
@@ -1757,29 +1771,39 @@ getDeploymentTargetFromOSVersionArg(DerivedArgList &Args,
: TvOSVersion ? TvOSVersion : WatchOSVersion)
->getAsString(Args);
}
- return DarwinPlatform::createOSVersionArg(Darwin::MacOS, macOSVersion);
+ return DarwinPlatform::createOSVersionArg(Darwin::MacOS, macOSVersion,
+ /*IsImulator=*/false);
} else if (iOSVersion) {
if (TvOSVersion || WatchOSVersion) {
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
<< iOSVersion->getAsString(Args)
<< (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args);
}
- return DarwinPlatform::createOSVersionArg(Darwin::IPhoneOS, iOSVersion);
+ return DarwinPlatform::createOSVersionArg(
+ Darwin::IPhoneOS, iOSVersion,
+ iOSVersion->getOption().getID() ==
+ options::OPT_mios_simulator_version_min_EQ);
} else if (TvOSVersion) {
if (WatchOSVersion) {
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
<< TvOSVersion->getAsString(Args)
<< WatchOSVersion->getAsString(Args);
}
- return DarwinPlatform::createOSVersionArg(Darwin::TvOS, TvOSVersion);
+ return DarwinPlatform::createOSVersionArg(
+ Darwin::TvOS, TvOSVersion,
+ TvOSVersion->getOption().getID() ==
+ options::OPT_mtvos_simulator_version_min_EQ);
} else if (WatchOSVersion)
- return DarwinPlatform::createOSVersionArg(Darwin::WatchOS, WatchOSVersion);
- return None;
+ return DarwinPlatform::createOSVersionArg(
+ Darwin::WatchOS, WatchOSVersion,
+ WatchOSVersion->getOption().getID() ==
+ options::OPT_mwatchos_simulator_version_min_EQ);
+ return std::nullopt;
}
/// Returns the deployment target that's specified using the
/// OS_DEPLOYMENT_TARGET environment variable.
-Optional<DarwinPlatform>
+std::optional<DarwinPlatform>
getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
const llvm::Triple &Triple) {
std::string Targets[Darwin::LastDarwinPlatform + 1];
@@ -1790,9 +1814,9 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
"WATCHOS_DEPLOYMENT_TARGET",
"DRIVERKIT_DEPLOYMENT_TARGET",
};
- static_assert(llvm::array_lengthof(EnvVars) == Darwin::LastDarwinPlatform + 1,
+ static_assert(std::size(EnvVars) == Darwin::LastDarwinPlatform + 1,
"Missing platform");
- for (const auto &I : llvm::enumerate(llvm::makeArrayRef(EnvVars))) {
+ for (const auto &I : llvm::enumerate(llvm::ArrayRef(EnvVars))) {
if (char *Env = ::getenv(I.value()))
Targets[I.index()] = Env;
}
@@ -1811,11 +1835,11 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
Targets[Darwin::TvOS] = "";
} else {
// Don't allow conflicts in any other platform.
- unsigned FirstTarget = llvm::array_lengthof(Targets);
- for (unsigned I = 0; I != llvm::array_lengthof(Targets); ++I) {
+ unsigned FirstTarget = std::size(Targets);
+ for (unsigned I = 0; I != std::size(Targets); ++I) {
if (Targets[I].empty())
continue;
- if (FirstTarget == llvm::array_lengthof(Targets))
+ if (FirstTarget == std::size(Targets))
FirstTarget = I;
else
TheDriver.Diag(diag::err_drv_conflicting_deployment_targets)
@@ -1823,13 +1847,13 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
}
}
- for (const auto &Target : llvm::enumerate(llvm::makeArrayRef(Targets))) {
+ for (const auto &Target : llvm::enumerate(llvm::ArrayRef(Targets))) {
if (!Target.value().empty())
return DarwinPlatform::createDeploymentTargetEnv(
(Darwin::DarwinPlatformKind)Target.index(), EnvVars[Target.index()],
Target.value());
}
- return None;
+ return std::nullopt;
}
/// Returns the SDK name without the optional prefix that ends with a '.' or an
@@ -1844,16 +1868,16 @@ static StringRef dropSDKNamePrefix(StringRef SDKName) {
/// Tries to infer the deployment target from the SDK specified by -isysroot
/// (or SDKROOT). Uses the version specified in the SDKSettings.json file if
/// it's available.
-Optional<DarwinPlatform>
+std::optional<DarwinPlatform>
inferDeploymentTargetFromSDK(DerivedArgList &Args,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
const Arg *A = Args.getLastArg(options::OPT_isysroot);
if (!A)
- return None;
+ return std::nullopt;
StringRef isysroot = A->getValue();
StringRef SDK = Darwin::getSDKName(isysroot);
if (!SDK.size())
- return None;
+ return std::nullopt;
std::string Version;
if (SDKInfo) {
@@ -1868,10 +1892,10 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args,
Version = std::string(SDK.slice(StartVer, EndVer + 1));
}
if (Version.empty())
- return None;
+ return std::nullopt;
auto CreatePlatformFromSDKName =
- [&](StringRef SDK) -> Optional<DarwinPlatform> {
+ [&](StringRef SDK) -> std::optional<DarwinPlatform> {
if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator"))
return DarwinPlatform::createFromSDK(
Darwin::IPhoneOS, Version,
@@ -1889,7 +1913,7 @@ inferDeploymentTargetFromSDK(DerivedArgList &Args,
/*IsSimulator=*/SDK.startswith("AppleTVSimulator"));
else if (SDK.startswith("DriverKit"))
return DarwinPlatform::createFromSDK(Darwin::DriverKit, Version);
- return None;
+ return std::nullopt;
};
if (auto Result = CreatePlatformFromSDKName(SDK))
return Result;
@@ -1941,7 +1965,7 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple,
}
/// Tries to infer the target OS from the -arch.
-Optional<DarwinPlatform>
+std::optional<DarwinPlatform>
inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain,
const llvm::Triple &Triple,
const Driver &TheDriver) {
@@ -1958,22 +1982,22 @@ inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain,
MachOArchName != "armv7em")
OSTy = llvm::Triple::MacOSX;
if (OSTy == llvm::Triple::UnknownOS)
- return None;
+ return std::nullopt;
return DarwinPlatform::createFromArch(OSTy,
getOSVersion(OSTy, Triple, TheDriver));
}
/// Returns the deployment target that's specified using the -target option.
-Optional<DarwinPlatform> getDeploymentTargetFromTargetArg(
+std::optional<DarwinPlatform> getDeploymentTargetFromTargetArg(
DerivedArgList &Args, const llvm::Triple &Triple, const Driver &TheDriver,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
if (!Args.hasArg(options::OPT_target))
- return None;
+ return std::nullopt;
if (Triple.getOS() == llvm::Triple::Darwin ||
Triple.getOS() == llvm::Triple::UnknownOS)
- return None;
+ return std::nullopt;
std::string OSVersion = getOSVersion(Triple.getOS(), Triple, TheDriver);
- Optional<llvm::Triple> TargetVariantTriple;
+ std::optional<llvm::Triple> TargetVariantTriple;
for (const Arg *A : Args.filtered(options::OPT_darwin_target_variant)) {
llvm::Triple TVT(A->getValue());
// Find a matching <arch>-<vendor> target variant triple that can be used.
@@ -2004,13 +2028,12 @@ Optional<DarwinPlatform> getDeploymentTargetFromTargetArg(
}
/// Returns the deployment target that's specified using the -mtargetos option.
-Optional<DarwinPlatform>
-getDeploymentTargetFromMTargetOSArg(DerivedArgList &Args,
- const Driver &TheDriver,
- const Optional<DarwinSDKInfo> &SDKInfo) {
+std::optional<DarwinPlatform> getDeploymentTargetFromMTargetOSArg(
+ DerivedArgList &Args, const Driver &TheDriver,
+ const std::optional<DarwinSDKInfo> &SDKInfo) {
auto *A = Args.getLastArg(options::OPT_mtargetos_EQ);
if (!A)
- return None;
+ return std::nullopt;
llvm::Triple TT(llvm::Twine("unknown-apple-") + A->getValue());
switch (TT.getOS()) {
case llvm::Triple::MacOSX:
@@ -2021,31 +2044,31 @@ getDeploymentTargetFromMTargetOSArg(DerivedArgList &Args,
default:
TheDriver.Diag(diag::err_drv_invalid_os_in_arg)
<< TT.getOSName() << A->getAsString(Args);
- return None;
+ return std::nullopt;
}
VersionTuple Version = TT.getOSVersion();
if (!Version.getMajor()) {
TheDriver.Diag(diag::err_drv_invalid_version_number)
<< A->getAsString(Args);
- return None;
+ return std::nullopt;
}
return DarwinPlatform::createFromMTargetOS(TT.getOS(), Version,
TT.getEnvironment(), A, SDKInfo);
}
-Optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS,
- const ArgList &Args,
- const Driver &TheDriver) {
+std::optional<DarwinSDKInfo> parseSDKSettings(llvm::vfs::FileSystem &VFS,
+ const ArgList &Args,
+ const Driver &TheDriver) {
const Arg *A = Args.getLastArg(options::OPT_isysroot);
if (!A)
- return None;
+ return std::nullopt;
StringRef isysroot = A->getValue();
auto SDKInfoOrErr = parseDarwinSDKInfo(VFS, isysroot);
if (!SDKInfoOrErr) {
llvm::consumeError(SDKInfoOrErr.takeError());
TheDriver.Diag(diag::warn_drv_darwin_sdk_invalid_settings);
- return None;
+ return std::nullopt;
}
return *SDKInfoOrErr;
}
@@ -2079,7 +2102,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
SDKInfo = parseSDKSettings(getVFS(), Args, getDriver());
// The OS and the version can be specified using the -target argument.
- Optional<DarwinPlatform> OSTarget =
+ std::optional<DarwinPlatform> OSTarget =
getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver(), SDKInfo);
if (OSTarget) {
// Disallow mixing -target and -mtargetos=.
@@ -2089,7 +2112,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
getDriver().Diag(diag::err_drv_cannot_mix_options)
<< TargetArgStr << MTargetOSArgStr;
}
- Optional<DarwinPlatform> OSVersionArgTarget =
+ std::optional<DarwinPlatform> OSVersionArgTarget =
getDeploymentTargetFromOSVersionArg(Args, getDriver());
if (OSVersionArgTarget) {
unsigned TargetMajor, TargetMinor, TargetMicro;
@@ -2124,7 +2147,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
SDKInfo))) {
// The OS target can be specified using the -mtargetos= argument.
// Disallow mixing -mtargetos= and -m<os>version-min=.
- Optional<DarwinPlatform> OSVersionArgTarget =
+ std::optional<DarwinPlatform> OSVersionArgTarget =
getDeploymentTargetFromOSVersionArg(Args, getDriver());
if (OSVersionArgTarget) {
std::string MTargetOSArgStr = OSTarget->getAsString(Args, Opts);
@@ -2142,7 +2165,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple());
if (OSTarget) {
// Don't infer simulator from the arch when the SDK is also specified.
- Optional<DarwinPlatform> SDKTarget =
+ std::optional<DarwinPlatform> SDKTarget =
inferDeploymentTargetFromSDK(Args, SDKInfo);
if (SDKTarget)
OSTarget->setEnvironment(SDKTarget->getEnvironment());
@@ -2171,17 +2194,20 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
unsigned Major, Minor, Micro;
bool HadExtra;
+ // The major version should not be over this number.
+ const unsigned MajorVersionLimit = 1000;
// Set the tool chain target information.
if (Platform == MacOS) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major < 10 || Major >= 100 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major < 10 || Major >= MajorVersionLimit || Minor >= 100 ||
+ Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
} else if (Platform == IPhoneOS) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
;
@@ -2213,19 +2239,20 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
} else if (Platform == TvOS) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
} else if (Platform == WatchOS) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major >= MajorVersionLimit || Minor >= 100 || Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
} else if (Platform == DriverKit) {
if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor,
Micro, HadExtra) ||
- HadExtra || Major < 19 || Major >= 100 || Minor >= 100 || Micro >= 100)
+ HadExtra || Major < 19 || Major >= MajorVersionLimit || Minor >= 100 ||
+ Micro >= 100)
getDriver().Diag(diag::err_drv_invalid_version_number)
<< OSTarget->getAsString(Args, Opts);
} else
@@ -2257,21 +2284,37 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
}
}
-// Returns the effective header sysroot path to use. This comes either from
-// -isysroot or --sysroot.
-llvm::StringRef DarwinClang::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const {
- if(DriverArgs.hasArg(options::OPT_isysroot))
- return DriverArgs.getLastArgValue(options::OPT_isysroot);
- if (!getDriver().SysRoot.empty())
- return getDriver().SysRoot;
- return "/";
+// For certain platforms/environments almost all resources (e.g., headers) are
+// located in sub-directories, e.g., for DriverKit they live in
+// <SYSROOT>/System/DriverKit/usr/include (instead of <SYSROOT>/usr/include).
+static void AppendPlatformPrefix(SmallString<128> &Path,
+ const llvm::Triple &T) {
+ if (T.isDriverKit()) {
+ llvm::sys::path::append(Path, "System", "DriverKit");
+ }
+}
+
+// Returns the effective sysroot from either -isysroot or --sysroot, plus the
+// platform prefix (if any).
+llvm::SmallString<128>
+DarwinClang::GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const {
+ llvm::SmallString<128> Path("/");
+ if (DriverArgs.hasArg(options::OPT_isysroot))
+ Path = DriverArgs.getLastArgValue(options::OPT_isysroot);
+ else if (!getDriver().SysRoot.empty())
+ Path = getDriver().SysRoot;
+
+ if (hasEffectiveTriple()) {
+ AppendPlatformPrefix(Path, getEffectiveTriple());
+ }
+ return Path;
}
void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
const Driver &D = getDriver();
- llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
+ llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs);
bool NoStdInc = DriverArgs.hasArg(options::OPT_nostdinc);
bool NoStdlibInc = DriverArgs.hasArg(options::OPT_nostdlibinc);
@@ -2356,11 +2399,11 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
// Also check whether this is used for setting library search paths.
ToolChain::AddClangCXXStdlibIncludeArgs(DriverArgs, CC1Args);
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
return;
- llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
+ llvm::SmallString<128> Sysroot = GetEffectiveSysroot(DriverArgs);
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libcxx: {
@@ -2630,7 +2673,7 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
}
// Add the arch options based on the particular spelling of -arch, to match
- // how the driver driver works.
+ // how the driver works.
if (!BoundArch.empty()) {
StringRef Name = BoundArch;
const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ);
@@ -2758,10 +2801,25 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
isAlignedAllocationUnavailable())
CC1Args.push_back("-faligned-alloc-unavailable");
+ addClangCC1ASTargetOptions(DriverArgs, CC1Args);
+
+ // Enable compatibility mode for NSItemProviderCompletionHandler in
+ // Foundation/NSItemProvider.h.
+ CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking");
+
+ // Give static local variables in inline functions hidden visibility when
+ // -fvisibility-inlines-hidden is enabled.
+ if (!DriverArgs.getLastArgNoClaim(
+ options::OPT_fvisibility_inlines_hidden_static_local_var,
+ options::OPT_fno_visibility_inlines_hidden_static_local_var))
+ CC1Args.push_back("-fvisibility-inlines-hidden-static-local-var");
+}
+
+void Darwin::addClangCC1ASTargetOptions(
+ const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CC1ASArgs) const {
if (TargetVariantTriple) {
- CC1Args.push_back("-darwin-target-variant-triple");
- CC1Args.push_back(
- DriverArgs.MakeArgString(TargetVariantTriple->getTriple()));
+ CC1ASArgs.push_back("-darwin-target-variant-triple");
+ CC1ASArgs.push_back(Args.MakeArgString(TargetVariantTriple->getTriple()));
}
if (SDKInfo) {
@@ -2771,14 +2829,15 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
std::string Arg;
llvm::raw_string_ostream OS(Arg);
OS << "-target-sdk-version=" << V;
- CC1Args.push_back(DriverArgs.MakeArgString(OS.str()));
+ CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
};
if (isTargetMacCatalyst()) {
if (const auto *MacOStoMacCatalystMapping = SDKInfo->getVersionMapping(
DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
- Optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map(
- SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(), None);
+ std::optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map(
+ SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(),
+ std::nullopt);
EmitTargetSDKVersionArg(
SDKVersion ? *SDKVersion : minimumMacCatalystDeploymentTarget());
}
@@ -2793,32 +2852,22 @@ void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
std::string Arg;
llvm::raw_string_ostream OS(Arg);
OS << "-darwin-target-variant-sdk-version=" << SDKInfo->getVersion();
- CC1Args.push_back(DriverArgs.MakeArgString(OS.str()));
+ CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
} else if (const auto *MacOStoMacCatalystMapping =
SDKInfo->getVersionMapping(
DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
- if (Optional<VersionTuple> SDKVersion = MacOStoMacCatalystMapping->map(
- SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(),
- None)) {
+ if (std::optional<VersionTuple> SDKVersion =
+ MacOStoMacCatalystMapping->map(
+ SDKInfo->getVersion(), minimumMacCatalystDeploymentTarget(),
+ std::nullopt)) {
std::string Arg;
llvm::raw_string_ostream OS(Arg);
OS << "-darwin-target-variant-sdk-version=" << *SDKVersion;
- CC1Args.push_back(DriverArgs.MakeArgString(OS.str()));
+ CC1ASArgs.push_back(Args.MakeArgString(OS.str()));
}
}
}
}
-
- // Enable compatibility mode for NSItemProviderCompletionHandler in
- // Foundation/NSItemProvider.h.
- CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking");
-
- // Give static local variables in inline functions hidden visibility when
- // -fvisibility-inlines-hidden is enabled.
- if (!DriverArgs.getLastArgNoClaim(
- options::OPT_fvisibility_inlines_hidden_static_local_var,
- options::OPT_fno_visibility_inlines_hidden_static_local_var))
- CC1Args.push_back("-fvisibility-inlines-hidden-static-local-var");
}
DerivedArgList *
@@ -2827,7 +2876,6 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
// First get the generic Apple args, before moving onto Darwin-specific ones.
DerivedArgList *DAL =
MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind);
- const OptTable &Opts = getDriver().getOpts();
// If no architecture is bound, none of the translations here are relevant.
if (BoundArch.empty())
@@ -2859,26 +2907,6 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
}
}
- if (!Args.getLastArg(options::OPT_stdlib_EQ) &&
- GetCXXStdlibType(Args) == ToolChain::CST_Libcxx)
- DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ),
- "libc++");
-
- // Validate the C++ standard library choice.
- CXXStdlibType Type = GetCXXStdlibType(*DAL);
- if (Type == ToolChain::CST_Libcxx) {
- // Check whether the target provides libc++.
- StringRef where;
-
- // Complain about targeting iOS < 5.0 in any way.
- if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0))
- where = "iOS 5.0";
-
- if (where != StringRef()) {
- getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where;
- }
- }
-
auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch);
if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) {
if (Args.hasFlag(options::OPT_fomit_frame_pointer,
@@ -2890,13 +2918,17 @@ Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
return DAL;
}
-bool MachO::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel MachO::getDefaultUnwindTableLevel(const ArgList &Args) const {
// Unwind tables are not emitted if -fno-exceptions is supplied (except when
// targeting x86_64).
- return getArch() == llvm::Triple::x86_64 ||
- (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj &&
- Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
- true));
+ if (getArch() == llvm::Triple::x86_64 ||
+ (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj &&
+ Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
+ true)))
+ return getArch() == llvm::Triple::aarch64 ? UnwindTableLevel::Synchronous
+ : UnwindTableLevel::Asynchronous;
+
+ return UnwindTableLevel::None;
}
bool MachO::UseDwarfDebugFlags() const {
@@ -3045,14 +3077,14 @@ void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args,
if (TargetPlatform == IPhoneOS && TargetEnvironment == MacCatalyst) {
// Mac Catalyst programs must use the appropriate iOS SDK version
// that corresponds to the macOS SDK version used for the compilation.
- Optional<VersionTuple> iOSSDKVersion;
+ std::optional<VersionTuple> iOSSDKVersion;
if (SDKInfo) {
if (const auto *MacOStoMacCatalystMapping =
SDKInfo->getVersionMapping(
DarwinSDKInfo::OSEnvPair::macOStoMacCatalystPair())) {
iOSSDKVersion = MacOStoMacCatalystMapping->map(
SDKInfo->getVersion().withoutBuild(),
- minimumMacCatalystDeploymentTarget(), None);
+ minimumMacCatalystDeploymentTarget(), std::nullopt);
}
}
CmdArgs.push_back(Args.MakeArgString(
@@ -3064,6 +3096,8 @@ void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args,
if (SDKInfo) {
VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild();
+ if (!SDKVersion.getMinor())
+ SDKVersion = VersionTuple(SDKVersion.getMajor(), 0);
CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString()));
} else {
// Use an SDK version that's matching the deployment target if the SDK
@@ -3229,11 +3263,10 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
!(isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0)))
Res |= SanitizerKind::Vptr;
- if ((IsX86_64 || IsAArch64) && isTargetMacOSBased()) {
+ if ((IsX86_64 || IsAArch64) &&
+ (isTargetMacOSBased() || isTargetIOSSimulator() ||
+ isTargetTvOSSimulator() || isTargetWatchOSSimulator())) {
Res |= SanitizerKind::Thread;
- } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) {
- if (IsX86_64)
- Res |= SanitizerKind::Thread;
}
return Res;
}
diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h
index 4535d021262e..f64e7180d0af 100644
--- a/clang/lib/Driver/ToolChains/Darwin.h
+++ b/clang/lib/Driver/ToolChains/Darwin.h
@@ -148,7 +148,7 @@ private:
mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug;
/// The version of the linker known to be available in the tool chain.
- mutable Optional<VersionTuple> LinkerVersion;
+ mutable std::optional<VersionTuple> LinkerVersion;
public:
MachO(const Driver &D, const llvm::Triple &Triple,
@@ -254,7 +254,8 @@ public:
bool UseObjCMixedDispatch() const override { return true; }
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
RuntimeLibType GetDefaultRuntimeLibType() const override {
return ToolChain::RLT_CompilerRT;
@@ -317,10 +318,10 @@ public:
mutable VersionTuple OSTargetVersion;
/// The information about the darwin SDK that was used.
- mutable Optional<DarwinSDKInfo> SDKInfo;
+ mutable std::optional<DarwinSDKInfo> SDKInfo;
/// The target variant triple that was specified (if any).
- mutable Optional<llvm::Triple> TargetVariantTriple;
+ mutable std::optional<llvm::Triple> TargetVariantTriple;
CudaInstallationDetector CudaInstallation;
RocmInstallationDetector RocmInstallation;
@@ -495,12 +496,6 @@ public:
: TargetVersion) < VersionTuple(V0, V1, V2);
}
- /// Returns the darwin target variant triple, the variant of the deployment
- /// target for which the code is being compiled.
- Optional<llvm::Triple> getTargetVariantTriple() const override {
- return TargetVariantTriple;
- }
-
protected:
/// Return true if c++17 aligned allocation/deallocation functions are not
/// implemented in the c++ standard library of the deployment target we are
@@ -511,6 +506,10 @@ protected:
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const override;
+ void addClangCC1ASTargetOptions(
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CC1ASArgs) const override;
+
StringRef getPlatformFamily() const;
StringRef getOSLibraryNameSuffix(bool IgnoreSim = false) const override;
@@ -628,7 +627,8 @@ private:
llvm::StringRef ArchDir,
llvm::StringRef BitDir) const;
- llvm::StringRef GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const;
+ llvm::SmallString<128>
+ GetEffectiveSysroot(const llvm::opt::ArgList &DriverArgs) const;
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 3368f6785718..4ee046be9ea9 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -27,7 +27,7 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input,
CmdArgs.push_back(types::getTypeName(Input.getType()));
}
-void Flang::AddFortranDialectOptions(const ArgList &Args,
+void Flang::addFortranDialectOptions(const ArgList &Args,
ArgStringList &CmdArgs) const {
Args.AddAllArgs(
CmdArgs, {options::OPT_ffixed_form, options::OPT_ffree_form,
@@ -44,18 +44,195 @@ void Flang::AddFortranDialectOptions(const ArgList &Args,
options::OPT_fno_automatic});
}
-void Flang::AddPreprocessingOptions(const ArgList &Args,
+void Flang::addPreprocessingOptions(const ArgList &Args,
ArgStringList &CmdArgs) const {
Args.AddAllArgs(CmdArgs,
{options::OPT_P, options::OPT_D, options::OPT_U,
options::OPT_I, options::OPT_cpp, options::OPT_nocpp});
}
-void Flang::AddOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
+void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
Args.AddAllArgs(CmdArgs,
{options::OPT_module_dir, options::OPT_fdebug_module_writer,
options::OPT_fintrinsic_modules_path, options::OPT_pedantic,
- options::OPT_std_EQ, options::OPT_W_Joined});
+ options::OPT_std_EQ, options::OPT_W_Joined,
+ options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ});
+}
+
+void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const {
+ // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of
+ // (RelocationModel, PICLevel, IsPIE).
+ llvm::Reloc::Model RelocationModel;
+ unsigned PICLevel;
+ bool IsPIE;
+ std::tie(RelocationModel, PICLevel, IsPIE) =
+ ParsePICArgs(getToolChain(), Args);
+
+ if (auto *RMName = RelocationModelName(RelocationModel)) {
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(RMName);
+ }
+ if (PICLevel > 0) {
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
+ if (IsPIE)
+ CmdArgs.push_back("-pic-is-pie");
+ }
+}
+
+void Flang::addTargetOptions(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const ToolChain &TC = getToolChain();
+ const llvm::Triple &Triple = TC.getEffectiveTriple();
+ const Driver &D = TC.getDriver();
+
+ std::string CPU = getCPUName(D, Args, Triple);
+ if (!CPU.empty()) {
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(CPU));
+ }
+
+ // Add the target features.
+ switch (TC.getArch()) {
+ default:
+ break;
+ case llvm::Triple::aarch64:
+ [[fallthrough]];
+ case llvm::Triple::x86_64:
+ getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false);
+ break;
+ }
+
+ // TODO: Add target specific flags, ABI, mtune option etc.
+}
+
+static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ StringRef FPContract;
+ bool HonorINFs = true;
+ bool HonorNaNs = true;
+ bool ApproxFunc = false;
+ bool SignedZeros = true;
+ bool AssociativeMath = false;
+ bool ReciprocalMath = false;
+
+ if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) {
+ const StringRef Val = A->getValue();
+ if (Val == "fast" || Val == "off") {
+ FPContract = Val;
+ } else if (Val == "on") {
+ // Warn instead of error because users might have makefiles written for
+ // gfortran (which accepts -ffp-contract=on)
+ D.Diag(diag::warn_drv_unsupported_option_for_flang)
+ << Val << A->getOption().getName() << "off";
+ FPContract = "off";
+ } else
+ // Clang's "fast-honor-pragmas" option is not supported because it is
+ // non-standard
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << Val;
+ }
+
+ for (const Arg *A : Args) {
+ auto optId = A->getOption().getID();
+ switch (optId) {
+ // if this isn't an FP option, skip the claim below
+ default:
+ continue;
+
+ case options::OPT_fhonor_infinities:
+ HonorINFs = true;
+ break;
+ case options::OPT_fno_honor_infinities:
+ HonorINFs = false;
+ break;
+ case options::OPT_fhonor_nans:
+ HonorNaNs = true;
+ break;
+ case options::OPT_fno_honor_nans:
+ HonorNaNs = false;
+ break;
+ case options::OPT_fapprox_func:
+ ApproxFunc = true;
+ break;
+ case options::OPT_fno_approx_func:
+ ApproxFunc = false;
+ break;
+ case options::OPT_fsigned_zeros:
+ SignedZeros = true;
+ break;
+ case options::OPT_fno_signed_zeros:
+ SignedZeros = false;
+ break;
+ case options::OPT_fassociative_math:
+ AssociativeMath = true;
+ break;
+ case options::OPT_fno_associative_math:
+ AssociativeMath = false;
+ break;
+ case options::OPT_freciprocal_math:
+ ReciprocalMath = true;
+ break;
+ case options::OPT_fno_reciprocal_math:
+ ReciprocalMath = false;
+ break;
+ case options::OPT_Ofast:
+ [[fallthrough]];
+ case options::OPT_ffast_math:
+ HonorINFs = false;
+ HonorNaNs = false;
+ AssociativeMath = true;
+ ReciprocalMath = true;
+ ApproxFunc = true;
+ SignedZeros = false;
+ FPContract = "fast";
+ break;
+ case options::OPT_fno_fast_math:
+ HonorINFs = true;
+ HonorNaNs = true;
+ AssociativeMath = false;
+ ReciprocalMath = false;
+ ApproxFunc = false;
+ SignedZeros = true;
+ // -fno-fast-math should undo -ffast-math so I return FPContract to the
+ // default. It is important to check it is "fast" (the default) so that
+ // --ffp-contract=off -fno-fast-math --> -ffp-contract=off
+ if (FPContract == "fast")
+ FPContract = "";
+ break;
+ }
+
+ // If we handled this option claim it
+ A->claim();
+ }
+
+ if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
+ ApproxFunc && !SignedZeros &&
+ (FPContract == "fast" || FPContract == "")) {
+ CmdArgs.push_back("-ffast-math");
+ return;
+ }
+
+ if (!FPContract.empty())
+ CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract));
+
+ if (!HonorINFs)
+ CmdArgs.push_back("-menable-no-infs");
+
+ if (!HonorNaNs)
+ CmdArgs.push_back("-menable-no-nans");
+
+ if (ApproxFunc)
+ CmdArgs.push_back("-fapprox-func");
+
+ if (!SignedZeros)
+ CmdArgs.push_back("-fno-signed-zeros");
+
+ if (AssociativeMath && !SignedZeros)
+ CmdArgs.push_back("-mreassociate");
+
+ if (ReciprocalMath)
+ CmdArgs.push_back("-freciprocal-math");
}
void Flang::ConstructJob(Compilation &C, const JobAction &JA,
@@ -105,9 +282,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor (i.e. skip when dealing with e.g. binary files).
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
- AddPreprocessingOptions(Args, CmdArgs);
+ addPreprocessingOptions(Args, CmdArgs);
- AddFortranDialectOptions(Args, CmdArgs);
+ addFortranDialectOptions(Args, CmdArgs);
// Color diagnostics are parsed by the driver directly from argv and later
// re-parsed to construct this job; claim any possible color diagnostic here
@@ -117,8 +294,17 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
if (D.getDiags().getDiagnosticOptions().ShowColors)
CmdArgs.push_back("-fcolor-diagnostics");
+ // -fPIC and related options.
+ addPicOptions(Args, CmdArgs);
+
+ // Floating point related options
+ addFloatingPointOptions(D, Args, CmdArgs);
+
+ // Add target args, features, etc.
+ addTargetOptions(Args, CmdArgs);
+
// Add other compile options
- AddOtherOptions(Args, CmdArgs);
+ addOtherOptions(Args, CmdArgs);
// Forward -Xflang arguments to -fc1
Args.AddAllArgValues(CmdArgs, options::OPT_Xflang);
@@ -140,6 +326,8 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
if (A->getOption().matches(options::OPT_O4)) {
CmdArgs.push_back("-O3");
D.Diag(diag::warn_O4_is_O3);
+ } else if (A->getOption().matches(options::OPT_Ofast)) {
+ CmdArgs.push_back("-O3");
} else {
A->render(Args, CmdArgs);
}
diff --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h
index efbdbe854e24..4c85c602e267 100644
--- a/clang/lib/Driver/ToolChains/Flang.h
+++ b/clang/lib/Driver/ToolChains/Flang.h
@@ -29,7 +29,7 @@ private:
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
- void AddFortranDialectOptions(const llvm::opt::ArgList &Args,
+ void addFortranDialectOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
/// Extract preprocessing options from the driver arguments and add them to
@@ -37,14 +37,31 @@ private:
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
- void AddPreprocessingOptions(const llvm::opt::ArgList &Args,
+ void addPreprocessingOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Extract PIC options from the driver arguments and add them to
+ /// the command arguments.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void addPicOptions(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
+ /// Extract target options from the driver arguments and add them to
+ /// the command arguments.
+ ///
+ /// \param [in] Args The list of input driver arguments
+ /// \param [out] CmdArgs The list of output command arguments
+ void addTargetOptions(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
+
/// Extract other compilation options from the driver arguments and add them
/// to the command arguments.
///
/// \param [in] Args The list of input driver arguments
/// \param [out] CmdArgs The list of output command arguments
- void AddOtherOptions(const llvm::opt::ArgList &Args,
+ void addOtherOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
public:
diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp
index e49e8b0bf7d1..64935227b07e 100644
--- a/clang/lib/Driver/ToolChains/FreeBSD.cpp
+++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp
@@ -11,6 +11,7 @@
#include "Arch/Mips.h"
#include "Arch/Sparc.h"
#include "CommonArgs.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
@@ -408,6 +409,40 @@ unsigned FreeBSD::GetDefaultDwarfVersion() const {
return 4;
}
+void FreeBSD::AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(D.ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Check for configure-time C include directories.
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ SmallVector<StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (StringRef dir : dirs) {
+ StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ return;
+ }
+
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ concat(D.SysRoot, "/usr/include"));
+}
+
void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
addSystemInclude(DriverArgs, CC1Args,
@@ -473,7 +508,10 @@ llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const {
bool FreeBSD::HasNativeLLVMSupport() const { return true; }
-bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; }
+ToolChain::UnwindTableLevel
+FreeBSD::getDefaultUnwindTableLevel(const ArgList &Args) const {
+ return UnwindTableLevel::Asynchronous;
+}
bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const {
return getSanitizerArgs(Args).requiresPIE();
diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h
index 2a721c750a64..18832dad9884 100644
--- a/clang/lib/Driver/ToolChains/FreeBSD.h
+++ b/clang/lib/Driver/ToolChains/FreeBSD.h
@@ -58,6 +58,9 @@ public:
bool IsMathErrnoDefault() const override { return false; }
bool IsObjCNonFragileABIDefault() const override { return true; }
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
CXXStdlibType GetDefaultCXXStdlibType() const override;
void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -73,7 +76,8 @@ public:
llvm::ExceptionHandling
GetExceptionModel(const llvm::opt::ArgList &Args) const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
SanitizerMask getSupportedSanitizers() const override;
unsigned GetDefaultDwarfVersion() const override;
diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp
index d63c69c63b1f..9bdc3a791779 100644
--- a/clang/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -87,6 +87,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
if (ToolChain.getArch() == llvm::Triple::aarch64) {
+ CmdArgs.push_back("--execute-only");
+
std::string CPU = getCPUName(D, Args, Triple);
if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
CmdArgs.push_back("--fix-cortex-a53-843419");
@@ -375,8 +377,8 @@ void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
return;
const Driver &D = getDriver();
diff --git a/clang/lib/Driver/ToolChains/Fuchsia.h b/clang/lib/Driver/ToolChains/Fuchsia.h
index f9f3bbfa9fbf..e43cb3b0dddf 100644
--- a/clang/lib/Driver/ToolChains/Fuchsia.h
+++ b/clang/lib/Driver/ToolChains/Fuchsia.h
@@ -50,8 +50,9 @@ public:
CXXStdlibType GetDefaultCXXStdlibType() const override {
return ToolChain::CST_Libcxx;
}
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override {
- return true;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override {
+ return UnwindTableLevel::Asynchronous;
}
bool isPICDefault() const override { return false; }
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 34396b0b59c2..4f2340316654 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -23,6 +23,8 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Path.h"
@@ -83,7 +85,7 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
RenderExtraToolArgs(JA, CmdArgs);
- // If using a driver driver, force the arch.
+ // If using a driver, force the arch.
if (getToolChain().getTriple().isOSDarwin()) {
CmdArgs.push_back("-arch");
CmdArgs.push_back(
@@ -227,7 +229,7 @@ static bool isArmBigEndian(const llvm::Triple &Triple,
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
IsBigEndian = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
@@ -278,6 +280,10 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
return "elf32_sparc";
case llvm::Triple::sparcv9:
return "elf64_sparc";
+ case llvm::Triple::loongarch32:
+ return "elf32loongarch";
+ case llvm::Triple::loongarch64:
+ return "elf64loongarch";
case llvm::Triple::mips:
return "elf32btsmip";
case llvm::Triple::mipsel:
@@ -326,8 +332,8 @@ static bool getStaticPIE(const ArgList &Args, const ToolChain &TC) {
if (HasStaticPIE && Args.hasArg(options::OPT_nopie)) {
const Driver &D = TC.getDriver();
const llvm::opt::OptTable &Opts = D.getOpts();
- const char *StaticPIEName = Opts.getOptionName(options::OPT_static_pie);
- const char *NoPIEName = Opts.getOptionName(options::OPT_nopie);
+ StringRef StaticPIEName = Opts.getOptionName(options::OPT_static_pie);
+ StringRef NoPIEName = Opts.getOptionName(options::OPT_nopie);
D.Diag(diag::err_drv_cannot_mix_options) << StaticPIEName << NoPIEName;
}
return HasStaticPIE;
@@ -582,13 +588,6 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lm");
}
- // If we are linking for the device all symbols should be bound locally. The
- // symbols are already protected which makes this redundant. This is only
- // necessary to work around a problem in bfd.
- // TODO: Remove this once 'lld' becomes the only linker for offloading.
- if (JA.isDeviceOffloading(Action::OFK_OpenMP))
- CmdArgs.push_back("-Bsymbolic");
-
// Silence warnings when linking C code with a C++ '-stdlib' argument.
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
@@ -631,6 +630,16 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
+ // LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so
+ // forcibly link with libatomic as a workaround.
+ // TODO: Issue #41880 and D118021.
+ if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) {
+ CmdArgs.push_back("--push-state");
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-latomic");
+ CmdArgs.push_back("--pop-state");
+ }
+
if (WantPthread && !isAndroid)
CmdArgs.push_back("-lpthread");
@@ -716,12 +725,12 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
CmdArgs.push_back("--compress-debug-sections");
} else {
StringRef Value = A->getValue();
- if (Value == "none" || Value == "zlib") {
+ if (Value == "none" || Value == "zlib" || Value == "zstd") {
CmdArgs.push_back(
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Value;
+ << A->getSpelling() << Value;
}
}
}
@@ -962,6 +971,17 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
+ if (Arg *A = Args.getLastArg(options::OPT_g_Flag, options::OPT_gN_Group,
+ options::OPT_gdwarf_2, options::OPT_gdwarf_3,
+ options::OPT_gdwarf_4, options::OPT_gdwarf_5,
+ options::OPT_gdwarf))
+ if (!A->getOption().matches(options::OPT_g0)) {
+ Args.AddLastArg(CmdArgs, options::OPT_g_Flag);
+
+ unsigned DwarfVersion = getDwarfVersion(getToolChain(), Args);
+ CmdArgs.push_back(Args.MakeArgString("-gdwarf-" + Twine(DwarfVersion)));
+ }
+
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(DefaultAssembler));
C.addCommand(std::make_unique<Command>(JA, *this,
@@ -1355,7 +1375,7 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
{"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()});
});
}
- for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) {
+ for (auto *Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) {
if (Candidate->select(Flags, Result.SelectedMultilib)) {
Result.Multilibs = *Candidate;
return true;
@@ -1448,7 +1468,7 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
{"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()});
});
}
- for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) {
+ for (auto *Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) {
if (Candidate->select(Flags, Result.SelectedMultilib)) {
Result.Multilibs = *Candidate;
return true;
@@ -1604,7 +1624,8 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
tools::csky::FloatABI TheFloatABI = tools::csky::getCSKYFloatABI(D, Args);
- llvm::Optional<llvm::StringRef> Res = tools::csky::getCSKYArchName(D, Args, TargetTriple);
+ std::optional<llvm::StringRef> Res =
+ tools::csky::getCSKYArchName(D, Args, TargetTriple);
if (!Res)
return;
@@ -1865,8 +1886,15 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
StringRef RHSPatchSuffix) const {
if (Major != RHSMajor)
return Major < RHSMajor;
- if (Minor != RHSMinor)
+ if (Minor != RHSMinor) {
+ // Note that versions without a specified minor sort higher than those with
+ // a minor.
+ if (RHSMinor == -1)
+ return true;
+ if (Minor == -1)
+ return false;
return Minor < RHSMinor;
+ }
if (Patch != RHSPatch) {
// Note that versions without a specified patch sort higher than those with
// a patch.
@@ -1983,6 +2011,28 @@ void Generic_GCC::GCCInstallationDetector::init(
CandidateTripleAliases, CandidateBiarchLibDirs,
CandidateBiarchTripleAliases);
+ // If --gcc-install-dir= is specified, skip filesystem detection.
+ if (const Arg *A =
+ Args.getLastArg(clang::driver::options::OPT_gcc_install_dir_EQ);
+ A && A->getValue()[0]) {
+ StringRef InstallDir = A->getValue();
+ if (!ScanGCCForMultilibs(TargetTriple, Args, InstallDir, false)) {
+ D.Diag(diag::err_drv_invalid_gcc_install_dir) << InstallDir;
+ } else {
+ (void)InstallDir.consume_back("/");
+ StringRef VersionText = llvm::sys::path::filename(InstallDir);
+ StringRef TripleText =
+ llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir));
+
+ Version = GCCVersion::Parse(VersionText);
+ GCCTriple.setTriple(TripleText);
+ GCCInstallPath = std::string(InstallDir);
+ GCCParentLibPath = GCCInstallPath + "/../../..";
+ IsValid = true;
+ }
+ return;
+ }
+
// Compute the set of prefixes for our search.
SmallVector<std::string, 8> Prefixes;
StringRef GCCToolchainDir = getGCCToolchainDir(Args, D.SysRoot);
@@ -2087,7 +2137,7 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
if (BiarchSibling) {
- M = BiarchSibling.value();
+ M = *BiarchSibling;
return true;
}
return false;
@@ -2129,31 +2179,21 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
// and gcc-toolsets.
if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux &&
D.getVFS().exists("/opt/rh")) {
- // Find the directory in /opt/rh/ starting with gcc-toolset-* or
- // devtoolset-* with the highest version number and add that
- // one to our prefixes.
- std::string ChosenToolsetDir;
- unsigned ChosenToolsetVersion = 0;
- std::error_code EC;
- for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin("/opt/rh", EC),
- LE;
- !EC && LI != LE; LI = LI.increment(EC)) {
- StringRef ToolsetDir = llvm::sys::path::filename(LI->path());
- unsigned ToolsetVersion;
- if ((!ToolsetDir.startswith("gcc-toolset-") &&
- !ToolsetDir.startswith("devtoolset-")) ||
- ToolsetDir.substr(ToolsetDir.rfind('-') + 1)
- .getAsInteger(10, ToolsetVersion))
- continue;
-
- if (ToolsetVersion > ChosenToolsetVersion) {
- ChosenToolsetVersion = ToolsetVersion;
- ChosenToolsetDir = "/opt/rh/" + ToolsetDir.str();
- }
- }
-
- if (ChosenToolsetVersion > 0)
- Prefixes.push_back(ChosenToolsetDir + "/root/usr");
+ // TODO: We may want to remove this, since the functionality
+ // can be achieved using config files.
+ Prefixes.push_back("/opt/rh/gcc-toolset-12/root/usr");
+ Prefixes.push_back("/opt/rh/gcc-toolset-11/root/usr");
+ Prefixes.push_back("/opt/rh/gcc-toolset-10/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-12/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-11/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-10/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-9/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-8/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-7/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-6/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-4/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-3/root/usr");
+ Prefixes.push_back("/opt/rh/devtoolset-2/root/usr");
}
// Fall back to /usr which is used by most non-Solaris systems.
@@ -2219,6 +2259,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
"i586-suse-linux", "i686-montavista-linux", "i686-gnu",
};
+ static const char *const LoongArch64LibDirs[] = {"/lib64", "/lib"};
+ static const char *const LoongArch64Triples[] = {
+ "loongarch64-linux-gnu", "loongarch64-unknown-linux-gnu"};
+
static const char *const M68kLibDirs[] = {"/lib"};
static const char *const M68kTriples[] = {
"m68k-linux-gnu", "m68k-unknown-linux-gnu", "m68k-suse-linux"};
@@ -2466,6 +2510,11 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
BiarchTripleAliases.append(begin(X32Triples), end(X32Triples));
}
break;
+ // TODO: Handle loongarch32.
+ case llvm::Triple::loongarch64:
+ LibDirs.append(begin(LoongArch64LibDirs), end(LoongArch64LibDirs));
+ TripleAliases.append(begin(LoongArch64Triples), end(LoongArch64Triples));
+ break;
case llvm::Triple::m68k:
LibDirs.append(begin(M68kLibDirs), end(M68kLibDirs));
TripleAliases.append(begin(M68kTriples), end(M68kTriples));
@@ -2804,7 +2853,8 @@ void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
RocmInstallation.print(OS);
}
-bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel
+Generic_GCC::getDefaultUnwindTableLevel(const ArgList &Args) const {
switch (getArch()) {
case llvm::Triple::aarch64:
case llvm::Triple::ppc:
@@ -2813,9 +2863,9 @@ bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const {
case llvm::Triple::ppc64le:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
- return true;
+ return UnwindTableLevel::Asynchronous;
default:
- return false;
+ return UnwindTableLevel::None;
}
}
@@ -2843,6 +2893,7 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const {
switch (getTriple().getArch()) {
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
+ case llvm::Triple::amdgcn:
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::avr:
@@ -2851,6 +2902,8 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const {
case llvm::Triple::csky:
case llvm::Triple::hexagon:
case llvm::Triple::lanai:
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
case llvm::Triple::m68k:
case llvm::Triple::mips:
case llvm::Triple::mipsel:
@@ -2861,6 +2914,7 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const {
case llvm::Triple::ppcle:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
+ case llvm::Triple::r600:
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
case llvm::Triple::sparc:
diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h
index 4eb7ab0215ab..b8610724103b 100644
--- a/clang/lib/Driver/ToolChains/Gnu.h
+++ b/clang/lib/Driver/ToolChains/Gnu.h
@@ -27,7 +27,7 @@ struct DetectedMultilibs {
/// On Biarch systems, this corresponds to the default multilib when
/// targeting the non-default multilib. Otherwise, it is empty.
- llvm::Optional<Multilib> BiarchSibling;
+ std::optional<Multilib> BiarchSibling;
};
bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
@@ -201,7 +201,7 @@ public:
Multilib SelectedMultilib;
/// On Biarch systems, this corresponds to the default multilib when
/// targeting the non-default multilib. Otherwise, it is empty.
- llvm::Optional<Multilib> BiarchSibling;
+ std::optional<Multilib> BiarchSibling;
GCCVersion Version;
@@ -218,7 +218,7 @@ public:
public:
explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {}
void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args,
- ArrayRef<std::string> ExtraTripleAliases = None);
+ ArrayRef<std::string> ExtraTripleAliases = std::nullopt);
/// Check whether we detected a valid GCC install.
bool isValid() const { return IsValid; }
@@ -296,7 +296,8 @@ public:
void printVerboseInfo(raw_ostream &OS) const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
diff --git a/clang/lib/Driver/ToolChains/HIPAMD.cpp b/clang/lib/Driver/ToolChains/HIPAMD.cpp
index b31077c1fd3b..a555fe5830e0 100644
--- a/clang/lib/Driver/ToolChains/HIPAMD.cpp
+++ b/clang/lib/Driver/ToolChains/HIPAMD.cpp
@@ -108,7 +108,12 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
const llvm::opt::ArgList &Args) const {
// Construct lld command.
// The output from ld.lld is an HSA code object file.
- ArgStringList LldArgs{"-flavor", "gnu", "--no-undefined", "-shared",
+ ArgStringList LldArgs{"-flavor",
+ "gnu",
+ "-m",
+ "elf64_amdgpu",
+ "--no-undefined",
+ "-shared",
"-plugin-opt=-amdgpu-internalize-symbols"};
auto &TC = getToolChain();
@@ -202,7 +207,7 @@ HIPAMDToolChain::HIPAMDToolChain(const Driver &D, const llvm::Triple &Triple,
if (!Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize,
true))
return;
- for (auto A : Args.filtered(options::OPT_fsanitize_EQ)) {
+ for (auto *A : Args.filtered(options::OPT_fsanitize_EQ)) {
SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false);
if (K != SanitizerKind::Address)
D.getDiags().Report(clang::diag::warn_drv_unsupported_option_for_target)
@@ -232,7 +237,7 @@ void HIPAMDToolChain::addClangTargetOptions(
DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ);
if (!MaxThreadsPerBlock.empty()) {
std::string ArgStr =
- std::string("--gpu-max-threads-per-block=") + MaxThreadsPerBlock.str();
+ (Twine("--gpu-max-threads-per-block=") + MaxThreadsPerBlock).str();
CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr));
}
@@ -242,11 +247,11 @@ void HIPAMDToolChain::addClangTargetOptions(
// supported for the foreseeable future.
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
- CC1Args.append({"-fvisibility", "hidden"});
+ CC1Args.append({"-fvisibility=hidden"});
CC1Args.push_back("-fapply-global-visibility-to-externs");
}
- for (auto BCFile : getHIPDeviceLibs(DriverArgs)) {
+ for (auto BCFile : getDeviceLibs(DriverArgs)) {
CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode"
: "-mlink-bitcode-file");
CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path));
@@ -332,14 +337,14 @@ VersionTuple HIPAMDToolChain::computeMSVCVersion(const Driver *D,
}
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
-HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
+HIPAMDToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
llvm::SmallVector<BitCodeLibraryInfo, 12> BCLibs;
if (DriverArgs.hasArg(options::OPT_nogpulib))
return {};
ArgStringList LibraryPaths;
// Find in --hip-device-lib-path and HIP_LIBRARY_PATH.
- for (auto Path : RocmInstallation.getRocmDeviceLibPathArg())
+ for (StringRef Path : RocmInstallation.getRocmDeviceLibPathArg())
LibraryPaths.push_back(DriverArgs.MakeArgString(Path));
addDirectoryList(DriverArgs, LibraryPaths, "", "HIP_DEVICE_LIB_PATH");
@@ -349,7 +354,7 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
if (!BCLibArgs.empty()) {
llvm::for_each(BCLibArgs, [&](StringRef BCName) {
StringRef FullName;
- for (std::string LibraryPath : LibraryPaths) {
+ for (StringRef LibraryPath : LibraryPaths) {
SmallString<128> Path(LibraryPath);
llvm::sys::path::append(Path, BCName);
FullName = Path;
@@ -382,15 +387,15 @@ HIPAMDToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
getDriver().Diag(DiagID);
return {};
} else
- BCLibs.push_back({AsanRTL.str(), /*ShouldInternalize=*/false});
+ BCLibs.emplace_back(AsanRTL, /*ShouldInternalize=*/false);
}
// Add the HIP specific bitcode library.
BCLibs.push_back(RocmInstallation.getHIPPath());
// Add common device libraries like ocml etc.
- for (auto N : getCommonDeviceLibNames(DriverArgs, GpuArch.str()))
- BCLibs.push_back(StringRef(N));
+ for (StringRef N : getCommonDeviceLibNames(DriverArgs, GpuArch.str()))
+ BCLibs.emplace_back(N);
// Add instrument lib.
auto InstLib =
diff --git a/clang/lib/Driver/ToolChains/HIPAMD.h b/clang/lib/Driver/ToolChains/HIPAMD.h
index 25d4a998e500..7275b1a137ac 100644
--- a/clang/lib/Driver/ToolChains/HIPAMD.h
+++ b/clang/lib/Driver/ToolChains/HIPAMD.h
@@ -76,7 +76,7 @@ public:
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
llvm::SmallVector<BitCodeLibraryInfo, 12>
- getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override;
+ getDeviceLibs(const llvm::opt::ArgList &Args) const override;
SanitizerMask getSupportedSanitizers() const override;
diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp
index d68c87e9b3e7..78566ca9a652 100644
--- a/clang/lib/Driver/ToolChains/HIPSPV.cpp
+++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp
@@ -152,9 +152,9 @@ void HIPSPVToolChain::addClangTargetOptions(
if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat))
CC1Args.append(
- {"-fvisibility", "hidden", "-fapply-global-visibility-to-externs"});
+ {"-fvisibility=hidden", "-fapply-global-visibility-to-externs"});
- llvm::for_each(getHIPDeviceLibs(DriverArgs),
+ llvm::for_each(getDeviceLibs(DriverArgs),
[&](const BitCodeLibraryInfo &BCFile) {
CC1Args.append({"-mlink-builtin-bitcode",
DriverArgs.MakeArgString(BCFile.Path)});
@@ -206,7 +206,7 @@ void HIPSPVToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs,
}
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12>
-HIPSPVToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
+HIPSPVToolChain::getDeviceLibs(const llvm::opt::ArgList &DriverArgs) const {
llvm::SmallVector<ToolChain::BitCodeLibraryInfo, 12> BCLibs;
if (DriverArgs.hasArg(options::OPT_nogpulib))
return {};
diff --git a/clang/lib/Driver/ToolChains/HIPSPV.h b/clang/lib/Driver/ToolChains/HIPSPV.h
index 79520f77c742..1c4c474cdf69 100644
--- a/clang/lib/Driver/ToolChains/HIPSPV.h
+++ b/clang/lib/Driver/ToolChains/HIPSPV.h
@@ -69,7 +69,7 @@ public:
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
llvm::SmallVector<BitCodeLibraryInfo, 12>
- getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override;
+ getDeviceLibs(const llvm::opt::ArgList &Args) const override;
SanitizerMask getSupportedSanitizers() const override;
diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp
index 584e00bb7f05..174146145777 100644
--- a/clang/lib/Driver/ToolChains/HLSL.cpp
+++ b/clang/lib/Driver/ToolChains/HLSL.cpp
@@ -64,12 +64,12 @@ bool isLegalShaderModel(Triple &T) {
return false;
}
-llvm::Optional<std::string> tryParseProfile(StringRef Profile) {
+std::optional<std::string> tryParseProfile(StringRef Profile) {
// [ps|vs|gs|hs|ds|cs|ms|as]_[major]_[minor]
SmallVector<StringRef, 3> Parts;
Profile.split(Parts, "_");
if (Parts.size() != 3)
- return NoneType();
+ return std::nullopt;
Triple::EnvironmentType Kind =
StringSwitch<Triple::EnvironmentType>(Parts[0])
@@ -84,17 +84,17 @@ llvm::Optional<std::string> tryParseProfile(StringRef Profile) {
.Case("as", Triple::EnvironmentType::Amplification)
.Default(Triple::EnvironmentType::UnknownEnvironment);
if (Kind == Triple::EnvironmentType::UnknownEnvironment)
- return NoneType();
+ return std::nullopt;
unsigned long long Major = 0;
if (llvm::getAsUnsignedInteger(Parts[1], 0, Major))
- return NoneType();
+ return std::nullopt;
unsigned long long Minor = 0;
if (Parts[2] == "x" && Kind == Triple::EnvironmentType::Library)
Minor = OfflineLibMinor;
else if (llvm::getAsUnsignedInteger(Parts[2], 0, Minor))
- return NoneType();
+ return std::nullopt;
// dxil-unknown-shadermodel-hull
llvm::Triple T;
@@ -105,7 +105,7 @@ llvm::Optional<std::string> tryParseProfile(StringRef Profile) {
if (isLegalShaderModel(T))
return T.getTriple();
else
- return NoneType();
+ return std::nullopt;
}
bool isLegalValidatorVersion(StringRef ValVersionStr, const Driver &D) {
@@ -138,7 +138,7 @@ HLSLToolChain::HLSLToolChain(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args) {}
-llvm::Optional<std::string>
+std::optional<std::string>
clang::driver::toolchains::HLSLToolChain::parseTargetProfile(
StringRef TargetProfile) {
return tryParseProfile(TargetProfile);
@@ -158,6 +158,24 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
if (!isLegalValidatorVersion(ValVerStr, getDriver()))
continue;
}
+ if (A->getOption().getID() == options::OPT_dxc_entrypoint) {
+ DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_hlsl_entrypoint),
+ A->getValue());
+ A->claim();
+ continue;
+ }
+ if (A->getOption().getID() == options::OPT__SLASH_O) {
+ StringRef OStr = A->getValue();
+ if (OStr == "d") {
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_O0));
+ A->claim();
+ continue;
+ } else {
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), OStr);
+ A->claim();
+ continue;
+ }
+ }
if (A->getOption().getID() == options::OPT_emit_pristine_llvm) {
// Translate fcgl into -S -emit-llvm and -disable-llvm-passes.
DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_S));
@@ -169,6 +187,15 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
}
DAL->append(A);
}
+
+ if (DAL->hasArg(options::OPT_o)) {
+ // When run the whole pipeline.
+ if (!DAL->hasArg(options::OPT_emit_llvm))
+ // Emit obj if write to file.
+ DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_emit_obj));
+ } else
+ DAL->AddSeparateArg(nullptr, Opts.getOption(options::OPT_o), "-");
+
// Add default validator version if not set.
// TODO: remove this once read validator version from validator.
if (!DAL->hasArg(options::OPT_dxil_validator_version)) {
@@ -177,7 +204,11 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch,
Opts.getOption(options::OPT_dxil_validator_version),
DefaultValidatorVer);
}
+ if (!DAL->hasArg(options::OPT_O_Group)) {
+ DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3");
+ }
// FIXME: add validation for enable_16bit_types should be after HLSL 2018 and
// shader model 6.2.
+ // See: https://github.com/llvm/llvm-project/issues/57876
return DAL;
}
diff --git a/clang/lib/Driver/ToolChains/HLSL.h b/clang/lib/Driver/ToolChains/HLSL.h
index 5573b0cc69e2..47eefdc24238 100644
--- a/clang/lib/Driver/ToolChains/HLSL.h
+++ b/clang/lib/Driver/ToolChains/HLSL.h
@@ -29,8 +29,7 @@ public:
llvm::opt::DerivedArgList *
TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch,
Action::OffloadKind DeviceOffloadKind) const override;
- static llvm::Optional<std::string>
- parseTargetProfile(StringRef TargetProfile);
+ static std::optional<std::string> parseTargetProfile(StringRef TargetProfile);
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index 93b987c07f29..09d2f41ab066 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -40,7 +40,7 @@ static void handleHVXWarnings(const Driver &D, const ArgList &Args) {
StringRef Val = A->getValue();
if (!Val.equals_insensitive("64b") && !Val.equals_insensitive("128b"))
D.Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << Val;
+ << A->getSpelling() << Val;
}
}
@@ -120,16 +120,17 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
HvxVerNum = 0;
// Handle HVX floating point flags.
- auto checkFlagHvxVersion = [&](auto FlagOn, auto FlagOff,
- unsigned MinVerNum) -> Optional<StringRef> {
- // Return an Optional<StringRef>:
- // - None indicates a verification failure, or that the flag was not
+ auto checkFlagHvxVersion =
+ [&](auto FlagOn, auto FlagOff,
+ unsigned MinVerNum) -> std::optional<StringRef> {
+ // Return an std::optional<StringRef>:
+ // - std::nullopt indicates a verification failure, or that the flag was not
// present in Args.
// - Otherwise the returned value is that name of the feature to add
// to Features.
Arg *A = Args.getLastArg(FlagOn, FlagOff);
if (!A)
- return None;
+ return std::nullopt;
StringRef OptName = A->getOption().getName();
if (A->getOption().matches(FlagOff))
@@ -137,12 +138,12 @@ static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
if (!HasHVX) {
D.Diag(diag::err_drv_needs_hvx) << withMinus(OptName);
- return None;
+ return std::nullopt;
}
if (HvxVerNum < MinVerNum) {
D.Diag(diag::err_drv_needs_hvx_version)
<< withMinus(OptName) << ("v" + std::to_string(HvxVerNum));
- return None;
+ return std::nullopt;
}
return makeFeature(OptName, true);
};
@@ -340,8 +341,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-pie");
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
- CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.value())));
- UseG0 = G.value() == 0;
+ CmdArgs.push_back(Args.MakeArgString("-G" + Twine(*G)));
+ UseG0 = *G == 0;
}
CmdArgs.push_back("-o");
@@ -519,8 +520,8 @@ std::string HexagonToolChain::getHexagonTargetDir(
return InstalledDir;
}
-Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
- const ArgList &Args) {
+std::optional<unsigned>
+HexagonToolChain::getSmallDataThreshold(const ArgList &Args) {
StringRef Gn = "";
if (Arg *A = Args.getLastArg(options::OPT_G)) {
Gn = A->getValue();
@@ -533,7 +534,7 @@ Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
if (!Gn.getAsInteger(10, G))
return G;
- return None;
+ return std::nullopt;
}
std::string HexagonToolChain::getCompilerRTPath() const {
diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h
index c742012444b4..47a3304c46ae 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.h
+++ b/clang/lib/Driver/ToolChains/Hexagon.h
@@ -107,8 +107,8 @@ public:
static StringRef GetDefaultCPU();
static StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args);
- static Optional<unsigned> getSmallDataThreshold(
- const llvm::opt::ArgList &Args);
+ static std::optional<unsigned>
+ getSmallDataThreshold(const llvm::opt::ArgList &Args);
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index ceb1a982c3a4..c6fb290ffdb4 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -8,6 +8,7 @@
#include "Linux.h"
#include "Arch/ARM.h"
+#include "Arch/LoongArch.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
#include "Arch/RISCV.h"
@@ -238,25 +239,18 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
// Android loader does not support .gnu.hash until API 23.
// Hexagon linker/loader does not support .gnu.hash
if (!IsMips && !IsHexagon) {
- if (Distro.IsRedhat() || Distro.IsOpenSUSE() || Distro.IsAlpineLinux() ||
- (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick) ||
- (IsAndroid && !Triple.isAndroidVersionLT(23)))
- ExtraOpts.push_back("--hash-style=gnu");
-
- if (Distro.IsDebian() || Distro.IsOpenSUSE() ||
- Distro == Distro::UbuntuLucid || Distro == Distro::UbuntuJaunty ||
- Distro == Distro::UbuntuKarmic ||
+ if (Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid ||
+ Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic ||
(IsAndroid && Triple.isAndroidVersionLT(23)))
ExtraOpts.push_back("--hash-style=both");
+ else
+ ExtraOpts.push_back("--hash-style=gnu");
}
#ifdef ENABLE_LINKER_BUILD_ID
ExtraOpts.push_back("--build-id");
#endif
- if (IsAndroid || Distro.IsOpenSUSE())
- ExtraOpts.push_back("--enable-new-dtags");
-
// The selection of paths to try here is designed to match the patterns which
// the GCC driver itself uses, as this is part of the GCC-compatible driver.
// This was determined by running GCC in a fake filesystem, creating all
@@ -473,6 +467,22 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const {
Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3";
break;
}
+ case llvm::Triple::loongarch32: {
+ LibDir = "lib32";
+ Loader =
+ ("ld-linux-loongarch-" +
+ tools::loongarch::getLoongArchABI(getDriver(), Args, Triple) + ".so.1")
+ .str();
+ break;
+ }
+ case llvm::Triple::loongarch64: {
+ LibDir = "lib64";
+ Loader =
+ ("ld-linux-loongarch-" +
+ tools::loongarch::getLoongArchABI(getDriver(), Args, Triple) + ".so.1")
+ .str();
+ break;
+ }
case llvm::Triple::m68k:
LibDir = "lib";
Loader = "ld.so.1";
@@ -681,9 +691,13 @@ void Linux::AddHIPIncludeArgs(const ArgList &DriverArgs,
void Linux::AddHIPRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- CmdArgs.append(
- {Args.MakeArgString(StringRef("-L") + RocmInstallation.getLibPath()),
- "-rpath", Args.MakeArgString(RocmInstallation.getLibPath())});
+ CmdArgs.push_back(
+ Args.MakeArgString(StringRef("-L") + RocmInstallation.getLibPath()));
+
+ if (Args.hasFlag(options::OPT_offload_add_rpath,
+ options::OPT_no_offload_add_rpath, false))
+ CmdArgs.append(
+ {"-rpath", Args.MakeArgString(RocmInstallation.getLibPath())});
CmdArgs.push_back("-lamdhip64");
}
@@ -699,11 +713,8 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs,
}
bool Linux::isPIEDefault(const llvm::opt::ArgList &Args) const {
- // TODO: Remove the special treatment for Flang once its frontend driver can
- // generate position independent code.
- return !getDriver().IsFlangMode() &&
- (CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() ||
- getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE());
+ return CLANG_DEFAULT_PIE_ON_LINUX || getTriple().isAndroid() ||
+ getTriple().isMusl() || getSanitizerArgs(Args).requiresPIE();
}
bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const {
@@ -738,6 +749,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
getTriple().getArch() == llvm::Triple::thumb ||
getTriple().getArch() == llvm::Triple::armeb ||
getTriple().getArch() == llvm::Triple::thumbeb;
+ const bool IsLoongArch64 = getTriple().getArch() == llvm::Triple::loongarch64;
const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;
const bool IsSystemZ = getTriple().getArch() == llvm::Triple::systemz;
const bool IsHexagon = getTriple().getArch() == llvm::Triple::hexagon;
@@ -754,19 +766,22 @@ SanitizerMask Linux::getSupportedSanitizers() const {
if (IsX86_64 || IsMIPS64 || IsAArch64)
Res |= SanitizerKind::DataFlow;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 ||
- IsRISCV64 || IsSystemZ || IsHexagon)
+ IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64)
Res |= SanitizerKind::Leak;
- if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ)
+ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ ||
+ IsLoongArch64)
Res |= SanitizerKind::Thread;
if (IsX86_64)
Res |= SanitizerKind::KernelMemory;
if (IsX86 || IsX86_64)
Res |= SanitizerKind::Function;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch ||
- IsPowerPC64 || IsHexagon)
+ IsPowerPC64 || IsHexagon || IsLoongArch64)
Res |= SanitizerKind::Scudo;
- if (IsX86_64 || IsAArch64) {
+ if (IsX86_64 || IsAArch64 || IsRISCV64) {
Res |= SanitizerKind::HWAddress;
+ }
+ if (IsX86_64 || IsAArch64) {
Res |= SanitizerKind::KernelHWAddress;
}
return Res;
@@ -805,3 +820,9 @@ void Linux::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const {
for (const auto &Opt : ExtraOpts)
CmdArgs.push_back(Opt.c_str());
}
+
+const char *Linux::getDefaultLinker() const {
+ if (getTriple().isAndroid())
+ return "ld.lld";
+ return Generic_ELF::getDefaultLinker();
+}
diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h
index 188cb1f09788..524391743090 100644
--- a/clang/lib/Driver/ToolChains/Linux.h
+++ b/clang/lib/Driver/ToolChains/Linux.h
@@ -63,6 +63,8 @@ public:
const llvm::opt::ArgList &DriverArgs, const JobAction &JA,
const llvm::fltSemantics *FPType = nullptr) const override;
+ const char *getDefaultLinker() const override;
+
protected:
Tool *buildAssembler() const override;
Tool *buildLinker() const override;
diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp
index bc789853049a..4edc1d2f0a1f 100644
--- a/clang/lib/Driver/ToolChains/MSP430.cpp
+++ b/clang/lib/Driver/ToolChains/MSP430.cpp
@@ -101,7 +101,7 @@ void msp430::getMSP430TargetFeatures(const Driver &D, const ArgList &Args,
Features.push_back("+hwmultf5");
} else {
D.Diag(clang::diag::err_drv_unsupported_option_argument)
- << HWMultArg->getOption().getName() << HWMult;
+ << HWMultArg->getSpelling() << HWMult;
}
}
diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp
index 14ebe38ee191..8ad67ca3e13f 100644
--- a/clang/lib/Driver/ToolChains/MSVC.cpp
+++ b/clang/lib/Driver/ToolChains/MSVC.cpp
@@ -18,7 +18,6 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/ConvertUTF.h"
@@ -411,7 +410,7 @@ MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple,
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
- Optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
+ std::optional<llvm::StringRef> VCToolsDir, VCToolsVersion;
if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsdir))
VCToolsDir = A->getValue();
if (Arg *A = Args.getLastArg(options::OPT__SLASH_vctoolsversion))
@@ -451,16 +450,20 @@ bool MSVCToolChain::IsIntegratedAssemblerDefault() const {
return true;
}
-bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel
+MSVCToolChain::getDefaultUnwindTableLevel(const ArgList &Args) const {
// Don't emit unwind tables by default for MachO targets.
if (getTriple().isOSBinFormatMachO())
- return false;
+ return UnwindTableLevel::None;
// All non-x86_32 Windows targets require unwind tables. However, LLVM
// doesn't know how to generate them for all targets, so only enable
// the ones that are actually implemented.
- return getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
- getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64;
+ if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
+ getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
+ return UnwindTableLevel::Asynchronous;
+
+ return UnwindTableLevel::None;
}
bool MSVCToolChain::isPICDefault() const {
diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h
index f09256ba124e..2826ee6aee28 100644
--- a/clang/lib/Driver/ToolChains/MSVC.h
+++ b/clang/lib/Driver/ToolChains/MSVC.h
@@ -51,7 +51,8 @@ public:
Action::OffloadKind DeviceOffloadKind) const override;
bool IsIntegratedAssemblerDefault() const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
@@ -132,7 +133,7 @@ protected:
Tool *buildLinker() const override;
Tool *buildAssembler() const override;
private:
- llvm::Optional<llvm::StringRef> WinSdkDir, WinSdkVersion, WinSysRoot;
+ std::optional<llvm::StringRef> WinSdkDir, WinSdkVersion, WinSysRoot;
std::string VCToolChainPath;
llvm::ToolsetLayout VSLayout = llvm::ToolsetLayout::OlderVS;
CudaInstallationDetector CudaInstallation;
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index ae7c4c56bf9e..908484fcc0b8 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -169,6 +169,17 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
+ if (Arg *A = Args.getLastArg(options::OPT_mguard_EQ)) {
+ StringRef GuardArgs = A->getValue();
+ if (GuardArgs == "none")
+ CmdArgs.push_back("--no-guard-cf");
+ else if (GuardArgs == "cf" || GuardArgs == "cf-nochecks")
+ CmdArgs.push_back("--guard-cf");
+ else
+ D.Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << GuardArgs;
+ }
+
CmdArgs.push_back("-o");
const char *OutputFile = Output.getFilename();
// GCC implicitly adds an .exe extension if it is given an output file name
@@ -337,6 +348,15 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Exec, CmdArgs, Inputs, Output));
}
+static bool isCrossCompiling(const llvm::Triple &T, bool RequireArchMatch) {
+ llvm::Triple HostTriple(llvm::Triple::normalize(LLVM_HOST_TRIPLE));
+ if (HostTriple.getOS() != llvm::Triple::Win32)
+ return true;
+ if (RequireArchMatch && HostTriple.getArch() != T.getArch())
+ return true;
+ return false;
+}
+
// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
std::string &Ver,
@@ -359,13 +379,26 @@ static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
return Ver.size();
}
-void toolchains::MinGW::findGccLibDir() {
- llvm::SmallVector<llvm::SmallString<32>, 2> SubdirNames;
+static llvm::Triple getLiteralTriple(const Driver &D, const llvm::Triple &T) {
+ llvm::Triple LiteralTriple(D.getTargetTriple());
+ // The arch portion of the triple may be overridden by -m32/-m64.
+ LiteralTriple.setArchName(T.getArchName());
+ return LiteralTriple;
+}
+
+void toolchains::MinGW::findGccLibDir(const llvm::Triple &LiteralTriple) {
+ llvm::SmallVector<llvm::SmallString<32>, 5> SubdirNames;
+ SubdirNames.emplace_back(LiteralTriple.str());
+ SubdirNames.emplace_back(getTriple().str());
+ SubdirNames.emplace_back(getTriple().getArchName());
+ SubdirNames.back() += "-w64-mingw32";
SubdirNames.emplace_back(getTriple().getArchName());
- SubdirNames[0] += "-w64-mingw32";
+ SubdirNames.back() += "-w64-mingw32ucrt";
SubdirNames.emplace_back("mingw32");
- if (SubdirName.empty())
- SubdirName = std::string(SubdirNames[0].str());
+ if (SubdirName.empty()) {
+ SubdirName = getTriple().getArchName();
+ SubdirName += "-w64-mingw32";
+ }
// lib: Arch Linux, Ubuntu, Windows
// lib64: openSUSE Linux
for (StringRef CandidateLib : {"lib", "lib64"}) {
@@ -380,10 +413,17 @@ void toolchains::MinGW::findGccLibDir() {
}
}
-static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &T) {
- llvm::SmallVector<llvm::SmallString<32>, 2> Gccs;
+static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &LiteralTriple,
+ const llvm::Triple &T) {
+ llvm::SmallVector<llvm::SmallString<32>, 5> Gccs;
+ Gccs.emplace_back(LiteralTriple.str());
+ Gccs.back() += "-gcc";
+ Gccs.emplace_back(T.str());
+ Gccs.back() += "-gcc";
+ Gccs.emplace_back(T.getArchName());
+ Gccs.back() += "-w64-mingw32-gcc";
Gccs.emplace_back(T.getArchName());
- Gccs[0] += "-w64-mingw32-gcc";
+ Gccs.back() += "-w64-mingw32ucrt-gcc";
Gccs.emplace_back("mingw32-gcc");
// Please do not add "gcc" here
for (StringRef CandidateGcc : Gccs)
@@ -393,12 +433,15 @@ static llvm::ErrorOr<std::string> findGcc(const llvm::Triple &T) {
}
static llvm::ErrorOr<std::string>
-findClangRelativeSysroot(const Driver &D, const llvm::Triple &T,
- std::string &SubdirName) {
- llvm::SmallVector<llvm::SmallString<32>, 2> Subdirs;
+findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple,
+ const llvm::Triple &T, std::string &SubdirName) {
+ llvm::SmallVector<llvm::SmallString<32>, 4> Subdirs;
+ Subdirs.emplace_back(LiteralTriple.str());
Subdirs.emplace_back(T.str());
Subdirs.emplace_back(T.getArchName());
- Subdirs[1] += "-w64-mingw32";
+ Subdirs.back() += "-w64-mingw32";
+ Subdirs.emplace_back(T.getArchName());
+ Subdirs.back() += "-w64-mingw32ucrt";
StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir());
StringRef Sep = llvm::sys::path::get_separator();
for (StringRef CandidateSubdir : Subdirs) {
@@ -418,14 +461,16 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
// The sequence for detecting a sysroot here should be kept in sync with
// the testTriple function below.
+ llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple());
if (getDriver().SysRoot.size())
Base = getDriver().SysRoot;
// Look for <clang-bin>/../<triplet>; if found, use <clang-bin>/.. as the
// base as it could still be a base for a gcc setup with libgcc.
- else if (llvm::ErrorOr<std::string> TargetSubdir =
- findClangRelativeSysroot(getDriver(), getTriple(), SubdirName))
+ else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot(
+ getDriver(), LiteralTriple, getTriple(), SubdirName))
Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get()));
- else if (llvm::ErrorOr<std::string> GPPName = findGcc(getTriple()))
+ else if (llvm::ErrorOr<std::string> GPPName =
+ findGcc(LiteralTriple, getTriple()))
Base = std::string(llvm::sys::path::parent_path(
llvm::sys::path::parent_path(GPPName.get())));
else
@@ -433,10 +478,17 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
llvm::sys::path::parent_path(getDriver().getInstalledDir()));
Base += llvm::sys::path::get_separator();
- findGccLibDir();
+ findGccLibDir(LiteralTriple);
+ TripleDirName = SubdirName;
// GccLibDir must precede Base/lib so that the
// correct crtbegin.o ,cetend.o would be found.
getFilePaths().push_back(GccLibDir);
+
+ // openSUSE/Fedora
+ std::string CandidateSubdir = SubdirName + "/sys-root/mingw";
+ if (getDriver().getVFS().exists(Base + CandidateSubdir))
+ SubdirName = CandidateSubdir;
+
getFilePaths().push_back(
(Base + SubdirName + llvm::sys::path::get_separator() + "lib").str());
@@ -444,9 +496,13 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
getFilePaths().push_back(
(Base + SubdirName + llvm::sys::path::get_separator() + "mingw/lib").str());
- getFilePaths().push_back(Base + "lib");
- // openSUSE
- getFilePaths().push_back(Base + SubdirName + "/sys-root/mingw/lib");
+ // Only include <base>/lib if we're not cross compiling (not even for
+ // windows->windows to a different arch), or if the sysroot has been set
+ // (where we presume the user has pointed it at an arch specific
+ // subdirectory).
+ if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/true) ||
+ getDriver().SysRoot.size())
+ getFilePaths().push_back(Base + "lib");
NativeLLVMSupport =
Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER)
@@ -482,15 +538,19 @@ bool toolchains::MinGW::HasNativeLLVMSupport() const {
return NativeLLVMSupport;
}
-bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const {
+ToolChain::UnwindTableLevel
+toolchains::MinGW::getDefaultUnwindTableLevel(const ArgList &Args) const {
Arg *ExceptionArg = Args.getLastArg(options::OPT_fsjlj_exceptions,
options::OPT_fseh_exceptions,
options::OPT_fdwarf_exceptions);
if (ExceptionArg &&
ExceptionArg->getOption().matches(options::OPT_fseh_exceptions))
- return true;
- return getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
- getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64;
+ return UnwindTableLevel::Asynchronous;
+
+ if (getArch() == llvm::Triple::x86_64 || getArch() == llvm::Triple::arm ||
+ getArch() == llvm::Triple::thumb || getArch() == llvm::Triple::aarch64)
+ return UnwindTableLevel::Asynchronous;
+ return UnwindTableLevel::None;
}
bool toolchains::MinGW::isPICDefault() const {
@@ -576,6 +636,12 @@ void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const {
// /usr/include/c++/4.8/backward
// /usr/x86_64-w64-mingw32/include
+// Fedora
+// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/x86_64-w64-mingw32ucrt
+// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include/c++/backward
+// /usr/x86_64-w64-mingw32ucrt/sys-root/mingw/include
+// /usr/lib/gcc/x86_64-w64-mingw32ucrt/12.2.1/include-fixed
+
void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdinc))
@@ -590,12 +656,6 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
- if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) {
- // openSUSE
- addSystemInclude(DriverArgs, CC1Args,
- Base + SubdirName + "/sys-root/mingw/include");
- }
-
addSystemInclude(DriverArgs, CC1Args,
Base + SubdirName + llvm::sys::path::get_separator() +
"include");
@@ -604,13 +664,39 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addSystemInclude(DriverArgs, CC1Args,
Base + SubdirName + llvm::sys::path::get_separator() + "usr/include");
- addSystemInclude(DriverArgs, CC1Args, Base + "include");
+ // Only include <base>/include if we're not cross compiling (but do allow it
+ // if we're on Windows and building for Windows on another architecture),
+ // or if the sysroot has been set (where we presume the user has pointed it
+ // at an arch specific subdirectory).
+ if (!::isCrossCompiling(getTriple(), /*RequireArchMatch=*/false) ||
+ getDriver().SysRoot.size())
+ addSystemInclude(DriverArgs, CC1Args, Base + "include");
+}
+
+void toolchains::MinGW::addClangTargetOptions(
+ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const {
+ if (Arg *A = DriverArgs.getLastArg(options::OPT_mguard_EQ)) {
+ StringRef GuardArgs = A->getValue();
+ if (GuardArgs == "none") {
+ // Do nothing.
+ } else if (GuardArgs == "cf") {
+ // Emit CFG instrumentation and the table of address-taken functions.
+ CC1Args.push_back("-cfguard");
+ } else if (GuardArgs == "cf-nochecks") {
+ // Emit only the table of address-taken functions.
+ CC1Args.push_back("-cfguard-no-checks");
+ } else {
+ getDriver().Diag(diag::err_drv_unsupported_option_argument)
+ << A->getSpelling() << GuardArgs;
+ }
+ }
}
void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
const ArgList &DriverArgs, ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
return;
StringRef Slash = llvm::sys::path::get_separator();
@@ -653,7 +739,7 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
for (auto &CppIncludeBase : CppIncludeBases) {
addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
CppIncludeBase += Slash;
- addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + SubdirName);
+ addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + TripleDirName);
addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
}
break;
@@ -667,10 +753,11 @@ static bool testTriple(const Driver &D, const llvm::Triple &Triple,
std::string SubdirName;
if (D.SysRoot.size())
return true;
+ llvm::Triple LiteralTriple = getLiteralTriple(D, Triple);
if (llvm::ErrorOr<std::string> TargetSubdir =
- findClangRelativeSysroot(D, Triple, SubdirName))
+ findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName))
return true;
- if (llvm::ErrorOr<std::string> GPPName = findGcc(Triple))
+ if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple))
return true;
// If we neither found a colocated sysroot or a matching gcc executable,
// conclude that we can't know if this is the correct spelling of the triple.
diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h
index f15f99dc8a8c..2919d57e8957 100644
--- a/clang/lib/Driver/ToolChains/MinGW.h
+++ b/clang/lib/Driver/ToolChains/MinGW.h
@@ -66,7 +66,8 @@ public:
bool HasNativeLLVMSupport() const override;
bool IsIntegratedAssemblerDefault() const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
bool isPICDefault() const override;
bool isPIEDefault(const llvm::opt::ArgList &Args) const override;
bool isPICDefaultForced() const override;
@@ -79,6 +80,10 @@ public:
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ Action::OffloadKind DeviceOffloadKind) const override;
void AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -106,9 +111,10 @@ private:
clang::driver::toolchains::Generic_GCC::GCCVersion GccVer;
std::string Ver;
std::string SubdirName;
+ std::string TripleDirName;
mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
mutable std::unique_ptr<tools::gcc::Compiler> Compiler;
- void findGccLibDir();
+ void findGccLibDir(const llvm::Triple &LiteralTriple);
bool NativeLLVMSupport;
};
diff --git a/clang/lib/Driver/ToolChains/Myriad.cpp b/clang/lib/Driver/ToolChains/Myriad.cpp
index f31466633104..eebf6dfc7d10 100644
--- a/clang/lib/Driver/ToolChains/Myriad.cpp
+++ b/clang/lib/Driver/ToolChains/Myriad.cpp
@@ -218,7 +218,7 @@ MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple,
default:
D.Diag(clang::diag::err_target_unsupported_arch)
<< Triple.getArchName() << "myriad";
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case llvm::Triple::shave:
return;
case llvm::Triple::sparc:
diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp
index ac90ed49b8a5..7a7c905e3e7a 100644
--- a/clang/lib/Driver/ToolChains/NetBSD.cpp
+++ b/clang/lib/Driver/ToolChains/NetBSD.cpp
@@ -11,6 +11,7 @@
#include "Arch/Mips.h"
#include "Arch/Sparc.h"
#include "CommonArgs.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
@@ -435,6 +436,40 @@ ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const {
return ToolChain::CST_Libstdcxx;
}
+void NetBSD::AddClangSystemIncludeArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc))
+ return;
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
+ SmallString<128> Dir(D.ResourceDir);
+ llvm::sys::path::append(Dir, "include");
+ addSystemInclude(DriverArgs, CC1Args, Dir.str());
+ }
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ // Check for configure-time C include directories.
+ StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (CIncludeDirs != "") {
+ SmallVector<StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (StringRef dir : dirs) {
+ StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ return;
+ }
+
+ addExternCSystemInclude(DriverArgs, CC1Args,
+ concat(D.SysRoot, "/usr/include"));
+}
+
void NetBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
const std::string Candidates[] = {
diff --git a/clang/lib/Driver/ToolChains/NetBSD.h b/clang/lib/Driver/ToolChains/NetBSD.h
index 8348554fd149..0f9b6dceb6fc 100644
--- a/clang/lib/Driver/ToolChains/NetBSD.h
+++ b/clang/lib/Driver/ToolChains/NetBSD.h
@@ -58,6 +58,9 @@ public:
CXXStdlibType GetDefaultCXXStdlibType() const override;
+ void
+ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const override;
void addLibCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
@@ -65,8 +68,9 @@ public:
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override {
- return true;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override {
+ return UnwindTableLevel::Asynchronous;
}
llvm::ExceptionHandling GetExceptionModel(
diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp
index 8b3a40606ff3..c80c650e18fb 100644
--- a/clang/lib/Driver/ToolChains/OpenBSD.cpp
+++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp
@@ -363,11 +363,12 @@ Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); }
bool OpenBSD::HasNativeLLVMSupport() const { return true; }
-bool OpenBSD::IsUnwindTablesDefault(const ArgList &Args) const {
- switch (getArch()) {
- case llvm::Triple::arm:
- return false;
- default:
- return true;
- }
+ToolChain::UnwindTableLevel
+OpenBSD::getDefaultUnwindTableLevel(const ArgList &Args) const {
+ switch (getArch()) {
+ case llvm::Triple::arm:
+ return UnwindTableLevel::None;
+ default:
+ return UnwindTableLevel::Asynchronous;
+ }
}
diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h
index 2d4c4e34520b..b7d3d1b5b6dc 100644
--- a/clang/lib/Driver/ToolChains/OpenBSD.h
+++ b/clang/lib/Driver/ToolChains/OpenBSD.h
@@ -82,7 +82,8 @@ public:
std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component,
FileType Type = ToolChain::FT_Static) const override;
- bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override;
+ UnwindTableLevel
+ getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override;
LangOptions::StackProtectorMode
GetDefaultStackProtectorLevel(bool KernelOrKext) const override {
diff --git a/clang/lib/Driver/ToolChains/PPCLinux.cpp b/clang/lib/Driver/ToolChains/PPCLinux.cpp
index 2fea262fd109..bdbecaef6040 100644
--- a/clang/lib/Driver/ToolChains/PPCLinux.cpp
+++ b/clang/lib/Driver/ToolChains/PPCLinux.cpp
@@ -49,7 +49,10 @@ PPCLinuxToolChain::PPCLinuxToolChain(const Driver &D,
: Linux(D, Triple, Args) {
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
StringRef ABIName = A->getValue();
- if (ABIName == "ieeelongdouble" && !SupportIEEEFloat128(D, Triple, Args))
+
+ if ((ABIName == "ieeelongdouble" &&
+ !SupportIEEEFloat128(D, Triple, Args)) ||
+ (ABIName == "ibmlongdouble" && !supportIBMLongDouble(D, Args)))
D.Diag(diag::warn_drv_unsupported_float_abi_by_lib) << ABIName;
}
}
@@ -67,6 +70,18 @@ void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
Linux::AddClangSystemIncludeArgs(DriverArgs, CC1Args);
}
+bool PPCLinuxToolChain::supportIBMLongDouble(
+ const Driver &D, const llvm::opt::ArgList &Args) const {
+ if (Args.hasArg(options::OPT_nostdlib, options::OPT_nostdlibxx))
+ return true;
+
+ CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args);
+ if (StdLib == CST_Libstdcxx)
+ return true;
+
+ return StdLib == CST_Libcxx && !defaultToIEEELongDouble();
+}
+
bool PPCLinuxToolChain::SupportIEEEFloat128(
const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args) const {
@@ -78,10 +93,11 @@ bool PPCLinuxToolChain::SupportIEEEFloat128(
CXXStdlibType StdLib = ToolChain::GetCXXStdlibType(Args);
bool HasUnsupportedCXXLib =
- StdLib == CST_Libcxx ||
+ (StdLib == CST_Libcxx && !defaultToIEEELongDouble()) ||
(StdLib == CST_Libstdcxx &&
GCCInstallation.getVersion().isOlderThan(12, 1, 0));
- return GlibcSupportsFloat128(Linux::getDynamicLinker(Args)) &&
+ std::string Linker = Linux::getDynamicLinker(Args);
+ return GlibcSupportsFloat128((Twine(D.DyldPrefix) + Linker).str()) &&
!(D.CCCIsCXX() && HasUnsupportedCXXLib);
}
diff --git a/clang/lib/Driver/ToolChains/PPCLinux.h b/clang/lib/Driver/ToolChains/PPCLinux.h
index e0318ae8a3a2..63adaff6be9c 100644
--- a/clang/lib/Driver/ToolChains/PPCLinux.h
+++ b/clang/lib/Driver/ToolChains/PPCLinux.h
@@ -27,6 +27,8 @@ public:
private:
bool SupportIEEEFloat128(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args) const;
+ bool supportIBMLongDouble(const Driver &D,
+ const llvm::opt::ArgList &Args) const;
};
} // end namespace toolchains
diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp
index 35a83d79abfd..643f815c5835 100644
--- a/clang/lib/Driver/ToolChains/PS4CPU.cpp
+++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp
@@ -152,6 +152,40 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
assert(Output.isNothing() && "Invalid output.");
}
+ const bool UseLTO = D.isUsingLTO();
+ const bool UseJMC =
+ Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false);
+ const bool IsPS4 = TC.getTriple().isPS4();
+ const bool IsPS5 = TC.getTriple().isPS5();
+ assert(IsPS4 || IsPS5);
+
+ auto AddCodeGenFlag = [&](Twine Flag) {
+ const char *Prefix = nullptr;
+ if (IsPS4 && D.getLTOMode() == LTOK_Thin)
+ Prefix = "-lto-thin-debug-options=";
+ else if (IsPS4 && D.getLTOMode() == LTOK_Full)
+ Prefix = "-lto-debug-options=";
+ else if (IsPS5)
+ Prefix = "-plugin-opt=";
+ else
+ llvm_unreachable("new LTO mode?");
+
+ CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + Flag));
+ };
+
+ if (UseLTO) {
+ // We default to creating the arange section, but LTO does not. Enable it
+ // here.
+ AddCodeGenFlag("-generate-arange-section");
+
+ // This tells LTO to perform JustMyCode instrumentation.
+ if (UseJMC)
+ AddCodeGenFlag("-enable-jmc-instrument");
+
+ if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir))
+ AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue());
+ }
+
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs))
TC.addSanitizerArgs(Args, CmdArgs, "-l", "");
@@ -171,6 +205,15 @@ void tools::PScpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lpthread");
}
+ if (UseJMC) {
+ CmdArgs.push_back("--whole-archive");
+ if (IsPS4)
+ CmdArgs.push_back("-lSceDbgJmc");
+ else
+ CmdArgs.push_back("-lSceJmc_nosubmission");
+ CmdArgs.push_back("--no-whole-archive");
+ }
+
if (Args.hasArg(options::OPT_fuse_ld_EQ)) {
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< "-fuse-ld" << TC.getTriple().str();
diff --git a/clang/lib/Driver/ToolChains/ROCm.h b/clang/lib/Driver/ToolChains/ROCm.h
index 33baaa887043..5c1431f3270c 100644
--- a/clang/lib/Driver/ToolChains/ROCm.h
+++ b/clang/lib/Driver/ToolChains/ROCm.h
@@ -107,6 +107,7 @@ private:
SmallString<0> LibPath;
SmallString<0> LibDevicePath;
SmallString<0> IncludePath;
+ SmallString<0> SharePath;
llvm::StringMap<std::string> LibDeviceMap;
// Libraries that are always linked.
@@ -251,8 +252,11 @@ public:
}
/// Get libdevice file for given architecture
- std::string getLibDeviceFile(StringRef Gpu) const {
- return LibDeviceMap.lookup(Gpu);
+ StringRef getLibDeviceFile(StringRef Gpu) const {
+ auto Loc = LibDeviceMap.find(Gpu);
+ if (Loc == LibDeviceMap.end())
+ return "";
+ return Loc->second;
}
void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs,
@@ -262,7 +266,7 @@ public:
void detectHIPRuntime();
/// Get the values for --rocm-device-lib-path arguments
- std::vector<std::string> getRocmDeviceLibPathArg() const {
+ ArrayRef<std::string> getRocmDeviceLibPathArg() const {
return RocmDeviceLibPathArg;
}
@@ -272,7 +276,7 @@ public:
/// Get the value for --hip-version argument
StringRef getHIPVersionArg() const { return HIPVersionArg; }
- std::string getHIPVersion() const { return DetectedVersion; }
+ StringRef getHIPVersion() const { return DetectedVersion; }
};
} // end namespace driver
diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp
index c75375ac95f7..7cc872c71775 100644
--- a/clang/lib/Driver/ToolChains/Solaris.cpp
+++ b/clang/lib/Driver/ToolChains/Solaris.cpp
@@ -115,6 +115,8 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(getToolChain().GetFilePath(values_xpg)));
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
+ // Add crtfastmath.o if available and fast math is enabled.
+ getToolChain().addFastMathRuntimeIfAvailable(Args, CmdArgs);
}
getToolChain().AddFilePathLibArgs(Args, CmdArgs);
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index b051bff87512..a1c4cd9ef9c7 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -424,8 +424,8 @@ void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
- DriverArgs.hasArg(options::OPT_nostdincxx))
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc, options::OPT_nostdinc,
+ options::OPT_nostdincxx))
return;
switch (GetCXXStdlibType(DriverArgs)) {
diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp
index 66da6fe97059..a890cc58ee42 100644
--- a/clang/lib/Driver/Types.cpp
+++ b/clang/lib/Driver/Types.cpp
@@ -42,7 +42,7 @@ static constexpr TypeInfo TypeInfos[] = {
#include "clang/Driver/Types.def"
#undef TYPE
};
-static const unsigned numTypes = llvm::array_lengthof(TypeInfos);
+static const unsigned numTypes = std::size(TypeInfos);
static const TypeInfo &getInfo(unsigned id) {
assert(id > 0 && id - 1 < numTypes && "Invalid Type ID.");
@@ -286,74 +286,77 @@ bool types::isHIP(ID Id) {
}
}
+bool types::isHLSL(ID Id) { return Id == TY_HLSL; }
+
bool types::isSrcFile(ID Id) {
return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID;
}
types::ID types::lookupTypeForExtension(llvm::StringRef Ext) {
return llvm::StringSwitch<types::ID>(Ext)
- .Case("c", TY_C)
- .Case("C", TY_CXX)
- .Case("F", TY_Fortran)
- .Case("f", TY_PP_Fortran)
- .Case("h", TY_CHeader)
- .Case("H", TY_CXXHeader)
- .Case("i", TY_PP_C)
- .Case("m", TY_ObjC)
- .Case("M", TY_ObjCXX)
- .Case("o", TY_Object)
- .Case("S", TY_Asm)
- .Case("s", TY_PP_Asm)
- .Case("bc", TY_LLVM_BC)
- .Case("cc", TY_CXX)
- .Case("CC", TY_CXX)
- .Case("cl", TY_CL)
- .Case("clcpp", TY_CLCXX)
- .Case("cp", TY_CXX)
- .Case("cu", TY_CUDA)
- .Case("hh", TY_CXXHeader)
- .Case("ii", TY_PP_CXX)
- .Case("ll", TY_LLVM_IR)
- .Case("mi", TY_PP_ObjC)
- .Case("mm", TY_ObjCXX)
- .Case("rs", TY_RenderScript)
- .Case("adb", TY_Ada)
- .Case("ads", TY_Ada)
- .Case("asm", TY_PP_Asm)
- .Case("ast", TY_AST)
- .Case("ccm", TY_CXXModule)
- .Case("cpp", TY_CXX)
- .Case("CPP", TY_CXX)
- .Case("c++", TY_CXX)
- .Case("C++", TY_CXX)
- .Case("cui", TY_PP_CUDA)
- .Case("cxx", TY_CXX)
- .Case("CXX", TY_CXX)
- .Case("F90", TY_Fortran)
- .Case("f90", TY_PP_Fortran)
- .Case("F95", TY_Fortran)
- .Case("f95", TY_PP_Fortran)
- .Case("for", TY_PP_Fortran)
- .Case("FOR", TY_PP_Fortran)
- .Case("fpp", TY_Fortran)
- .Case("FPP", TY_Fortran)
- .Case("gch", TY_PCH)
- .Case("hip", TY_HIP)
- .Case("hpp", TY_CXXHeader)
- .Case("hxx", TY_CXXHeader)
- .Case("iim", TY_PP_CXXModule)
- .Case("iih", TY_PP_CXXHeaderUnit)
- .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)
- .Case("cppm", TY_CXXModule)
- .Case("cxxm", TY_CXXModule)
- .Case("hlsl", TY_HLSL)
- .Default(TY_INVALID);
+ .Case("c", TY_C)
+ .Case("C", TY_CXX)
+ .Case("F", TY_Fortran)
+ .Case("f", TY_PP_Fortran)
+ .Case("h", TY_CHeader)
+ .Case("H", TY_CXXHeader)
+ .Case("i", TY_PP_C)
+ .Case("m", TY_ObjC)
+ .Case("M", TY_ObjCXX)
+ .Case("o", TY_Object)
+ .Case("S", TY_Asm)
+ .Case("s", TY_PP_Asm)
+ .Case("bc", TY_LLVM_BC)
+ .Case("cc", TY_CXX)
+ .Case("CC", TY_CXX)
+ .Case("cl", TY_CL)
+ .Case("clcpp", TY_CLCXX)
+ .Case("cp", TY_CXX)
+ .Case("cu", TY_CUDA)
+ .Case("hh", TY_CXXHeader)
+ .Case("ii", TY_PP_CXX)
+ .Case("ll", TY_LLVM_IR)
+ .Case("mi", TY_PP_ObjC)
+ .Case("mm", TY_ObjCXX)
+ .Case("rs", TY_RenderScript)
+ .Case("adb", TY_Ada)
+ .Case("ads", TY_Ada)
+ .Case("asm", TY_PP_Asm)
+ .Case("ast", TY_AST)
+ .Case("ccm", TY_CXXModule)
+ .Case("cpp", TY_CXX)
+ .Case("CPP", TY_CXX)
+ .Case("c++", TY_CXX)
+ .Case("C++", TY_CXX)
+ .Case("cui", TY_PP_CUDA)
+ .Case("cxx", TY_CXX)
+ .Case("CXX", TY_CXX)
+ .Case("F90", TY_Fortran)
+ .Case("f90", TY_PP_Fortran)
+ .Case("F95", TY_Fortran)
+ .Case("f95", TY_PP_Fortran)
+ .Case("for", TY_PP_Fortran)
+ .Case("FOR", TY_PP_Fortran)
+ .Case("fpp", TY_Fortran)
+ .Case("FPP", TY_Fortran)
+ .Case("gch", TY_PCH)
+ .Case("hip", TY_HIP)
+ .Case("hipi", TY_PP_HIP)
+ .Case("hpp", TY_CXXHeader)
+ .Case("hxx", TY_CXXHeader)
+ .Case("iim", TY_PP_CXXModule)
+ .Case("iih", TY_PP_CXXHeaderUnit)
+ .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)
+ .Case("cppm", TY_CXXModule)
+ .Case("cxxm", TY_CXXModule)
+ .Case("hlsl", TY_HLSL)
+ .Default(TY_INVALID);
}
types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp
index 63b575178bd1..cf9b5780c455 100644
--- a/clang/lib/Driver/XRayArgs.cpp
+++ b/clang/lib/Driver/XRayArgs.cpp
@@ -79,8 +79,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
XRayInstrument = true;
if (const Arg *A =
- Args.getLastArg(options::OPT_fxray_instruction_threshold_,
- options::OPT_fxray_instruction_threshold_EQ)) {
+ Args.getLastArg(options::OPT_fxray_instruction_threshold_EQ)) {
StringRef S = A->getValue();
if (S.getAsInteger(0, InstructionThreshold) || InstructionThreshold < 0)
D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 1ca041f3ed6d..736e450574d9 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/ParentMap.h"
#include "clang/Edit/Commit.h"
#include "clang/Lex/Lexer.h"
+#include <optional>
using namespace clang;
using namespace edit;
@@ -691,7 +692,7 @@ static bool getLiteralInfo(SourceRange literalRange,
if (text.empty())
return false;
- Optional<bool> UpperU, UpperL;
+ std::optional<bool> UpperU, UpperL;
bool UpperF = false;
struct Suff {
@@ -775,8 +776,8 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
ASTContext &Ctx = NS.getASTContext();
Selector Sel = Msg->getSelector();
- Optional<NSAPI::NSNumberLiteralMethodKind>
- MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
+ std::optional<NSAPI::NSNumberLiteralMethodKind> MKOpt =
+ NS.getNSNumberLiteralMethodKind(Sel);
if (!MKOpt)
return false;
NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
@@ -796,28 +797,28 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
case NSAPI::NSNumberWithUnsignedInt:
case NSAPI::NSNumberWithUnsignedInteger:
CallIsUnsigned = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NSAPI::NSNumberWithInt:
case NSAPI::NSNumberWithInteger:
break;
case NSAPI::NSNumberWithUnsignedLong:
CallIsUnsigned = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NSAPI::NSNumberWithLong:
CallIsLong = true;
break;
case NSAPI::NSNumberWithUnsignedLongLong:
CallIsUnsigned = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NSAPI::NSNumberWithLongLong:
CallIsLongLong = true;
break;
case NSAPI::NSNumberWithDouble:
CallIsDouble = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NSAPI::NSNumberWithFloat:
CallIsFloating = true;
break;
@@ -983,8 +984,8 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
ASTContext &Ctx = NS.getASTContext();
Selector Sel = Msg->getSelector();
- Optional<NSAPI::NSNumberLiteralMethodKind>
- MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
+ std::optional<NSAPI::NSNumberLiteralMethodKind> MKOpt =
+ NS.getNSNumberLiteralMethodKind(Sel);
if (!MKOpt)
return false;
NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp
index 073e36f320d3..553b7bbe710f 100644
--- a/clang/lib/ExtractAPI/API.cpp
+++ b/clang/lib/ExtractAPI/API.cpp
@@ -27,7 +27,8 @@ using namespace llvm;
namespace {
template <typename RecordTy, typename... CtorArgsTy>
-RecordTy *addTopLevelRecord(APISet::RecordMap<RecordTy> &RecordMap,
+RecordTy *addTopLevelRecord(DenseMap<StringRef, APIRecord *> &USRLookupTable,
+ APISet::RecordMap<RecordTy> &RecordMap,
StringRef USR, CtorArgsTy &&...CtorArgs) {
auto Result = RecordMap.insert({USR, nullptr});
@@ -36,75 +37,99 @@ RecordTy *addTopLevelRecord(APISet::RecordMap<RecordTy> &RecordMap,
Result.first->second =
std::make_unique<RecordTy>(USR, std::forward<CtorArgsTy>(CtorArgs)...);
- return Result.first->second.get();
+ auto *Record = Result.first->second.get();
+ USRLookupTable.insert({USR, Record});
+ return Record;
}
} // namespace
GlobalVariableRecord *
APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability, LinkageInfo Linkage,
+ AvailabilitySet Availabilities, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Fragments,
- DeclarationFragments SubHeading) {
- return addTopLevelRecord(GlobalVariables, USR, Name, Loc, Availability,
- Linkage, Comment, Fragments, SubHeading);
+ DeclarationFragments SubHeading, bool IsFromSystemHeader) {
+ return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc,
+ std::move(Availabilities), Linkage, Comment,
+ Fragments, SubHeading, IsFromSystemHeader);
}
GlobalFunctionRecord *APISet::addGlobalFunction(
StringRef Name, StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability, LinkageInfo Linkage,
+ AvailabilitySet Availabilities, LinkageInfo Linkage,
const DocComment &Comment, DeclarationFragments Fragments,
- DeclarationFragments SubHeading, FunctionSignature Signature) {
- return addTopLevelRecord(GlobalFunctions, USR, Name, Loc, Availability,
- Linkage, Comment, Fragments, SubHeading, Signature);
+ DeclarationFragments SubHeading, FunctionSignature Signature,
+ bool IsFromSystemHeader) {
+ return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc,
+ std::move(Availabilities), Linkage, Comment,
+ Fragments, SubHeading, Signature,
+ IsFromSystemHeader);
}
-EnumConstantRecord *APISet::addEnumConstant(
- EnumRecord *Enum, StringRef Name, StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability, const DocComment &Comment,
- DeclarationFragments Declaration, DeclarationFragments SubHeading) {
+EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name,
+ StringRef USR, PresumedLoc Loc,
+ AvailabilitySet Availabilities,
+ const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading,
+ bool IsFromSystemHeader) {
auto Record = std::make_unique<EnumConstantRecord>(
- USR, Name, Loc, Availability, Comment, Declaration, SubHeading);
+ USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
+ SubHeading, IsFromSystemHeader);
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Enum->USR, Enum->Name, Enum->getKind(), Enum);
+ USRBasedLookupTable.insert({USR, Record.get()});
return Enum->Constants.emplace_back(std::move(Record)).get();
}
EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability,
+ AvailabilitySet Availabilities,
const DocComment &Comment,
DeclarationFragments Declaration,
- DeclarationFragments SubHeading) {
- return addTopLevelRecord(Enums, USR, Name, Loc, Availability, Comment,
- Declaration, SubHeading);
+ DeclarationFragments SubHeading,
+ bool IsFromSystemHeader) {
+ return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc,
+ std::move(Availabilities), Comment, Declaration,
+ SubHeading, IsFromSystemHeader);
}
StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability,
+ AvailabilitySet Availabilities,
const DocComment &Comment,
DeclarationFragments Declaration,
- DeclarationFragments SubHeading) {
+ DeclarationFragments SubHeading,
+ bool IsFromSystemHeader) {
auto Record = std::make_unique<StructFieldRecord>(
- USR, Name, Loc, Availability, Comment, Declaration, SubHeading);
+ USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
+ SubHeading, IsFromSystemHeader);
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Struct->USR, Struct->Name, Struct->getKind(), Struct);
+ USRBasedLookupTable.insert({USR, Record.get()});
return Struct->Fields.emplace_back(std::move(Record)).get();
}
StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability,
+ AvailabilitySet Availabilities,
const DocComment &Comment,
DeclarationFragments Declaration,
- DeclarationFragments SubHeading) {
- return addTopLevelRecord(Structs, USR, Name, Loc, Availability, Comment,
- Declaration, SubHeading);
+ DeclarationFragments SubHeading,
+ bool IsFromSystemHeader) {
+ return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc,
+ std::move(Availabilities), Comment, Declaration,
+ SubHeading, IsFromSystemHeader);
}
ObjCCategoryRecord *APISet::addObjCCategory(
StringRef Name, StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability, const DocComment &Comment,
+ AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
- SymbolReference Interface) {
+ SymbolReference Interface, bool IsFromSystemHeader) {
// Create the category record.
- auto *Record = addTopLevelRecord(ObjCCategories, USR, Name, Loc, Availability,
- Comment, Declaration, SubHeading, Interface);
+ auto *Record =
+ addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc,
+ std::move(Availabilities), Comment, Declaration,
+ SubHeading, Interface, IsFromSystemHeader);
// If this category is extending a known interface, associate it with the
// ObjCInterfaceRecord.
@@ -115,76 +140,119 @@ ObjCCategoryRecord *APISet::addObjCCategory(
return Record;
}
-ObjCInterfaceRecord *APISet::addObjCInterface(
- StringRef Name, StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability, LinkageInfo Linkage,
- const DocComment &Comment, DeclarationFragments Declaration,
- DeclarationFragments SubHeading, SymbolReference SuperClass) {
- return addTopLevelRecord(ObjCInterfaces, USR, Name, Loc, Availability,
- Linkage, Comment, Declaration, SubHeading,
- SuperClass);
+ObjCInterfaceRecord *
+APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc,
+ AvailabilitySet Availabilities, LinkageInfo Linkage,
+ const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading,
+ SymbolReference SuperClass, bool IsFromSystemHeader) {
+ return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc,
+ std::move(Availabilities), Linkage, Comment,
+ Declaration, SubHeading, SuperClass,
+ IsFromSystemHeader);
}
ObjCMethodRecord *APISet::addObjCMethod(
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
- PresumedLoc Loc, const AvailabilityInfo &Availability,
- const DocComment &Comment, DeclarationFragments Declaration,
- DeclarationFragments SubHeading, FunctionSignature Signature,
- bool IsInstanceMethod) {
- auto Record = std::make_unique<ObjCMethodRecord>(
- USR, Name, Loc, Availability, Comment, Declaration, SubHeading, Signature,
- IsInstanceMethod);
+ PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
+ DeclarationFragments Declaration, DeclarationFragments SubHeading,
+ FunctionSignature Signature, bool IsInstanceMethod,
+ bool IsFromSystemHeader) {
+ std::unique_ptr<ObjCMethodRecord> Record;
+ if (IsInstanceMethod)
+ Record = std::make_unique<ObjCInstanceMethodRecord>(
+ USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
+ SubHeading, Signature, IsFromSystemHeader);
+ else
+ Record = std::make_unique<ObjCClassMethodRecord>(
+ USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
+ SubHeading, Signature, IsFromSystemHeader);
+
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Container->USR, Container->Name, Container->getKind(), Container);
+ USRBasedLookupTable.insert({USR, Record.get()});
return Container->Methods.emplace_back(std::move(Record)).get();
}
ObjCPropertyRecord *APISet::addObjCProperty(
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
- PresumedLoc Loc, const AvailabilityInfo &Availability,
- const DocComment &Comment, DeclarationFragments Declaration,
- DeclarationFragments SubHeading,
+ PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
+ DeclarationFragments Declaration, DeclarationFragments SubHeading,
ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
- StringRef SetterName, bool IsOptional) {
- auto Record = std::make_unique<ObjCPropertyRecord>(
- USR, Name, Loc, Availability, Comment, Declaration, SubHeading,
- Attributes, GetterName, SetterName, IsOptional);
+ StringRef SetterName, bool IsOptional, bool IsInstanceProperty,
+ bool IsFromSystemHeader) {
+ std::unique_ptr<ObjCPropertyRecord> Record;
+ if (IsInstanceProperty)
+ Record = std::make_unique<ObjCInstancePropertyRecord>(
+ USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
+ SubHeading, Attributes, GetterName, SetterName, IsOptional,
+ IsFromSystemHeader);
+ else
+ Record = std::make_unique<ObjCClassPropertyRecord>(
+ USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
+ SubHeading, Attributes, GetterName, SetterName, IsOptional,
+ IsFromSystemHeader);
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Container->USR, Container->Name, Container->getKind(), Container);
+ USRBasedLookupTable.insert({USR, Record.get()});
return Container->Properties.emplace_back(std::move(Record)).get();
}
ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
ObjCContainerRecord *Container, StringRef Name, StringRef USR,
- PresumedLoc Loc, const AvailabilityInfo &Availability,
- const DocComment &Comment, DeclarationFragments Declaration,
- DeclarationFragments SubHeading,
- ObjCInstanceVariableRecord::AccessControl Access) {
+ PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
+ DeclarationFragments Declaration, DeclarationFragments SubHeading,
+ ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) {
auto Record = std::make_unique<ObjCInstanceVariableRecord>(
- USR, Name, Loc, Availability, Comment, Declaration, SubHeading, Access);
+ USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
+ SubHeading, Access, IsFromSystemHeader);
+ Record->ParentInformation = APIRecord::HierarchyInformation(
+ Container->USR, Container->Name, Container->getKind(), Container);
+ USRBasedLookupTable.insert({USR, Record.get()});
return Container->Ivars.emplace_back(std::move(Record)).get();
}
-ObjCProtocolRecord *APISet::addObjCProtocol(
- StringRef Name, StringRef USR, PresumedLoc Loc,
- const AvailabilityInfo &Availability, const DocComment &Comment,
- DeclarationFragments Declaration, DeclarationFragments SubHeading) {
- return addTopLevelRecord(ObjCProtocols, USR, Name, Loc, Availability, Comment,
- Declaration, SubHeading);
+ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR,
+ PresumedLoc Loc,
+ AvailabilitySet Availabilities,
+ const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading,
+ bool IsFromSystemHeader) {
+ return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc,
+ std::move(Availabilities), Comment, Declaration,
+ SubHeading, IsFromSystemHeader);
}
MacroDefinitionRecord *
APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
DeclarationFragments Declaration,
- DeclarationFragments SubHeading) {
- return addTopLevelRecord(Macros, USR, Name, Loc, Declaration, SubHeading);
+ DeclarationFragments SubHeading,
+ bool IsFromSystemHeader) {
+ return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc,
+ Declaration, SubHeading, IsFromSystemHeader);
+}
+
+TypedefRecord *
+APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc,
+ AvailabilitySet Availabilities, const DocComment &Comment,
+ DeclarationFragments Declaration,
+ DeclarationFragments SubHeading,
+ SymbolReference UnderlyingType, bool IsFromSystemHeader) {
+ return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc,
+ std::move(Availabilities), Comment, Declaration,
+ SubHeading, UnderlyingType, IsFromSystemHeader);
}
-TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR,
- PresumedLoc Loc,
- const AvailabilityInfo &Availability,
- const DocComment &Comment,
- DeclarationFragments Declaration,
- DeclarationFragments SubHeading,
- SymbolReference UnderlyingType) {
- return addTopLevelRecord(Typedefs, USR, Name, Loc, Availability, Comment,
- Declaration, SubHeading, UnderlyingType);
+APIRecord *APISet::findRecordForUSR(StringRef USR) const {
+ if (USR.empty())
+ return nullptr;
+
+ auto It = USRBasedLookupTable.find(USR);
+ if (It != USRBasedLookupTable.end())
+ return It->second;
+ return nullptr;
}
StringRef APISet::recordUSR(const Decl *D) {
@@ -214,8 +282,9 @@ StringRef APISet::copyString(StringRef String) {
}
APIRecord::~APIRecord() {}
-
ObjCContainerRecord::~ObjCContainerRecord() {}
+ObjCMethodRecord::~ObjCMethodRecord() {}
+ObjCPropertyRecord::~ObjCPropertyRecord() {}
void GlobalFunctionRecord::anchor() {}
void GlobalVariableRecord::anchor() {}
@@ -223,9 +292,11 @@ void EnumConstantRecord::anchor() {}
void EnumRecord::anchor() {}
void StructFieldRecord::anchor() {}
void StructRecord::anchor() {}
-void ObjCPropertyRecord::anchor() {}
+void ObjCInstancePropertyRecord::anchor() {}
+void ObjCClassPropertyRecord::anchor() {}
void ObjCInstanceVariableRecord::anchor() {}
-void ObjCMethodRecord::anchor() {}
+void ObjCInstanceMethodRecord::anchor() {}
+void ObjCClassMethodRecord::anchor() {}
void ObjCCategoryRecord::anchor() {}
void ObjCInterfaceRecord::anchor() {}
void ObjCProtocolRecord::anchor() {}
diff --git a/clang/lib/ExtractAPI/APIIgnoresList.cpp b/clang/lib/ExtractAPI/APIIgnoresList.cpp
new file mode 100644
index 000000000000..1d65ae2b8e31
--- /dev/null
+++ b/clang/lib/ExtractAPI/APIIgnoresList.cpp
@@ -0,0 +1,53 @@
+//===- ExtractAPI/APIIgnoresList.cpp -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements APIIgnoresList that allows users to specifiy a file
+/// containing symbols to ignore during API extraction.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ExtractAPI/APIIgnoresList.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
+
+using namespace clang;
+using namespace clang::extractapi;
+using namespace llvm;
+
+char IgnoresFileNotFound::ID;
+
+void IgnoresFileNotFound::log(llvm::raw_ostream &os) const {
+ os << "Could not find API ignores file " << Path;
+}
+
+std::error_code IgnoresFileNotFound::convertToErrorCode() const {
+ return llvm::inconvertibleErrorCode();
+}
+
+Expected<APIIgnoresList> APIIgnoresList::create(StringRef IgnoresFilePath,
+ FileManager &FM) {
+ auto BufferOrErr = FM.getBufferForFile(IgnoresFilePath);
+ if (!BufferOrErr)
+ return make_error<IgnoresFileNotFound>(IgnoresFilePath);
+
+ auto Buffer = std::move(BufferOrErr.get());
+ SmallVector<StringRef, 32> Lines;
+ Buffer->getBuffer().split(Lines, '\n', /*MaxSplit*/ -1, /*KeepEmpty*/ false);
+ // Symbol names don't have spaces in them, let's just remove these in case the
+ // input is slighlty malformed.
+ transform(Lines, Lines.begin(), [](StringRef Line) { return Line.trim(); });
+ sort(Lines);
+ return APIIgnoresList(std::move(Lines), std::move(Buffer));
+}
+
+bool APIIgnoresList::shouldIgnore(StringRef SymbolName) const {
+ auto It = lower_bound(SymbolsToIgnore, SymbolName);
+ return (It != SymbolsToIgnore.end()) && (*It == SymbolName);
+}
diff --git a/clang/lib/ExtractAPI/AvailabilityInfo.cpp b/clang/lib/ExtractAPI/AvailabilityInfo.cpp
new file mode 100644
index 000000000000..ada64cfb92e6
--- /dev/null
+++ b/clang/lib/ExtractAPI/AvailabilityInfo.cpp
@@ -0,0 +1,50 @@
+#include "clang/ExtractAPI/AvailabilityInfo.h"
+#include "clang/AST/Attr.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang;
+using namespace extractapi;
+
+AvailabilitySet::AvailabilitySet(const Decl *Decl) {
+ // Collect availability attributes from all redeclrations.
+ for (const auto *RD : Decl->redecls()) {
+ if (const auto *A = RD->getAttr<UnavailableAttr>()) {
+ if (!A->isImplicit()) {
+ this->Availabilities.clear();
+ UnconditionallyUnavailable = true;
+ }
+ }
+
+ if (const auto *A = RD->getAttr<DeprecatedAttr>()) {
+ if (!A->isImplicit()) {
+ this->Availabilities.clear();
+ UnconditionallyDeprecated = true;
+ }
+ }
+
+ for (const auto *Attr : RD->specific_attrs<AvailabilityAttr>()) {
+ StringRef Domain = Attr->getPlatform()->getName();
+ auto *Availability =
+ llvm::find_if(Availabilities, [Domain](const AvailabilityInfo &Info) {
+ return Domain.equals(Info.Domain);
+ });
+ if (Availability != Availabilities.end()) {
+ // Get the highest introduced version for all redeclarations.
+ if (Availability->Introduced < Attr->getIntroduced())
+ Availability->Introduced = Attr->getIntroduced();
+
+ // Get the lowest deprecated version for all redeclarations.
+ if (Availability->Deprecated > Attr->getDeprecated())
+ Availability->Deprecated = Attr->getDeprecated();
+
+ // Get the lowest obsoleted version for all redeclarations.
+ if (Availability->Obsoleted > Attr->getObsoleted())
+ Availability->Obsoleted = Attr->getObsoleted();
+ } else {
+ Availabilities.emplace_back(Domain, Attr->getIntroduced(),
+ Attr->getDeprecated(),
+ Attr->getObsoleted());
+ }
+ }
+ }
+}
diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 75d360a3ba16..12c91c582aa9 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -109,7 +109,7 @@ DeclarationFragmentsBuilder::getFragmentsForNNS(const NestedNameSpecifier *NNS,
SmallString<128> USR;
index::generateUSRForDecl(NS, USR);
Fragments.append(NS->getName(),
- DeclarationFragments::FragmentKind::Identifier, USR);
+ DeclarationFragments::FragmentKind::Identifier, USR, NS);
break;
}
@@ -118,7 +118,8 @@ DeclarationFragmentsBuilder::getFragmentsForNNS(const NestedNameSpecifier *NNS,
SmallString<128> USR;
index::generateUSRForDecl(Alias, USR);
Fragments.append(Alias->getName(),
- DeclarationFragments::FragmentKind::Identifier, USR);
+ DeclarationFragments::FragmentKind::Identifier, USR,
+ Alias);
break;
}
@@ -136,7 +137,7 @@ DeclarationFragmentsBuilder::getFragmentsForNNS(const NestedNameSpecifier *NNS,
Fragments.append("template", DeclarationFragments::FragmentKind::Keyword);
Fragments.appendSpace();
// Fallthrough after adding the keyword to handle the actual type.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case NestedNameSpecifier::TypeSpec: {
const Type *T = NNS->getAsType();
@@ -255,11 +256,11 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
// direct reference to the typedef instead of the wrapped type.
if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(T)) {
const TypedefNameDecl *Decl = TypedefTy->getDecl();
- std::string USR =
- TypedefUnderlyingTypeResolver(Context).getUSRForType(QualType(T, 0));
- return Fragments.append(Decl->getName(),
- DeclarationFragments::FragmentKind::TypeIdentifier,
- USR);
+ TypedefUnderlyingTypeResolver TypedefResolver(Context);
+ std::string USR = TypedefResolver.getUSRForType(QualType(T, 0));
+ return Fragments.append(
+ Decl->getName(), DeclarationFragments::FragmentKind::TypeIdentifier,
+ USR, TypedefResolver.getUnderlyingTypeDecl(QualType(T, 0)));
}
// If the base type is a TagType (struct/interface/union/class/enum), let's
@@ -273,7 +274,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
clang::index::generateUSRForDecl(Decl, TagUSR);
return Fragments.append(Decl->getName(),
DeclarationFragments::FragmentKind::TypeIdentifier,
- TagUSR);
+ TagUSR, Decl);
}
// If the base type is an ObjCInterfaceType, use the underlying
@@ -284,7 +285,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForType(
index::generateUSRForDecl(Decl, USR);
return Fragments.append(Decl->getName(),
DeclarationFragments::FragmentKind::TypeIdentifier,
- USR);
+ USR, Decl);
}
// Default fragment builder for other kinds of types (BuiltinType etc.)
@@ -530,13 +531,15 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory(
const ObjCCategoryDecl *Category) {
DeclarationFragments Fragments;
+ auto *Interface = Category->getClassInterface();
SmallString<128> InterfaceUSR;
- index::generateUSRForDecl(Category->getClassInterface(), InterfaceUSR);
+ index::generateUSRForDecl(Interface, InterfaceUSR);
Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword)
.appendSpace()
.append(Category->getClassInterface()->getName(),
- DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR)
+ DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR,
+ Interface)
.append(" (", DeclarationFragments::FragmentKind::Text)
.append(Category->getName(),
DeclarationFragments::FragmentKind::Identifier)
@@ -560,7 +563,8 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCInterface(
index::generateUSRForDecl(SuperClass, SuperUSR);
Fragments.append(" : ", DeclarationFragments::FragmentKind::Text)
.append(SuperClass->getName(),
- DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR);
+ DeclarationFragments::FragmentKind::TypeIdentifier, SuperUSR,
+ SuperClass);
}
return Fragments;
@@ -692,6 +696,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty(
return Fragments.appendSpace()
.append(getFragmentsForType(Property->getType(),
Property->getASTContext(), After))
+ .appendSpace()
.append(Property->getName(),
DeclarationFragments::FragmentKind::Identifier)
.append(std::move(After));
@@ -718,7 +723,8 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(
SmallString<128> USR;
index::generateUSRForDecl(*It, USR);
Fragments.append((*It)->getName(),
- DeclarationFragments::FragmentKind::TypeIdentifier, USR);
+ DeclarationFragments::FragmentKind::TypeIdentifier, USR,
+ *It);
}
Fragments.append(">", DeclarationFragments::FragmentKind::Text);
}
diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index 1a785182e363..644845efb819 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -7,25 +7,20 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// This file implements the ExtractAPIAction, and ASTVisitor/Consumer to
-/// collect API information.
+/// This file implements the ExtractAPIAction, and ASTConsumer to collect API
+/// information.
///
//===----------------------------------------------------------------------===//
-#include "TypedefUnderlyingTypeResolver.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ParentMapContext.h"
-#include "clang/AST/RawCommentList.h"
-#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/ExtractAPI/API.h"
-#include "clang/ExtractAPI/AvailabilityInfo.h"
-#include "clang/ExtractAPI/DeclarationFragments.h"
+#include "clang/ExtractAPI/APIIgnoresList.h"
+#include "clang/ExtractAPI/ExtractAPIVisitor.h"
#include "clang/ExtractAPI/FrontendActions.h"
#include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
#include "clang/Frontend/ASTConsumers.h"
@@ -38,12 +33,14 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
+#include <optional>
#include <utility>
using namespace clang;
@@ -51,16 +48,9 @@ using namespace extractapi;
namespace {
-StringRef getTypedefName(const TagDecl *Decl) {
- if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
- return TypedefDecl->getName();
-
- return {};
-}
-
-Optional<std::string> getRelativeIncludeName(const CompilerInstance &CI,
- StringRef File,
- bool *IsQuoted = nullptr) {
+std::optional<std::string> getRelativeIncludeName(const CompilerInstance &CI,
+ StringRef File,
+ bool *IsQuoted = nullptr) {
assert(CI.hasFileManager() &&
"CompilerInstance does not have a FileNamager!");
@@ -154,7 +144,7 @@ Optional<std::string> getRelativeIncludeName(const CompilerInstance &CI,
Rule.match(File, &Matches);
// Returned matches are always in stable order.
if (Matches.size() != 4)
- return None;
+ return std::nullopt;
return path::convert_to_slash(
(Matches[1].drop_front(Matches[1].rfind('/') + 1) + "/" +
@@ -169,11 +159,11 @@ Optional<std::string> getRelativeIncludeName(const CompilerInstance &CI,
}
// Couldn't determine a include name, use full path instead.
- return None;
+ return std::nullopt;
}
struct LocationFileChecker {
- bool isLocationInKnownFile(SourceLocation Loc) {
+ bool operator()(SourceLocation Loc) {
// If the loc refers to a macro expansion we need to first get the file
// location of the expansion.
auto &SM = CI.getSourceManager();
@@ -229,554 +219,6 @@ private:
llvm::DenseSet<const FileEntry *> ExternalFileEntries;
};
-/// The RecursiveASTVisitor to traverse symbol declarations and collect API
-/// information.
-class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
-public:
- ExtractAPIVisitor(ASTContext &Context, LocationFileChecker &LCF, APISet &API)
- : Context(Context), API(API), LCF(LCF) {}
-
- const APISet &getAPI() const { return API; }
-
- bool VisitVarDecl(const VarDecl *Decl) {
- // Skip function parameters.
- if (isa<ParmVarDecl>(Decl))
- return true;
-
- // Skip non-global variables in records (struct/union/class).
- if (Decl->getDeclContext()->isRecord())
- return true;
-
- // Skip local variables inside function or method.
- if (!Decl->isDefinedOutsideFunctionOrMethod())
- return true;
-
- // If this is a template but not specialization or instantiation, skip.
- if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
- Decl->getTemplateSpecializationKind() == TSK_Undeclared)
- return true;
-
- if (!LCF.isLocationInKnownFile(Decl->getLocation()))
- return true;
-
- // Collect symbol information.
- StringRef Name = Decl->getName();
- StringRef USR = API.recordUSR(Decl);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Decl->getLocation());
- AvailabilityInfo Availability = getAvailability(Decl);
- LinkageInfo Linkage = Decl->getLinkageAndVisibility();
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the variable.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Decl);
-
- // Add the global variable record to the API set.
- API.addGlobalVar(Name, USR, Loc, Availability, Linkage, Comment,
- Declaration, SubHeading);
- return true;
- }
-
- bool VisitFunctionDecl(const FunctionDecl *Decl) {
- if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
- // Skip member function in class templates.
- if (Method->getParent()->getDescribedClassTemplate() != nullptr)
- return true;
-
- // Skip methods in records.
- for (auto P : Context.getParents(*Method)) {
- if (P.get<CXXRecordDecl>())
- return true;
- }
-
- // Skip ConstructorDecl and DestructorDecl.
- if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
- return true;
- }
-
- // Skip templated functions.
- switch (Decl->getTemplatedKind()) {
- case FunctionDecl::TK_NonTemplate:
- case FunctionDecl::TK_DependentNonTemplate:
- break;
- case FunctionDecl::TK_MemberSpecialization:
- case FunctionDecl::TK_FunctionTemplateSpecialization:
- if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
- if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
- return true;
- }
- break;
- case FunctionDecl::TK_FunctionTemplate:
- case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
- return true;
- }
-
- if (!LCF.isLocationInKnownFile(Decl->getLocation()))
- return true;
-
- // Collect symbol information.
- StringRef Name = Decl->getName();
- StringRef USR = API.recordUSR(Decl);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Decl->getLocation());
- AvailabilityInfo Availability = getAvailability(Decl);
- LinkageInfo Linkage = Decl->getLinkageAndVisibility();
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments, sub-heading, and signature of the function.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Decl);
- FunctionSignature Signature =
- DeclarationFragmentsBuilder::getFunctionSignature(Decl);
-
- // Add the function record to the API set.
- API.addGlobalFunction(Name, USR, Loc, Availability, Linkage, Comment,
- Declaration, SubHeading, Signature);
- return true;
- }
-
- bool VisitEnumDecl(const EnumDecl *Decl) {
- if (!Decl->isComplete())
- return true;
-
- // Skip forward declaration.
- if (!Decl->isThisDeclarationADefinition())
- return true;
-
- if (!LCF.isLocationInKnownFile(Decl->getLocation()))
- return true;
-
- // Collect symbol information.
- std::string NameString = Decl->getQualifiedNameAsString();
- StringRef Name(NameString);
- if (Name.empty())
- Name = getTypedefName(Decl);
-
- StringRef USR = API.recordUSR(Decl);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Decl->getLocation());
- AvailabilityInfo Availability = getAvailability(Decl);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the enum.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Decl);
-
- EnumRecord *EnumRecord =
- API.addEnum(API.copyString(Name), USR, Loc, Availability, Comment,
- Declaration, SubHeading);
-
- // Now collect information about the enumerators in this enum.
- recordEnumConstants(EnumRecord, Decl->enumerators());
-
- return true;
- }
-
- bool VisitRecordDecl(const RecordDecl *Decl) {
- if (!Decl->isCompleteDefinition())
- return true;
-
- // Skip C++ structs/classes/unions
- // TODO: support C++ records
- if (isa<CXXRecordDecl>(Decl))
- return true;
-
- if (!LCF.isLocationInKnownFile(Decl->getLocation()))
- return true;
-
- // Collect symbol information.
- StringRef Name = Decl->getName();
- if (Name.empty())
- Name = getTypedefName(Decl);
- StringRef USR = API.recordUSR(Decl);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Decl->getLocation());
- AvailabilityInfo Availability = getAvailability(Decl);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the struct.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Decl);
-
- StructRecord *StructRecord = API.addStruct(
- Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
-
- // Now collect information about the fields in this struct.
- recordStructFields(StructRecord, Decl->fields());
-
- return true;
- }
-
- bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
- // Skip forward declaration for classes (@class)
- if (!Decl->isThisDeclarationADefinition())
- return true;
-
- if (!LCF.isLocationInKnownFile(Decl->getLocation()))
- return true;
-
- // Collect symbol information.
- StringRef Name = Decl->getName();
- StringRef USR = API.recordUSR(Decl);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Decl->getLocation());
- AvailabilityInfo Availability = getAvailability(Decl);
- LinkageInfo Linkage = Decl->getLinkageAndVisibility();
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the interface.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Decl);
-
- // Collect super class information.
- SymbolReference SuperClass;
- if (const auto *SuperClassDecl = Decl->getSuperClass()) {
- SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
- SuperClass.USR = API.recordUSR(SuperClassDecl);
- }
-
- ObjCInterfaceRecord *ObjCInterfaceRecord =
- API.addObjCInterface(Name, USR, Loc, Availability, Linkage, Comment,
- Declaration, SubHeading, SuperClass);
-
- // Record all methods (selectors). This doesn't include automatically
- // synthesized property methods.
- recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
- recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
- recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
- recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
-
- return true;
- }
-
- bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
- // Skip forward declaration for protocols (@protocol).
- if (!Decl->isThisDeclarationADefinition())
- return true;
-
- if (!LCF.isLocationInKnownFile(Decl->getLocation()))
- return true;
-
- // Collect symbol information.
- StringRef Name = Decl->getName();
- StringRef USR = API.recordUSR(Decl);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Decl->getLocation());
- AvailabilityInfo Availability = getAvailability(Decl);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the protocol.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Decl);
-
- ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
- Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
-
- recordObjCMethods(ObjCProtocolRecord, Decl->methods());
- recordObjCProperties(ObjCProtocolRecord, Decl->properties());
- recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
-
- return true;
- }
-
- bool VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
- // Skip ObjC Type Parameter for now.
- if (isa<ObjCTypeParamDecl>(Decl))
- return true;
-
- if (!Decl->isDefinedOutsideFunctionOrMethod())
- return true;
-
- if (!LCF.isLocationInKnownFile(Decl->getLocation()))
- return true;
-
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Decl->getLocation());
- StringRef Name = Decl->getName();
- AvailabilityInfo Availability = getAvailability(Decl);
- StringRef USR = API.recordUSR(Decl);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- QualType Type = Decl->getUnderlyingType();
- SymbolReference SymRef =
- TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
- API);
-
- API.addTypedef(Name, USR, Loc, Availability, Comment,
- DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
- DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef);
-
- return true;
- }
-
- bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
- // Collect symbol information.
- StringRef Name = Decl->getName();
- StringRef USR = API.recordUSR(Decl);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Decl->getLocation());
- AvailabilityInfo Availability = getAvailability(Decl);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
- // Build declaration fragments and sub-heading for the category.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Decl);
-
- const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
- SymbolReference Interface(InterfaceDecl->getName(),
- API.recordUSR(InterfaceDecl));
-
- ObjCCategoryRecord *ObjCCategoryRecord =
- API.addObjCCategory(Name, USR, Loc, Availability, Comment, Declaration,
- SubHeading, Interface);
-
- recordObjCMethods(ObjCCategoryRecord, Decl->methods());
- recordObjCProperties(ObjCCategoryRecord, Decl->properties());
- recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
- recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
-
- return true;
- }
-
-private:
- /// Get availability information of the declaration \p D.
- AvailabilityInfo getAvailability(const Decl *D) const {
- StringRef PlatformName = Context.getTargetInfo().getPlatformName();
-
- AvailabilityInfo Availability;
- // Collect availability attributes from all redeclarations.
- for (const auto *RD : D->redecls()) {
- for (const auto *A : RD->specific_attrs<AvailabilityAttr>()) {
- if (A->getPlatform()->getName() != PlatformName)
- continue;
- Availability = AvailabilityInfo(A->getIntroduced(), A->getDeprecated(),
- A->getObsoleted(), A->getUnavailable(),
- /* UnconditionallyDeprecated */ false,
- /* UnconditionallyUnavailable */ false);
- break;
- }
-
- if (const auto *A = RD->getAttr<UnavailableAttr>())
- if (!A->isImplicit()) {
- Availability.Unavailable = true;
- Availability.UnconditionallyUnavailable = true;
- }
-
- if (const auto *A = RD->getAttr<DeprecatedAttr>())
- if (!A->isImplicit())
- Availability.UnconditionallyDeprecated = true;
- }
-
- return Availability;
- }
-
- /// Collect API information for the enum constants and associate with the
- /// parent enum.
- void recordEnumConstants(EnumRecord *EnumRecord,
- const EnumDecl::enumerator_range Constants) {
- for (const auto *Constant : Constants) {
- // Collect symbol information.
- StringRef Name = Constant->getName();
- StringRef USR = API.recordUSR(Constant);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Constant->getLocation());
- AvailabilityInfo Availability = getAvailability(Constant);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the enum constant.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Constant);
-
- API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
- Declaration, SubHeading);
- }
- }
-
- /// Collect API information for the struct fields and associate with the
- /// parent struct.
- void recordStructFields(StructRecord *StructRecord,
- const RecordDecl::field_range Fields) {
- for (const auto *Field : Fields) {
- // Collect symbol information.
- StringRef Name = Field->getName();
- StringRef USR = API.recordUSR(Field);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Field->getLocation());
- AvailabilityInfo Availability = getAvailability(Field);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the struct field.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForField(Field);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Field);
-
- API.addStructField(StructRecord, Name, USR, Loc, Availability, Comment,
- Declaration, SubHeading);
- }
- }
-
- /// Collect API information for the Objective-C methods and associate with the
- /// parent container.
- void recordObjCMethods(ObjCContainerRecord *Container,
- const ObjCContainerDecl::method_range Methods) {
- for (const auto *Method : Methods) {
- // Don't record selectors for properties.
- if (Method->isPropertyAccessor())
- continue;
-
- StringRef Name = API.copyString(Method->getSelector().getAsString());
- StringRef USR = API.recordUSR(Method);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Method->getLocation());
- AvailabilityInfo Availability = getAvailability(Method);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments, sub-heading, and signature for the method.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Method);
- FunctionSignature Signature =
- DeclarationFragmentsBuilder::getFunctionSignature(Method);
-
- API.addObjCMethod(Container, Name, USR, Loc, Availability, Comment,
- Declaration, SubHeading, Signature,
- Method->isInstanceMethod());
- }
- }
-
- void recordObjCProperties(ObjCContainerRecord *Container,
- const ObjCContainerDecl::prop_range Properties) {
- for (const auto *Property : Properties) {
- StringRef Name = Property->getName();
- StringRef USR = API.recordUSR(Property);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Property->getLocation());
- AvailabilityInfo Availability = getAvailability(Property);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the property.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Property);
-
- StringRef GetterName =
- API.copyString(Property->getGetterName().getAsString());
- StringRef SetterName =
- API.copyString(Property->getSetterName().getAsString());
-
- // Get the attributes for property.
- unsigned Attributes = ObjCPropertyRecord::NoAttr;
- if (Property->getPropertyAttributes() &
- ObjCPropertyAttribute::kind_readonly)
- Attributes |= ObjCPropertyRecord::ReadOnly;
- if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class)
- Attributes |= ObjCPropertyRecord::Class;
-
- API.addObjCProperty(
- Container, Name, USR, Loc, Availability, Comment, Declaration,
- SubHeading,
- static_cast<ObjCPropertyRecord::AttributeKind>(Attributes),
- GetterName, SetterName, Property->isOptional());
- }
- }
-
- void recordObjCInstanceVariables(
- ObjCContainerRecord *Container,
- const llvm::iterator_range<
- DeclContext::specific_decl_iterator<ObjCIvarDecl>>
- Ivars) {
- for (const auto *Ivar : Ivars) {
- StringRef Name = Ivar->getName();
- StringRef USR = API.recordUSR(Ivar);
- PresumedLoc Loc =
- Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
- AvailabilityInfo Availability = getAvailability(Ivar);
- DocComment Comment;
- if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
- Comment = RawComment->getFormattedLines(Context.getSourceManager(),
- Context.getDiagnostics());
-
- // Build declaration fragments and sub-heading for the instance variable.
- DeclarationFragments Declaration =
- DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
- DeclarationFragments SubHeading =
- DeclarationFragmentsBuilder::getSubHeading(Ivar);
-
- ObjCInstanceVariableRecord::AccessControl Access =
- Ivar->getCanonicalAccessControl();
-
- API.addObjCInstanceVariable(Container, Name, USR, Loc, Availability,
- Comment, Declaration, SubHeading, Access);
- }
- }
-
- void recordObjCProtocols(ObjCContainerRecord *Container,
- ObjCInterfaceDecl::protocol_range Protocols) {
- for (const auto *Protocol : Protocols)
- Container->Protocols.emplace_back(Protocol->getName(),
- API.recordUSR(Protocol));
- }
-
- ASTContext &Context;
- APISet &API;
- LocationFileChecker &LCF;
-};
-
class ExtractAPIConsumer : public ASTConsumer {
public:
ExtractAPIConsumer(ASTContext &Context,
@@ -837,7 +279,7 @@ public:
if (PM.MD->getMacroInfo()->isUsedForHeaderGuard())
continue;
- if (!LCF.isLocationInKnownFile(PM.MacroNameToken.getLocation()))
+ if (!LCF(PM.MacroNameToken.getLocation()))
continue;
StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName();
@@ -848,7 +290,8 @@ public:
API.addMacroDefinition(
Name, USR, Loc,
DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD),
- DeclarationFragmentsBuilder::getSubHeadingForMacro(Name));
+ DeclarationFragmentsBuilder::getSubHeadingForMacro(Name),
+ SM.isInSystemHeader(PM.MacroNameToken.getLocation()));
}
PendingMacros.clear();
@@ -878,19 +321,36 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (!OS)
return nullptr;
- ProductName = CI.getFrontendOpts().ProductName;
+ auto ProductName = CI.getFrontendOpts().ProductName;
// Now that we have enough information about the language options and the
// target triple, let's create the APISet before anyone uses it.
API = std::make_unique<APISet>(
CI.getTarget().getTriple(),
- CI.getFrontendOpts().Inputs.back().getKind().getLanguage());
+ CI.getFrontendOpts().Inputs.back().getKind().getLanguage(), ProductName);
auto LCF = std::make_unique<LocationFileChecker>(CI, KnownInputFiles);
CI.getPreprocessor().addPPCallbacks(std::make_unique<MacroCallback>(
CI.getSourceManager(), *LCF, *API, CI.getPreprocessor()));
+ // Do not include location in anonymous decls.
+ PrintingPolicy Policy = CI.getASTContext().getPrintingPolicy();
+ Policy.AnonymousTagLocations = false;
+ CI.getASTContext().setPrintingPolicy(Policy);
+
+ if (!CI.getFrontendOpts().ExtractAPIIgnoresFile.empty()) {
+ llvm::handleAllErrors(
+ APIIgnoresList::create(CI.getFrontendOpts().ExtractAPIIgnoresFile,
+ CI.getFileManager())
+ .moveInto(IgnoresList),
+ [&CI](const IgnoresFileNotFound &Err) {
+ CI.getDiagnostics().Report(
+ diag::err_extract_api_ignores_file_not_found)
+ << Err.Path;
+ });
+ }
+
return std::make_unique<ExtractAPIConsumer>(CI.getASTContext(),
std::move(LCF), *API);
}
@@ -959,7 +419,7 @@ void ExtractAPIAction::EndSourceFileAction() {
// Setup a SymbolGraphSerializer to write out collected API information in
// the Symbol Graph format.
// FIXME: Make the kind of APISerializer configurable.
- SymbolGraphSerializer SGSerializer(*API, ProductName);
+ SymbolGraphSerializer SGSerializer(*API, IgnoresList);
SGSerializer.serialize(*OS);
OS.reset();
}
diff --git a/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp b/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp
new file mode 100644
index 000000000000..24260cf89383
--- /dev/null
+++ b/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp
@@ -0,0 +1,560 @@
+//===- ExtractAPI/ExtractAPIVisitor.cpp -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the ExtractAPIVisitor an ASTVisitor to collect API
+/// information.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ExtractAPI/ExtractAPIVisitor.h"
+
+#include "TypedefUnderlyingTypeResolver.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ParentMapContext.h"
+#include "clang/AST/RawCommentList.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/AvailabilityInfo.h"
+#include "clang/ExtractAPI/DeclarationFragments.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace extractapi;
+
+namespace {
+
+StringRef getTypedefName(const TagDecl *Decl) {
+ if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
+ return TypedefDecl->getName();
+
+ return {};
+}
+
+template <class DeclTy>
+bool isInSystemHeader(const ASTContext &Context, const DeclTy *D) {
+ return Context.getSourceManager().isInSystemHeader(D->getLocation());
+}
+
+} // namespace
+
+bool ExtractAPIVisitor::VisitVarDecl(const VarDecl *Decl) {
+ // skip function parameters.
+ if (isa<ParmVarDecl>(Decl))
+ return true;
+
+ // Skip non-global variables in records (struct/union/class).
+ if (Decl->getDeclContext()->isRecord())
+ return true;
+
+ // Skip local variables inside function or method.
+ if (!Decl->isDefinedOutsideFunctionOrMethod())
+ return true;
+
+ // If this is a template but not specialization or instantiation, skip.
+ if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
+ Decl->getTemplateSpecializationKind() == TSK_Undeclared)
+ return true;
+
+ if (!LocationChecker(Decl->getLocation()))
+ return true;
+
+ // Collect symbol information.
+ StringRef Name = Decl->getName();
+ StringRef USR = API.recordUSR(Decl);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ LinkageInfo Linkage = Decl->getLinkageAndVisibility();
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the variable.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+ // Add the global variable record to the API set.
+ API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
+ Declaration, SubHeading, isInSystemHeader(Context, Decl));
+ return true;
+}
+
+bool ExtractAPIVisitor::VisitFunctionDecl(const FunctionDecl *Decl) {
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
+ // Skip member function in class templates.
+ if (Method->getParent()->getDescribedClassTemplate() != nullptr)
+ return true;
+
+ // Skip methods in records.
+ for (auto P : Context.getParents(*Method)) {
+ if (P.get<CXXRecordDecl>())
+ return true;
+ }
+
+ // Skip ConstructorDecl and DestructorDecl.
+ if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
+ return true;
+ }
+
+ // Skip templated functions.
+ switch (Decl->getTemplatedKind()) {
+ case FunctionDecl::TK_NonTemplate:
+ case FunctionDecl::TK_DependentNonTemplate:
+ break;
+ case FunctionDecl::TK_MemberSpecialization:
+ case FunctionDecl::TK_FunctionTemplateSpecialization:
+ if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
+ if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
+ return true;
+ }
+ break;
+ case FunctionDecl::TK_FunctionTemplate:
+ case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
+ return true;
+ }
+
+ if (!LocationChecker(Decl->getLocation()))
+ return true;
+
+ // Collect symbol information.
+ StringRef Name = Decl->getName();
+ StringRef USR = API.recordUSR(Decl);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ LinkageInfo Linkage = Decl->getLinkageAndVisibility();
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments, sub-heading, and signature of the function.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+ FunctionSignature Signature =
+ DeclarationFragmentsBuilder::getFunctionSignature(Decl);
+
+ // Add the function record to the API set.
+ API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
+ Declaration, SubHeading, Signature,
+ isInSystemHeader(Context, Decl));
+ return true;
+}
+
+bool ExtractAPIVisitor::VisitEnumDecl(const EnumDecl *Decl) {
+ if (!Decl->isComplete())
+ return true;
+
+ // Skip forward declaration.
+ if (!Decl->isThisDeclarationADefinition())
+ return true;
+
+ if (!LocationChecker(Decl->getLocation()))
+ return true;
+
+ SmallString<128> QualifiedNameBuffer;
+ // Collect symbol information.
+ StringRef Name = Decl->getName();
+ if (Name.empty())
+ Name = getTypedefName(Decl);
+ if (Name.empty()) {
+ llvm::raw_svector_ostream OS(QualifiedNameBuffer);
+ Decl->printQualifiedName(OS);
+ Name = QualifiedNameBuffer.str();
+ }
+
+ StringRef USR = API.recordUSR(Decl);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the enum.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+ EnumRecord *EnumRecord = API.addEnum(
+ API.copyString(Name), USR, Loc, AvailabilitySet(Decl), Comment,
+ Declaration, SubHeading, isInSystemHeader(Context, Decl));
+
+ // Now collect information about the enumerators in this enum.
+ recordEnumConstants(EnumRecord, Decl->enumerators());
+
+ return true;
+}
+
+bool ExtractAPIVisitor::VisitRecordDecl(const RecordDecl *Decl) {
+ if (!Decl->isCompleteDefinition())
+ return true;
+
+ // Skip C++ structs/classes/unions
+ // TODO: support C++ records
+ if (isa<CXXRecordDecl>(Decl))
+ return true;
+
+ if (!LocationChecker(Decl->getLocation()))
+ return true;
+
+ // Collect symbol information.
+ StringRef Name = Decl->getName();
+ if (Name.empty())
+ Name = getTypedefName(Decl);
+ if (Name.empty())
+ return true;
+
+ StringRef USR = API.recordUSR(Decl);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the struct.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+ StructRecord *StructRecord =
+ API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
+ SubHeading, isInSystemHeader(Context, Decl));
+
+ // Now collect information about the fields in this struct.
+ recordStructFields(StructRecord, Decl->fields());
+
+ return true;
+}
+
+bool ExtractAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
+ // Skip forward declaration for classes (@class)
+ if (!Decl->isThisDeclarationADefinition())
+ return true;
+
+ if (!LocationChecker(Decl->getLocation()))
+ return true;
+
+ // Collect symbol information.
+ StringRef Name = Decl->getName();
+ StringRef USR = API.recordUSR(Decl);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ LinkageInfo Linkage = Decl->getLinkageAndVisibility();
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the interface.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+ // Collect super class information.
+ SymbolReference SuperClass;
+ if (const auto *SuperClassDecl = Decl->getSuperClass()) {
+ SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
+ SuperClass.USR = API.recordUSR(SuperClassDecl);
+ }
+
+ ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface(
+ Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration,
+ SubHeading, SuperClass, isInSystemHeader(Context, Decl));
+
+ // Record all methods (selectors). This doesn't include automatically
+ // synthesized property methods.
+ recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
+ recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
+ recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
+ recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
+
+ return true;
+}
+
+bool ExtractAPIVisitor::VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
+ // Skip forward declaration for protocols (@protocol).
+ if (!Decl->isThisDeclarationADefinition())
+ return true;
+
+ if (!LocationChecker(Decl->getLocation()))
+ return true;
+
+ // Collect symbol information.
+ StringRef Name = Decl->getName();
+ StringRef USR = API.recordUSR(Decl);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the protocol.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+ ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
+ Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
+ isInSystemHeader(Context, Decl));
+
+ recordObjCMethods(ObjCProtocolRecord, Decl->methods());
+ recordObjCProperties(ObjCProtocolRecord, Decl->properties());
+ recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
+
+ return true;
+}
+
+bool ExtractAPIVisitor::VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
+ // Skip ObjC Type Parameter for now.
+ if (isa<ObjCTypeParamDecl>(Decl))
+ return true;
+
+ if (!Decl->isDefinedOutsideFunctionOrMethod())
+ return true;
+
+ if (!LocationChecker(Decl->getLocation()))
+ return true;
+
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ StringRef Name = Decl->getName();
+ StringRef USR = API.recordUSR(Decl);
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ QualType Type = Decl->getUnderlyingType();
+ SymbolReference SymRef =
+ TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
+ API);
+
+ API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment,
+ DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
+ DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef,
+ isInSystemHeader(Context, Decl));
+
+ return true;
+}
+
+bool ExtractAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
+ // Collect symbol information.
+ StringRef Name = Decl->getName();
+ StringRef USR = API.recordUSR(Decl);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+ // Build declaration fragments and sub-heading for the category.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+ const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
+ SymbolReference Interface(InterfaceDecl->getName(),
+ API.recordUSR(InterfaceDecl));
+
+ ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory(
+ Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
+ Interface, isInSystemHeader(Context, Decl));
+
+ recordObjCMethods(ObjCCategoryRecord, Decl->methods());
+ recordObjCProperties(ObjCCategoryRecord, Decl->properties());
+ recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
+ recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
+
+ return true;
+}
+
+/// Collect API information for the enum constants and associate with the
+/// parent enum.
+void ExtractAPIVisitor::recordEnumConstants(
+ EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) {
+ for (const auto *Constant : Constants) {
+ // Collect symbol information.
+ StringRef Name = Constant->getName();
+ StringRef USR = API.recordUSR(Constant);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Constant->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the enum constant.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Constant);
+
+ API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant),
+ Comment, Declaration, SubHeading,
+ isInSystemHeader(Context, Constant));
+ }
+}
+
+/// Collect API information for the struct fields and associate with the
+/// parent struct.
+void ExtractAPIVisitor::recordStructFields(
+ StructRecord *StructRecord, const RecordDecl::field_range Fields) {
+ for (const auto *Field : Fields) {
+ // Collect symbol information.
+ StringRef Name = Field->getName();
+ StringRef USR = API.recordUSR(Field);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Field->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Field))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the struct field.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForField(Field);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Field);
+
+ API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
+ Comment, Declaration, SubHeading,
+ isInSystemHeader(Context, Field));
+ }
+}
+
+/// Collect API information for the Objective-C methods and associate with the
+/// parent container.
+void ExtractAPIVisitor::recordObjCMethods(
+ ObjCContainerRecord *Container,
+ const ObjCContainerDecl::method_range Methods) {
+ for (const auto *Method : Methods) {
+ // Don't record selectors for properties.
+ if (Method->isPropertyAccessor())
+ continue;
+
+ StringRef Name = API.copyString(Method->getSelector().getAsString());
+ StringRef USR = API.recordUSR(Method);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Method->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments, sub-heading, and signature for the method.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Method);
+ FunctionSignature Signature =
+ DeclarationFragmentsBuilder::getFunctionSignature(Method);
+
+ API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method),
+ Comment, Declaration, SubHeading, Signature,
+ Method->isInstanceMethod(),
+ isInSystemHeader(Context, Method));
+ }
+}
+
+void ExtractAPIVisitor::recordObjCProperties(
+ ObjCContainerRecord *Container,
+ const ObjCContainerDecl::prop_range Properties) {
+ for (const auto *Property : Properties) {
+ StringRef Name = Property->getName();
+ StringRef USR = API.recordUSR(Property);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Property->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the property.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Property);
+
+ StringRef GetterName =
+ API.copyString(Property->getGetterName().getAsString());
+ StringRef SetterName =
+ API.copyString(Property->getSetterName().getAsString());
+
+ // Get the attributes for property.
+ unsigned Attributes = ObjCPropertyRecord::NoAttr;
+ if (Property->getPropertyAttributes() &
+ ObjCPropertyAttribute::kind_readonly)
+ Attributes |= ObjCPropertyRecord::ReadOnly;
+
+ API.addObjCProperty(
+ Container, Name, USR, Loc, AvailabilitySet(Property), Comment,
+ Declaration, SubHeading,
+ static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), GetterName,
+ SetterName, Property->isOptional(),
+ !(Property->getPropertyAttributes() &
+ ObjCPropertyAttribute::kind_class),
+ isInSystemHeader(Context, Property));
+ }
+}
+
+void ExtractAPIVisitor::recordObjCInstanceVariables(
+ ObjCContainerRecord *Container,
+ const llvm::iterator_range<
+ DeclContext::specific_decl_iterator<ObjCIvarDecl>>
+ Ivars) {
+ for (const auto *Ivar : Ivars) {
+ StringRef Name = Ivar->getName();
+ StringRef USR = API.recordUSR(Ivar);
+ PresumedLoc Loc =
+ Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
+ DocComment Comment;
+ if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
+ Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+ Context.getDiagnostics());
+
+ // Build declaration fragments and sub-heading for the instance variable.
+ DeclarationFragments Declaration =
+ DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
+ DeclarationFragments SubHeading =
+ DeclarationFragmentsBuilder::getSubHeading(Ivar);
+
+ ObjCInstanceVariableRecord::AccessControl Access =
+ Ivar->getCanonicalAccessControl();
+
+ API.addObjCInstanceVariable(
+ Container, Name, USR, Loc, AvailabilitySet(Ivar), Comment, Declaration,
+ SubHeading, Access, isInSystemHeader(Context, Ivar));
+ }
+}
+
+void ExtractAPIVisitor::recordObjCProtocols(
+ ObjCContainerRecord *Container,
+ ObjCInterfaceDecl::protocol_range Protocols) {
+ for (const auto *Protocol : Protocols)
+ Container->Protocols.emplace_back(Protocol->getName(),
+ API.recordUSR(Protocol));
+}
diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index 709b781968bf..01e9b37d2680 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -12,12 +12,21 @@
//===----------------------------------------------------------------------===//
#include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Version.h"
#include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/APIIgnoresList.h"
#include "clang/ExtractAPI/DeclarationFragments.h"
+#include "clang/ExtractAPI/Serialization/SerializerBase.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/VersionTuple.h"
+#include <optional>
#include <type_traits>
using namespace clang;
@@ -29,16 +38,16 @@ namespace {
/// Helper function to inject a JSON object \p Obj into another object \p Paren
/// at position \p Key.
-void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) {
+void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
if (Obj)
- Paren[Key] = std::move(Obj.value());
+ Paren[Key] = std::move(*Obj);
}
/// Helper function to inject a JSON array \p Array into object \p Paren at
/// position \p Key.
-void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) {
+void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
if (Array)
- Paren[Key] = std::move(Array.value());
+ Paren[Key] = std::move(*Array);
}
/// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
@@ -55,11 +64,11 @@ void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) {
/// }
/// \endcode
///
-/// \returns \c None if the version \p V is empty, or an \c Object containing
-/// the semantic version representation of \p V.
-Optional<Object> serializeSemanticVersion(const VersionTuple &V) {
+/// \returns \c std::nullopt if the version \p V is empty, or an \c Object
+/// containing the semantic version representation of \p V.
+std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
if (V.empty())
- return None;
+ return std::nullopt;
Object Version;
Version["major"] = V.getMajor();
@@ -135,30 +144,43 @@ Object serializeSourceRange(const PresumedLoc &BeginLoc,
/// Serialize the availability attributes of a symbol.
///
/// Availability information contains the introduced, deprecated, and obsoleted
-/// versions of the symbol as semantic versions, if not default.
-/// Availability information also contains flags to indicate if the symbol is
-/// unconditionally unavailable or deprecated,
-/// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
+/// versions of the symbol for a given domain (roughly corresponds to a
+/// platform) as semantic versions, if not default. Availability information
+/// also contains flags to indicate if the symbol is unconditionally unavailable
+/// or deprecated, i.e. \c __attribute__((unavailable)) and \c
+/// __attribute__((deprecated)).
///
-/// \returns \c None if the symbol has default availability attributes, or
-/// an \c Object containing the formatted availability information.
-Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) {
- if (Avail.isDefault())
- return None;
-
- Object Availbility;
- serializeObject(Availbility, "introducedVersion",
- serializeSemanticVersion(Avail.Introduced));
- serializeObject(Availbility, "deprecatedVersion",
- serializeSemanticVersion(Avail.Deprecated));
- serializeObject(Availbility, "obsoletedVersion",
- serializeSemanticVersion(Avail.Obsoleted));
- if (Avail.isUnavailable())
- Availbility["isUnconditionallyUnavailable"] = true;
- if (Avail.isUnconditionallyDeprecated())
- Availbility["isUnconditionallyDeprecated"] = true;
-
- return Availbility;
+/// \returns \c std::nullopt if the symbol has default availability attributes,
+/// or an \c Array containing the formatted availability information.
+std::optional<Array>
+serializeAvailability(const AvailabilitySet &Availabilities) {
+ if (Availabilities.isDefault())
+ return std::nullopt;
+
+ Array AvailabilityArray;
+
+ if (Availabilities.isUnconditionallyDeprecated()) {
+ Object UnconditionallyDeprecated;
+ UnconditionallyDeprecated["domain"] = "*";
+ UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
+ AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
+ }
+
+ // Note unconditionally unavailable records are skipped.
+
+ for (const auto &AvailInfo : Availabilities) {
+ Object Availability;
+ Availability["domain"] = AvailInfo.Domain;
+ serializeObject(Availability, "introducedVersion",
+ serializeSemanticVersion(AvailInfo.Introduced));
+ serializeObject(Availability, "deprecatedVersion",
+ serializeSemanticVersion(AvailInfo.Deprecated));
+ serializeObject(Availability, "obsoletedVersion",
+ serializeSemanticVersion(AvailInfo.Obsoleted));
+ AvailabilityArray.emplace_back(std::move(Availability));
+ }
+
+ return AvailabilityArray;
}
/// Get the language name string for interface language references.
@@ -215,11 +237,11 @@ Object serializeIdentifier(const APIRecord &Record, Language Lang) {
/// ^~~~~~~~~~~~~~~~~~~~~~~' Second line.
/// \endcode
///
-/// \returns \c None if \p Comment is empty, or an \c Object containing the
-/// formatted lines.
-Optional<Object> serializeDocComment(const DocComment &Comment) {
+/// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
+/// the formatted lines.
+std::optional<Object> serializeDocComment(const DocComment &Comment) {
if (Comment.empty())
- return None;
+ return std::nullopt;
Object DocComment;
Array LinesArray;
@@ -267,11 +289,12 @@ Optional<Object> serializeDocComment(const DocComment &Comment) {
/// ]
/// \endcode
///
-/// \returns \c None if \p DF is empty, or an \c Array containing the formatted
-/// declaration fragments array.
-Optional<Array> serializeDeclarationFragments(const DeclarationFragments &DF) {
+/// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
+/// formatted declaration fragments array.
+std::optional<Array>
+serializeDeclarationFragments(const DeclarationFragments &DF) {
if (DF.getFragments().empty())
- return None;
+ return std::nullopt;
Array Fragments;
for (const auto &F : DF.getFragments()) {
@@ -310,18 +333,16 @@ Object serializeNames(const APIRecord &Record) {
return Names;
}
-/// Serialize the symbol kind information.
-///
-/// The Symbol Graph symbol kind property contains a shorthand \c identifier
-/// which is prefixed by the source language name, useful for tooling to parse
-/// the kind, and a \c displayName for rendering human-readable names.
-Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
+Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
return (getLanguageName(Lang) + "." + S).str();
};
Object Kind;
- switch (Record.getKind()) {
+ switch (RK) {
+ case APIRecord::RK_Unknown:
+ llvm_unreachable("Records should have an explicit kind");
+ break;
case APIRecord::RK_GlobalFunction:
Kind["identifier"] = AddLangPrefix("func");
Kind["displayName"] = "Function";
@@ -350,19 +371,22 @@ Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
Kind["identifier"] = AddLangPrefix("ivar");
Kind["displayName"] = "Instance Variable";
break;
- case APIRecord::RK_ObjCMethod:
- if (dyn_cast<ObjCMethodRecord>(&Record)->IsInstanceMethod) {
- Kind["identifier"] = AddLangPrefix("method");
- Kind["displayName"] = "Instance Method";
- } else {
- Kind["identifier"] = AddLangPrefix("type.method");
- Kind["displayName"] = "Type Method";
- }
+ case APIRecord::RK_ObjCInstanceMethod:
+ Kind["identifier"] = AddLangPrefix("method");
+ Kind["displayName"] = "Instance Method";
break;
- case APIRecord::RK_ObjCProperty:
+ case APIRecord::RK_ObjCClassMethod:
+ Kind["identifier"] = AddLangPrefix("type.method");
+ Kind["displayName"] = "Type Method";
+ break;
+ case APIRecord::RK_ObjCInstanceProperty:
Kind["identifier"] = AddLangPrefix("property");
Kind["displayName"] = "Instance Property";
break;
+ case APIRecord::RK_ObjCClassProperty:
+ Kind["identifier"] = AddLangPrefix("type.property");
+ Kind["displayName"] = "Type Property";
+ break;
case APIRecord::RK_ObjCInterface:
Kind["identifier"] = AddLangPrefix("class");
Kind["displayName"] = "Class";
@@ -389,12 +413,21 @@ Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
return Kind;
}
+/// Serialize the symbol kind information.
+///
+/// The Symbol Graph symbol kind property contains a shorthand \c identifier
+/// which is prefixed by the source language name, useful for tooling to parse
+/// the kind, and a \c displayName for rendering human-readable names.
+Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
+ return serializeSymbolKind(Record.getKind(), Lang);
+}
+
template <typename RecordTy>
-Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record,
- std::true_type) {
+std::optional<Object>
+serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
const auto &FS = Record.Signature;
if (FS.empty())
- return None;
+ return std::nullopt;
Object Signature;
serializeArray(Signature, "returns",
@@ -416,9 +449,9 @@ Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record,
}
template <typename RecordTy>
-Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record,
- std::false_type) {
- return None;
+std::optional<Object>
+serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
+ return std::nullopt;
}
/// Serialize the function signature field, as specified by the
@@ -429,7 +462,7 @@ Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record,
/// - The \c parameters array contains names and declaration fragments of the
/// parameters.
///
-/// \returns \c None if \p FS is empty, or an \c Object containing the
+/// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
/// formatted function signature.
template <typename RecordTy>
void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
@@ -438,6 +471,78 @@ void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
Record, has_function_signature<RecordTy>()));
}
+struct PathComponent {
+ StringRef USR;
+ StringRef Name;
+ APIRecord::RecordKind Kind;
+
+ PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
+ : USR(USR), Name(Name), Kind(Kind) {}
+};
+
+template <typename RecordTy>
+bool generatePathComponents(
+ const RecordTy &Record, const APISet &API,
+ function_ref<void(const PathComponent &)> ComponentTransformer) {
+ SmallVector<PathComponent, 4> ReverseComponenents;
+ ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
+ const auto *CurrentParent = &Record.ParentInformation;
+ while (CurrentParent && !CurrentParent->empty()) {
+ PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
+ CurrentParent->ParentName,
+ CurrentParent->ParentKind);
+
+ auto *ParentRecord = CurrentParent->ParentRecord;
+ // Slow path if we don't have a direct reference to the ParentRecord
+ if (!ParentRecord)
+ ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
+
+ // If the parent is a category then we need to pretend this belongs to the
+ // associated interface.
+ if (auto *CategoryRecord =
+ dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
+ ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
+ CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
+ CategoryRecord->Interface.Name,
+ APIRecord::RK_ObjCInterface);
+ }
+
+ // The parent record doesn't exist which means the symbol shouldn't be
+ // treated as part of the current product.
+ if (!ParentRecord)
+ return true;
+
+ ReverseComponenents.push_back(std::move(CurrentParentComponent));
+ CurrentParent = &ParentRecord->ParentInformation;
+ }
+
+ for (const auto &PC : reverse(ReverseComponenents))
+ ComponentTransformer(PC);
+
+ return false;
+}
+Object serializeParentContext(const PathComponent &PC, Language Lang) {
+ Object ParentContextElem;
+ ParentContextElem["usr"] = PC.USR;
+ ParentContextElem["name"] = PC.Name;
+ ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
+ return ParentContextElem;
+}
+
+template <typename RecordTy>
+Array generateParentContexts(const RecordTy &Record, const APISet &API,
+ Language Lang) {
+ Array ParentContexts;
+ if (generatePathComponents(
+ Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
+ ParentContexts.push_back(serializeParentContext(PC, Lang));
+ }))
+ ParentContexts.clear();
+ ParentContexts.pop_back();
+
+ return ParentContexts;
+}
+
} // namespace
void SymbolGraphSerializer::anchor() {}
@@ -457,14 +562,18 @@ Object SymbolGraphSerializer::serializeModule() const {
Object Module;
// The user is expected to always pass `--product-name=` on the command line
// to populate this field.
- Module["name"] = ProductName;
+ Module["name"] = API.ProductName;
serializeObject(Module, "platform", serializePlatform(API.getTarget()));
return Module;
}
bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
+ // Skip explicitly ignored symbols.
+ if (IgnoresList.shouldIgnore(Record.Name))
+ return true;
+
// Skip unconditionally unavailable symbols
- if (Record.Availability.isUnconditionallyUnavailable())
+ if (Record.Availabilities.isUnconditionallyUnavailable())
return true;
// Filter out symbols prefixed with an underscored as they are understood to
@@ -476,10 +585,10 @@ bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
}
template <typename RecordTy>
-Optional<Object>
+std::optional<Object>
SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
if (shouldSkip(Record))
- return None;
+ return std::nullopt;
Object Obj;
serializeObject(Obj, "identifier",
@@ -489,15 +598,24 @@ SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
serializeObject(
Obj, "location",
serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
- serializeObject(Obj, "availbility",
- serializeAvailability(Record.Availability));
+ serializeArray(Obj, "availability",
+ serializeAvailability(Record.Availabilities));
serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
serializeArray(Obj, "declarationFragments",
serializeDeclarationFragments(Record.Declaration));
// TODO: Once we keep track of symbol access information serialize it
// correctly here.
Obj["accessLevel"] = "public";
- serializeArray(Obj, "pathComponents", Array(PathComponents));
+ SmallVector<StringRef, 4> PathComponentsNames;
+ // If this returns true it indicates that we couldn't find a symbol in the
+ // hierarchy.
+ if (generatePathComponents(Record, API,
+ [&PathComponentsNames](const PathComponent &PC) {
+ PathComponentsNames.push_back(PC.Name);
+ }))
+ return {};
+
+ serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
serializeFunctionSignatureMixin(Obj, Record);
@@ -508,8 +626,10 @@ template <typename MemberTy>
void SymbolGraphSerializer::serializeMembers(
const APIRecord &Record,
const SmallVector<std::unique_ptr<MemberTy>> &Members) {
+ // Members should not be serialized if we aren't recursing.
+ if (!ShouldRecurse)
+ return;
for (const auto &Member : Members) {
- auto MemberPathComponentGuard = makePathComponentGuard(Member->Name);
auto MemberRecord = serializeAPIRecord(*Member);
if (!MemberRecord)
continue;
@@ -537,6 +657,7 @@ void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
Object Relationship;
Relationship["source"] = Source.USR;
Relationship["target"] = Target.USR;
+ Relationship["targetFallback"] = Target.Name;
Relationship["kind"] = getRelationshipString(Kind);
Relationships.emplace_back(std::move(Relationship));
@@ -544,8 +665,6 @@ void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
void SymbolGraphSerializer::serializeGlobalFunctionRecord(
const GlobalFunctionRecord &Record) {
- auto GlobalPathComponentGuard = makePathComponentGuard(Record.Name);
-
auto Obj = serializeAPIRecord(Record);
if (!Obj)
return;
@@ -555,8 +674,6 @@ void SymbolGraphSerializer::serializeGlobalFunctionRecord(
void SymbolGraphSerializer::serializeGlobalVariableRecord(
const GlobalVariableRecord &Record) {
- auto GlobalPathComponentGuard = makePathComponentGuard(Record.Name);
-
auto Obj = serializeAPIRecord(Record);
if (!Obj)
return;
@@ -565,7 +682,6 @@ void SymbolGraphSerializer::serializeGlobalVariableRecord(
}
void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
- auto EnumPathComponentGuard = makePathComponentGuard(Record.Name);
auto Enum = serializeAPIRecord(Record);
if (!Enum)
return;
@@ -575,7 +691,6 @@ void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
}
void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
- auto StructPathComponentGuard = makePathComponentGuard(Record.Name);
auto Struct = serializeAPIRecord(Record);
if (!Struct)
return;
@@ -586,7 +701,6 @@ void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
void SymbolGraphSerializer::serializeObjCContainerRecord(
const ObjCContainerRecord &Record) {
- auto ObjCContainerPathComponentGuard = makePathComponentGuard(Record.Name);
auto ObjCContainer = serializeAPIRecord(Record);
if (!ObjCContainer)
return;
@@ -615,7 +729,7 @@ void SymbolGraphSerializer::serializeObjCContainerRecord(
serializeMembers(Record, Category->Methods);
serializeMembers(Record, Category->Properties);
- // Surface the protocols of the the category to the interface.
+ // Surface the protocols of the category to the interface.
for (const auto &Protocol : Category->Protocols)
serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
}
@@ -624,7 +738,6 @@ void SymbolGraphSerializer::serializeObjCContainerRecord(
void SymbolGraphSerializer::serializeMacroDefinitionRecord(
const MacroDefinitionRecord &Record) {
- auto MacroPathComponentGuard = makePathComponentGuard(Record.Name);
auto Macro = serializeAPIRecord(Record);
if (!Macro)
@@ -633,6 +746,46 @@ void SymbolGraphSerializer::serializeMacroDefinitionRecord(
Symbols.emplace_back(std::move(*Macro));
}
+void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
+ switch (Record->getKind()) {
+ case APIRecord::RK_Unknown:
+ llvm_unreachable("Records should have a known kind!");
+ case APIRecord::RK_GlobalFunction:
+ serializeGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
+ break;
+ case APIRecord::RK_GlobalVariable:
+ serializeGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
+ break;
+ case APIRecord::RK_Enum:
+ serializeEnumRecord(*cast<EnumRecord>(Record));
+ break;
+ case APIRecord::RK_Struct:
+ serializeStructRecord(*cast<StructRecord>(Record));
+ break;
+ case APIRecord::RK_ObjCInterface:
+ serializeObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
+ break;
+ case APIRecord::RK_ObjCProtocol:
+ serializeObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
+ break;
+ case APIRecord::RK_MacroDefinition:
+ serializeMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
+ break;
+ case APIRecord::RK_Typedef:
+ serializeTypedefRecord(*cast<TypedefRecord>(Record));
+ break;
+ default:
+ if (auto Obj = serializeAPIRecord(*Record)) {
+ Symbols.emplace_back(std::move(*Obj));
+ auto &ParentInformation = Record->ParentInformation;
+ if (!ParentInformation.empty())
+ serializeRelationship(RelationshipKind::MemberOf, *Record,
+ *ParentInformation.ParentRecord);
+ }
+ break;
+ }
+}
+
void SymbolGraphSerializer::serializeTypedefRecord(
const TypedefRecord &Record) {
// Typedefs of anonymous types have their entries unified with the underlying
@@ -644,7 +797,6 @@ void SymbolGraphSerializer::serializeTypedefRecord(
if (ShouldDrop)
return;
- auto TypedefPathComponentGuard = makePathComponentGuard(Record.Name);
auto Typedef = serializeAPIRecord(Record);
if (!Typedef)
return;
@@ -654,16 +806,7 @@ void SymbolGraphSerializer::serializeTypedefRecord(
Symbols.emplace_back(std::move(*Typedef));
}
-SymbolGraphSerializer::PathComponentGuard
-SymbolGraphSerializer::makePathComponentGuard(StringRef Component) {
- return PathComponentGuard(PathComponents, Component);
-}
-
Object SymbolGraphSerializer::serialize() {
- Object Root;
- serializeObject(Root, "metadata", serializeMetadata());
- serializeObject(Root, "module", serializeModule());
-
// Serialize global variables in the API set.
for (const auto &GlobalVar : API.getGlobalVariables())
serializeGlobalVariableRecord(*GlobalVar.second);
@@ -693,6 +836,14 @@ Object SymbolGraphSerializer::serialize() {
for (const auto &Typedef : API.getTypedefs())
serializeTypedefRecord(*Typedef.second);
+ return serializeCurrentGraph();
+}
+
+Object SymbolGraphSerializer::serializeCurrentGraph() {
+ Object Root;
+ serializeObject(Root, "metadata", serializeMetadata());
+ serializeObject(Root, "module", serializeModule());
+
Root["symbols"] = std::move(Symbols);
Root["relationships"] = std::move(Relationships);
@@ -706,3 +857,53 @@ void SymbolGraphSerializer::serialize(raw_ostream &os) {
else
os << formatv("{0:2}", Value(std::move(root))) << "\n";
}
+
+std::optional<Object>
+SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
+ const APISet &API) {
+ APIRecord *Record = API.findRecordForUSR(USR);
+ if (!Record)
+ return {};
+
+ Object Root;
+ APIIgnoresList EmptyIgnores;
+ SymbolGraphSerializer Serializer(API, EmptyIgnores,
+ /*Options.Compact*/ {true},
+ /*ShouldRecurse*/ false);
+ Serializer.serializeSingleRecord(Record);
+ serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
+
+ Language Lang = API.getLanguage();
+ serializeArray(Root, "parentContexts",
+ generateParentContexts(*Record, API, Lang));
+
+ Array RelatedSymbols;
+
+ for (const auto &Fragment : Record->Declaration.getFragments()) {
+ // If we don't have a USR there isn't much we can do.
+ if (Fragment.PreciseIdentifier.empty())
+ continue;
+
+ APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
+
+ // If we can't find the record let's skip.
+ if (!RelatedRecord)
+ continue;
+
+ Object RelatedSymbol;
+ RelatedSymbol["usr"] = RelatedRecord->USR;
+ RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
+ // TODO: once we record this properly let's serialize it right.
+ RelatedSymbol["accessLevel"] = "public";
+ RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
+ RelatedSymbol["moduleName"] = API.ProductName;
+ RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
+
+ serializeArray(RelatedSymbol, "parentContexts",
+ generateParentContexts(*RelatedRecord, API, Lang));
+ RelatedSymbols.push_back(std::move(RelatedSymbol));
+ }
+
+ serializeArray(Root, "relatedSymbols", RelatedSymbols);
+ return Root;
+}
diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
index 9c165e693e0e..3da2424ea726 100644
--- a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
+++ b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
@@ -17,9 +17,8 @@
using namespace clang;
using namespace extractapi;
-namespace {
-
-const NamedDecl *getUnderlyingTypeDecl(QualType Type) {
+const NamedDecl *
+TypedefUnderlyingTypeResolver::getUnderlyingTypeDecl(QualType Type) const {
const NamedDecl *TypeDecl = nullptr;
const TypedefType *TypedefTy = Type->getAs<TypedefType>();
@@ -44,8 +43,6 @@ const NamedDecl *getUnderlyingTypeDecl(QualType Type) {
return TypeDecl;
}
-} // namespace
-
SymbolReference
TypedefUnderlyingTypeResolver::getSymbolReferenceForType(QualType Type,
APISet &API) const {
diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
index 0096ff235914..54aa11c354c0 100644
--- a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
+++ b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
@@ -26,6 +26,8 @@ namespace clang {
namespace extractapi {
struct TypedefUnderlyingTypeResolver {
+ /// Gets the underlying type declaration.
+ const NamedDecl *getUnderlyingTypeDecl(QualType Type) const;
/// Get a SymbolReference for the given type.
SymbolReference getSymbolReferenceForType(QualType Type, APISet &API) const;
diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp
index db82018a4c83..b3ef2a895d7f 100644
--- a/clang/lib/Format/BreakableToken.cpp
+++ b/clang/lib/Format/BreakableToken.cpp
@@ -49,10 +49,10 @@ static StringRef getLineCommentIndentPrefix(StringRef Comment,
if (Style.Language == FormatStyle::LK_TextProto)
KnownPrefixes = KnownTextProtoPrefixes;
- assert(std::is_sorted(KnownPrefixes.begin(), KnownPrefixes.end(),
- [](StringRef Lhs, StringRef Rhs) noexcept {
- return Lhs.size() > Rhs.size();
- }));
+ assert(
+ llvm::is_sorted(KnownPrefixes, [](StringRef Lhs, StringRef Rhs) noexcept {
+ return Lhs.size() > Rhs.size();
+ }));
for (StringRef KnownPrefix : KnownPrefixes) {
if (Comment.startswith(KnownPrefix)) {
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 651ec80d6196..412c57b850b5 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -21,6 +21,7 @@
#include "clang/Format/Format.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Debug.h"
+#include <optional>
#define DEBUG_TYPE "format-indenter"
@@ -146,13 +147,13 @@ static bool opensProtoMessageField(const FormatToken &LessTok,
(LessTok.Previous && LessTok.Previous->is(tok::equal))));
}
-// Returns the delimiter of a raw string literal, or None if TokenText is not
-// the text of a raw string literal. The delimiter could be the empty string.
-// For example, the delimiter of R"deli(cont)deli" is deli.
-static llvm::Optional<StringRef> getRawStringDelimiter(StringRef TokenText) {
+// Returns the delimiter of a raw string literal, or std::nullopt if TokenText
+// is not the text of a raw string literal. The delimiter could be the empty
+// string. For example, the delimiter of R"deli(cont)deli" is deli.
+static std::optional<StringRef> getRawStringDelimiter(StringRef TokenText) {
if (TokenText.size() < 5 // The smallest raw string possible is 'R"()"'.
|| !TokenText.startswith("R\"") || !TokenText.endswith("\"")) {
- return None;
+ return std::nullopt;
}
// A raw string starts with 'R"<delimiter>(' and delimiter is ascii and has
@@ -160,15 +161,15 @@ static llvm::Optional<StringRef> getRawStringDelimiter(StringRef TokenText) {
// 19 bytes.
size_t LParenPos = TokenText.substr(0, 19).find_first_of('(');
if (LParenPos == StringRef::npos)
- return None;
+ return std::nullopt;
StringRef Delimiter = TokenText.substr(2, LParenPos - 2);
// Check that the string ends in ')Delimiter"'.
size_t RParenPos = TokenText.size() - Delimiter.size() - 2;
if (TokenText[RParenPos] != ')')
- return None;
+ return std::nullopt;
if (!TokenText.substr(RParenPos + 1).startswith(Delimiter))
- return None;
+ return std::nullopt;
return Delimiter;
}
@@ -186,7 +187,7 @@ getCanonicalRawStringDelimiter(const FormatStyle &Style,
RawStringFormatStyleManager::RawStringFormatStyleManager(
const FormatStyle &CodeStyle) {
for (const auto &RawStringFormat : CodeStyle.RawStringFormats) {
- llvm::Optional<FormatStyle> LanguageStyle =
+ std::optional<FormatStyle> LanguageStyle =
CodeStyle.GetLanguageStyle(RawStringFormat.Language);
if (!LanguageStyle) {
FormatStyle PredefinedStyle;
@@ -205,20 +206,20 @@ RawStringFormatStyleManager::RawStringFormatStyleManager(
}
}
-llvm::Optional<FormatStyle>
+std::optional<FormatStyle>
RawStringFormatStyleManager::getDelimiterStyle(StringRef Delimiter) const {
auto It = DelimiterStyle.find(Delimiter);
if (It == DelimiterStyle.end())
- return None;
+ return std::nullopt;
return It->second;
}
-llvm::Optional<FormatStyle>
+std::optional<FormatStyle>
RawStringFormatStyleManager::getEnclosingFunctionStyle(
StringRef EnclosingFunction) const {
auto It = EnclosingFunctionStyle.find(EnclosingFunction);
if (It == EnclosingFunctionStyle.end())
- return None;
+ return std::nullopt;
return It->second;
}
@@ -331,6 +332,15 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
if (Previous.is(tok::l_square) && Previous.is(TT_ObjCMethodExpr))
return false;
+ if (Current.is(TT_ConditionalExpr) && Previous.is(tok::r_paren) &&
+ Previous.MatchingParen && Previous.MatchingParen->Previous &&
+ Previous.MatchingParen->Previous->MatchingParen &&
+ Previous.MatchingParen->Previous->MatchingParen->is(TT_LambdaLBrace)) {
+ // We have a lambda within a conditional expression, allow breaking here.
+ assert(Previous.MatchingParen->Previous->is(tok::r_brace));
+ return true;
+ }
+
return !CurrentState.NoLineBreak;
}
@@ -343,8 +353,12 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
auto LambdaBodyLength = getLengthToMatchingParen(Current, State.Stack);
return LambdaBodyLength > getColumnLimit(State);
}
- if (Current.MustBreakBefore || Current.is(TT_InlineASMColon))
+ if (Current.MustBreakBefore ||
+ (Current.is(TT_InlineASMColon) &&
+ (Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always ||
+ Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_OnlyMultiline))) {
return true;
+ }
if (CurrentState.BreakBeforeClosingBrace &&
Current.closesBlockOrBlockTypeList(Style)) {
return true;
@@ -444,7 +458,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
}
// If the template declaration spans multiple lines, force wrap before the
- // function/class declaration
+ // function/class declaration.
if (Previous.ClosesTemplateDeclaration && CurrentState.BreakBeforeParameter &&
Current.CanBreakBefore) {
return true;
@@ -552,7 +566,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
// If the return type spans multiple lines, wrap before the function name.
if (((Current.is(TT_FunctionDeclarationName) &&
- // Don't break before a C# function when no break after return type
+ !State.Line->ReturnTypeWrapped &&
+ // Don't break before a C# function when no break after return type.
(!Style.isCSharp() ||
Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None) &&
// Don't always break between a JavaScript `function` and the function
@@ -707,8 +722,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
(Previous.is(tok::l_brace) && Previous.isNot(BK_Block) &&
Style.Cpp11BracedListStyle)) &&
State.Column > getNewLineColumn(State) &&
- (!Previous.Previous || !Previous.Previous->isOneOf(
- tok::kw_for, tok::kw_while, tok::kw_switch)) &&
+ (!Previous.Previous ||
+ !Previous.Previous->isOneOf(TT_CastRParen, tok::kw_for, tok::kw_while,
+ tok::kw_switch)) &&
// Don't do this for simple (no expressions) one-argument function calls
// as that feels like needlessly wasting whitespace, e.g.:
//
@@ -1090,8 +1106,12 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
CurrentState.Indent + Style.ContinuationIndentWidth);
}
- if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths &&
- State.Line->First->is(tok::kw_enum)) {
+ // After a goto label. Usually labels are on separate lines. However
+ // for Verilog the labels may be only recognized by the annotator and
+ // thus are on the same line as the current token.
+ if ((Style.isVerilog() && Keywords.isVerilogEndOfLabel(Previous)) ||
+ (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths &&
+ State.Line->First->is(tok::kw_enum))) {
return (Style.IndentWidth * State.Line->First->IndentLevel) +
Style.IndentWidth;
}
@@ -1244,6 +1264,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
return ContinuationIndent;
}
+ if (State.Line->InPragmaDirective)
+ return CurrentState.Indent + Style.ContinuationIndentWidth;
+
// This ensure that we correctly format ObjC methods calls without inputs,
// i.e. where the last element isn't selector like: [callee method];
if (NextNonComment->is(tok::identifier) && NextNonComment->FakeRParens == 0 &&
@@ -1301,7 +1324,7 @@ static bool hasNestedBlockInlined(const FormatToken *Previous,
if (Previous->ParameterCount > 1)
return true;
- // Also a nested block if contains a lambda inside function with 1 parameter
+ // Also a nested block if contains a lambda inside function with 1 parameter.
return Style.BraceWrapping.BeforeLambdaBody && Current.is(TT_LambdaLSquare);
}
@@ -1399,8 +1422,10 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
CurrentState.NestedBlockIndent = State.Column + Current.ColumnWidth + 1;
if (Current.isOneOf(TT_LambdaLSquare, TT_LambdaArrow))
CurrentState.LastSpace = State.Column;
- if (Current.is(TT_RequiresExpression))
+ if (Current.is(TT_RequiresExpression) &&
+ Style.RequiresExpressionIndentation == FormatStyle::REI_Keyword) {
CurrentState.NestedBlockIndent = State.Column;
+ }
// Insert scopes created by fake parenthesis.
const FormatToken *Previous = Current.getPreviousNonComment();
@@ -1514,6 +1539,12 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
std::max(State.Column, NewParenState.Indent), CurrentState.LastSpace);
}
+ // Special case for generic selection expressions, its comma-separated
+ // expressions are not aligned to the opening paren like regular calls, but
+ // rather continuation-indented relative to the _Generic keyword.
+ if (Previous && Previous->endsSequence(tok::l_paren, tok::kw__Generic))
+ NewParenState.Indent = CurrentState.LastSpace;
+
if (Previous &&
(Previous->getPrecedence() == prec::Assignment ||
Previous->isOneOf(tok::kw_return, TT_RequiresClause) ||
@@ -1521,7 +1552,7 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
Previous->is(TT_ConditionalExpr))) &&
!Newline) {
// If BreakBeforeBinaryOperators is set, un-indent a bit to account for
- // the operator and keep the operands aligned
+ // the operator and keep the operands aligned.
if (Style.AlignOperands == FormatStyle::OAS_AlignAfterOperator)
NewParenState.UnindentOperator = true;
// Mark indentation as alignment if the expression is aligned.
@@ -1660,8 +1691,12 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
(State.Line->Type != LT_ObjCDecl && Style.BinPackParameters) ||
(State.Line->Type == LT_ObjCDecl && ObjCBinPackProtocolList);
+ bool GenericSelection =
+ Current.getPreviousNonComment() &&
+ Current.getPreviousNonComment()->is(tok::kw__Generic);
+
AvoidBinPacking =
- (CurrentState.IsCSharpGenericTypeConstraint) ||
+ (CurrentState.IsCSharpGenericTypeConstraint) || GenericSelection ||
(Style.isJavaScript() && EndsInComma) ||
(State.Line->MustBeDeclaration && !BinPackDeclaration) ||
(!State.Line->MustBeDeclaration && !Style.BinPackArguments) ||
@@ -1713,7 +1748,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
if (Style.BraceWrapping.BeforeLambdaBody && Current.Next != nullptr &&
Current.is(tok::l_paren)) {
- // Search for any parameter that is a lambda
+ // Search for any parameter that is a lambda.
FormatToken const *next = Current.Next;
while (next != nullptr) {
if (next->is(TT_LambdaLSquare)) {
@@ -2045,21 +2080,21 @@ static StringRef getEnclosingFunctionName(const FormatToken &Current) {
return Tok->TokenText;
}
-llvm::Optional<FormatStyle>
+std::optional<FormatStyle>
ContinuationIndenter::getRawStringStyle(const FormatToken &Current,
const LineState &State) {
if (!Current.isStringLiteral())
- return None;
+ return std::nullopt;
auto Delimiter = getRawStringDelimiter(Current.TokenText);
if (!Delimiter)
- return None;
+ return std::nullopt;
auto RawStringStyle = RawStringFormats.getDelimiterStyle(*Delimiter);
if (!RawStringStyle && Delimiter->empty()) {
RawStringStyle = RawStringFormats.getEnclosingFunctionStyle(
getEnclosingFunctionName(Current));
}
if (!RawStringStyle)
- return None;
+ return std::nullopt;
RawStringStyle->ColumnLimit = getColumnLimit(State);
return RawStringStyle;
}
@@ -2533,7 +2568,7 @@ ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
}
unsigned ContinuationIndenter::getColumnLimit(const LineState &State) const {
- // In preprocessor directives reserve two chars for trailing " \"
+ // In preprocessor directives reserve two chars for trailing " \".
return Style.ColumnLimit - (State.Line->InPPDirective ? 2 : 0);
}
diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h
index 620060e68861..2a1b96834a79 100644
--- a/clang/lib/Format/ContinuationIndenter.h
+++ b/clang/lib/Format/ContinuationIndenter.h
@@ -20,6 +20,7 @@
#include "clang/Format/Format.h"
#include "llvm/Support/Regex.h"
#include <map>
+#include <optional>
#include <tuple>
namespace clang {
@@ -41,9 +42,9 @@ struct RawStringFormatStyleManager {
RawStringFormatStyleManager(const FormatStyle &CodeStyle);
- llvm::Optional<FormatStyle> getDelimiterStyle(StringRef Delimiter) const;
+ std::optional<FormatStyle> getDelimiterStyle(StringRef Delimiter) const;
- llvm::Optional<FormatStyle>
+ std::optional<FormatStyle>
getEnclosingFunctionStyle(StringRef EnclosingFunction) const;
};
@@ -120,8 +121,8 @@ private:
/// If \p Current is a raw string that is configured to be reformatted,
/// return the style to be used.
- llvm::Optional<FormatStyle> getRawStringStyle(const FormatToken &Current,
- const LineState &State);
+ std::optional<FormatStyle> getRawStringStyle(const FormatToken &Current,
+ const LineState &State);
/// If the current token sticks out over the end of the line, break
/// it if possible.
diff --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp
index f6edcd13ecd6..5c006e2d037b 100644
--- a/clang/lib/Format/DefinitionBlockSeparator.cpp
+++ b/clang/lib/Format/DefinitionBlockSeparator.cpp
@@ -69,11 +69,11 @@ void DefinitionBlockSeparator::separateBlocks(
(Style.SeparateDefinitionBlocks == FormatStyle::SDS_Always ? 1 : 0) + 1;
WhitespaceManager Whitespaces(
Env.getSourceManager(), Style,
- Style.DeriveLineEnding
+ Style.LineEnding > FormatStyle::LE_CRLF
? WhitespaceManager::inputUsesCRLF(
Env.getSourceManager().getBufferData(Env.getFileID()),
- Style.UseCRLF)
- : Style.UseCRLF);
+ Style.LineEnding == FormatStyle::LE_DeriveCRLF)
+ : Style.LineEnding == FormatStyle::LE_CRLF);
for (unsigned I = 0; I < Lines.size(); ++I) {
const auto &CurrentLine = Lines[I];
if (CurrentLine->InPPDirective)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 2659fa2af1a7..f37c3f983635 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -20,6 +20,7 @@
#include "FormatInternal.h"
#include "FormatToken.h"
#include "FormatTokenLexer.h"
+#include "IntegerLiteralSeparatorFixer.h"
#include "NamespaceEndCommentsFixer.h"
#include "QualifierAlignmentFixer.h"
#include "SortJavaScriptImports.h"
@@ -46,6 +47,7 @@
#include <algorithm>
#include <memory>
#include <mutex>
+#include <optional>
#include <string>
#include <unordered_map>
@@ -57,101 +59,6 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
namespace llvm {
namespace yaml {
-template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
- static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
- IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
- IO.enumCase(Value, "Java", FormatStyle::LK_Java);
- IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
- IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
- IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
- IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
- IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
- IO.enumCase(Value, "CSharp", FormatStyle::LK_CSharp);
- IO.enumCase(Value, "Json", FormatStyle::LK_Json);
- }
-};
-
-template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
- static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
- 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);
- }
-};
-
-template <>
-struct ScalarEnumerationTraits<FormatStyle::LambdaBodyIndentationKind> {
- static void enumeration(IO &IO,
- FormatStyle::LambdaBodyIndentationKind &Value) {
- IO.enumCase(Value, "Signature", FormatStyle::LBI_Signature);
- IO.enumCase(Value, "OuterScope", FormatStyle::LBI_OuterScope);
- }
-};
-
-template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
- static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
- IO.enumCase(Value, "Never", FormatStyle::UT_Never);
- IO.enumCase(Value, "false", FormatStyle::UT_Never);
- IO.enumCase(Value, "Always", FormatStyle::UT_Always);
- IO.enumCase(Value, "true", FormatStyle::UT_Always);
- IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
- IO.enumCase(Value, "ForContinuationAndIndentation",
- FormatStyle::UT_ForContinuationAndIndentation);
- IO.enumCase(Value, "AlignWithSpaces", FormatStyle::UT_AlignWithSpaces);
- }
-};
-
-template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
- static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) {
- IO.enumCase(Value, "Leave", FormatStyle::JSQS_Leave);
- IO.enumCase(Value, "Single", FormatStyle::JSQS_Single);
- IO.enumCase(Value, "Double", FormatStyle::JSQS_Double);
- }
-};
-
-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::QualifierAlignmentStyle> {
- static void enumeration(IO &IO, FormatStyle::QualifierAlignmentStyle &Value) {
- IO.enumCase(Value, "Leave", FormatStyle::QAS_Leave);
- IO.enumCase(Value, "Left", FormatStyle::QAS_Left);
- IO.enumCase(Value, "Right", FormatStyle::QAS_Right);
- IO.enumCase(Value, "Custom", FormatStyle::QAS_Custom);
- }
-};
-
-template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
- static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
- IO.enumCase(Value, "None", FormatStyle::SFS_None);
- IO.enumCase(Value, "false", FormatStyle::SFS_None);
- IO.enumCase(Value, "All", FormatStyle::SFS_All);
- IO.enumCase(Value, "true", FormatStyle::SFS_All);
- IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
- IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
- IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
- }
-};
-
template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> {
static void enumInput(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) {
IO.enumCase(Value, "None",
@@ -205,6 +112,15 @@ template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> {
};
template <>
+struct ScalarEnumerationTraits<FormatStyle::AttributeBreakingStyle> {
+ static void enumeration(IO &IO, FormatStyle::AttributeBreakingStyle &Value) {
+ IO.enumCase(Value, "Always", FormatStyle::ABS_Always);
+ IO.enumCase(Value, "Leave", FormatStyle::ABS_Leave);
+ IO.enumCase(Value, "Never", FormatStyle::ABS_Never);
+ }
+};
+
+template <>
struct ScalarEnumerationTraits<FormatStyle::ArrayInitializerAlignmentStyle> {
static void enumeration(IO &IO,
FormatStyle::ArrayInitializerAlignmentStyle &Value) {
@@ -214,28 +130,13 @@ struct ScalarEnumerationTraits<FormatStyle::ArrayInitializerAlignmentStyle> {
}
};
-template <> struct ScalarEnumerationTraits<FormatStyle::ShortIfStyle> {
- static void enumeration(IO &IO, FormatStyle::ShortIfStyle &Value) {
- IO.enumCase(Value, "Never", FormatStyle::SIS_Never);
- IO.enumCase(Value, "WithoutElse", FormatStyle::SIS_WithoutElse);
- IO.enumCase(Value, "OnlyFirstIf", FormatStyle::SIS_OnlyFirstIf);
- IO.enumCase(Value, "AllIfsAndElse", FormatStyle::SIS_AllIfsAndElse);
-
- // For backward compatibility.
- IO.enumCase(Value, "Always", FormatStyle::SIS_OnlyFirstIf);
- IO.enumCase(Value, "false", FormatStyle::SIS_Never);
- IO.enumCase(Value, "true", FormatStyle::SIS_WithoutElse);
- }
-};
-
-template <> struct ScalarEnumerationTraits<FormatStyle::ShortLambdaStyle> {
- static void enumeration(IO &IO, FormatStyle::ShortLambdaStyle &Value) {
- IO.enumCase(Value, "None", FormatStyle::SLS_None);
- IO.enumCase(Value, "false", FormatStyle::SLS_None);
- IO.enumCase(Value, "Empty", FormatStyle::SLS_Empty);
- IO.enumCase(Value, "Inline", FormatStyle::SLS_Inline);
- IO.enumCase(Value, "All", FormatStyle::SLS_All);
- IO.enumCase(Value, "true", FormatStyle::SLS_All);
+template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
+ static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
+ IO.enumCase(Value, "All", FormatStyle::BOS_All);
+ IO.enumCase(Value, "true", FormatStyle::BOS_All);
+ IO.enumCase(Value, "None", FormatStyle::BOS_None);
+ IO.enumCase(Value, "false", FormatStyle::BOS_None);
+ IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment);
}
};
@@ -247,20 +148,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BinPackStyle> {
}
};
-template <> struct ScalarEnumerationTraits<FormatStyle::TrailingCommaStyle> {
- static void enumeration(IO &IO, FormatStyle::TrailingCommaStyle &Value) {
- IO.enumCase(Value, "None", FormatStyle::TCS_None);
- IO.enumCase(Value, "Wrapped", FormatStyle::TCS_Wrapped);
- }
-};
-
-template <> struct ScalarEnumerationTraits<FormatStyle::BinaryOperatorStyle> {
- static void enumeration(IO &IO, FormatStyle::BinaryOperatorStyle &Value) {
- IO.enumCase(Value, "All", FormatStyle::BOS_All);
- IO.enumCase(Value, "true", FormatStyle::BOS_All);
- IO.enumCase(Value, "None", FormatStyle::BOS_None);
- IO.enumCase(Value, "false", FormatStyle::BOS_None);
- IO.enumCase(Value, "NonAssignment", FormatStyle::BOS_NonAssignment);
+template <>
+struct ScalarEnumerationTraits<FormatStyle::BitFieldColonSpacingStyle> {
+ static void enumeration(IO &IO,
+ FormatStyle::BitFieldColonSpacingStyle &Value) {
+ IO.enumCase(Value, "Both", FormatStyle::BFCS_Both);
+ IO.enumCase(Value, "None", FormatStyle::BFCS_None);
+ IO.enumCase(Value, "Before", FormatStyle::BFCS_Before);
+ IO.enumCase(Value, "After", FormatStyle::BFCS_After);
}
};
@@ -278,6 +173,42 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
}
};
+template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
+ static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
+ IO.mapOptional("AfterCaseLabel", Wrapping.AfterCaseLabel);
+ IO.mapOptional("AfterClass", Wrapping.AfterClass);
+ IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
+ IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
+ IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
+ IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
+ IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
+ IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
+ IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
+ IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
+ IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
+ IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
+ IO.mapOptional("BeforeLambdaBody", Wrapping.BeforeLambdaBody);
+ IO.mapOptional("BeforeWhile", Wrapping.BeforeWhile);
+ IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
+ IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
+ IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
+ IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
+ static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) {
+ IO.enumCase(Value, "Align", FormatStyle::BAS_Align);
+ IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign);
+ IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
+ IO.enumCase(Value, "BlockIndent", FormatStyle::BAS_BlockIndent);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "true", FormatStyle::BAS_Align);
+ IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign);
+ }
+};
+
template <>
struct ScalarEnumerationTraits<
FormatStyle::BraceWrappingAfterControlStatementStyle> {
@@ -310,6 +241,15 @@ struct ScalarEnumerationTraits<
};
template <>
+struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> {
+ static void enumeration(IO &IO,
+ FormatStyle::BreakBeforeInlineASMColonStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::BBIAS_Never);
+ IO.enumCase(Value, "OnlyMultiline", FormatStyle::BBIAS_OnlyMultiline);
+ IO.enumCase(Value, "Always", FormatStyle::BBIAS_Always);
+ }
+};
+template <>
struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
static void
enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
@@ -331,13 +271,44 @@ struct ScalarEnumerationTraits<FormatStyle::BreakInheritanceListStyle> {
};
template <>
-struct ScalarEnumerationTraits<FormatStyle::PackConstructorInitializersStyle> {
+struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> {
+ static void enumeration(IO &IO,
+ FormatStyle::BreakTemplateDeclarationsStyle &Value) {
+ IO.enumCase(Value, "No", FormatStyle::BTDS_No);
+ IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine);
+ IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "false", FormatStyle::BTDS_MultiLine);
+ IO.enumCase(Value, "true", FormatStyle::BTDS_Yes);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
static void
- enumeration(IO &IO, FormatStyle::PackConstructorInitializersStyle &Value) {
- IO.enumCase(Value, "Never", FormatStyle::PCIS_Never);
- IO.enumCase(Value, "BinPack", FormatStyle::PCIS_BinPack);
- IO.enumCase(Value, "CurrentLine", FormatStyle::PCIS_CurrentLine);
- IO.enumCase(Value, "NextLine", FormatStyle::PCIS_NextLine);
+ enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::DRTBS_None);
+ IO.enumCase(Value, "All", FormatStyle::DRTBS_All);
+ IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "false", FormatStyle::DRTBS_None);
+ IO.enumCase(Value, "true", FormatStyle::DRTBS_All);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
+ static void enumeration(IO &IO,
+ FormatStyle::EscapedNewlineAlignmentStyle &Value) {
+ IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
+ IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
+ IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
+ IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
}
};
@@ -364,15 +335,6 @@ struct ScalarEnumerationTraits<
};
template <>
-struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
- static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
- IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
- IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
- IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash);
- }
-};
-
-template <>
struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
static void enumeration(IO &IO, FormatStyle::IndentExternBlockStyle &Value) {
IO.enumCase(Value, "AfterExternBlock", FormatStyle::IEBS_AfterExternBlock);
@@ -383,80 +345,80 @@ struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
}
};
-template <>
-struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
- static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
- IO.enumCase(Value, "None", FormatStyle::RTBS_None);
- IO.enumCase(Value, "All", FormatStyle::RTBS_All);
- IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
- IO.enumCase(Value, "TopLevelDefinitions",
- FormatStyle::RTBS_TopLevelDefinitions);
- IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
+template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> {
+ static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) {
+ IO.mapOptional("Binary", Base.Binary);
+ IO.mapOptional("Decimal", Base.Decimal);
+ IO.mapOptional("Hex", Base.Hex);
}
};
-template <>
-struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> {
- static void enumeration(IO &IO,
- FormatStyle::BreakTemplateDeclarationsStyle &Value) {
- IO.enumCase(Value, "No", FormatStyle::BTDS_No);
- IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine);
- IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes);
+template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
+ static void enumeration(IO &IO, FormatStyle::JavaScriptQuoteStyle &Value) {
+ IO.enumCase(Value, "Leave", FormatStyle::JSQS_Leave);
+ IO.enumCase(Value, "Single", FormatStyle::JSQS_Single);
+ IO.enumCase(Value, "Double", FormatStyle::JSQS_Double);
+ }
+};
- // For backward compatibility.
- IO.enumCase(Value, "false", FormatStyle::BTDS_MultiLine);
- IO.enumCase(Value, "true", FormatStyle::BTDS_Yes);
+template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
+ static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
+ IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
+ IO.enumCase(Value, "Java", FormatStyle::LK_Java);
+ IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
+ IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
+ IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
+ IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
+ IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
+ IO.enumCase(Value, "CSharp", FormatStyle::LK_CSharp);
+ IO.enumCase(Value, "Json", FormatStyle::LK_Json);
}
};
-template <>
-struct ScalarEnumerationTraits<FormatStyle::DefinitionReturnTypeBreakingStyle> {
- static void
- enumeration(IO &IO, FormatStyle::DefinitionReturnTypeBreakingStyle &Value) {
- IO.enumCase(Value, "None", FormatStyle::DRTBS_None);
- IO.enumCase(Value, "All", FormatStyle::DRTBS_All);
- IO.enumCase(Value, "TopLevel", FormatStyle::DRTBS_TopLevel);
+template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
+ static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
+ 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
- // For backward compatibility.
- IO.enumCase(Value, "false", FormatStyle::DRTBS_None);
- IO.enumCase(Value, "true", FormatStyle::DRTBS_All);
+ 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);
}
};
template <>
-struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
+struct ScalarEnumerationTraits<FormatStyle::LambdaBodyIndentationKind> {
static void enumeration(IO &IO,
- FormatStyle::NamespaceIndentationKind &Value) {
- IO.enumCase(Value, "None", FormatStyle::NI_None);
- IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
- IO.enumCase(Value, "All", FormatStyle::NI_All);
+ FormatStyle::LambdaBodyIndentationKind &Value) {
+ IO.enumCase(Value, "Signature", FormatStyle::LBI_Signature);
+ IO.enumCase(Value, "OuterScope", FormatStyle::LBI_OuterScope);
}
};
-template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
- static void enumeration(IO &IO, FormatStyle::BracketAlignmentStyle &Value) {
- IO.enumCase(Value, "Align", FormatStyle::BAS_Align);
- IO.enumCase(Value, "DontAlign", FormatStyle::BAS_DontAlign);
- IO.enumCase(Value, "AlwaysBreak", FormatStyle::BAS_AlwaysBreak);
- IO.enumCase(Value, "BlockIndent", FormatStyle::BAS_BlockIndent);
-
- // For backward compatibility.
- IO.enumCase(Value, "true", FormatStyle::BAS_Align);
- IO.enumCase(Value, "false", FormatStyle::BAS_DontAlign);
+template <> struct ScalarEnumerationTraits<FormatStyle::LineEndingStyle> {
+ static void enumeration(IO &IO, FormatStyle::LineEndingStyle &Value) {
+ IO.enumCase(Value, "LF", FormatStyle::LE_LF);
+ IO.enumCase(Value, "CRLF", FormatStyle::LE_CRLF);
+ IO.enumCase(Value, "DeriveLF", FormatStyle::LE_DeriveLF);
+ IO.enumCase(Value, "DeriveCRLF", FormatStyle::LE_DeriveCRLF);
}
};
template <>
-struct ScalarEnumerationTraits<FormatStyle::EscapedNewlineAlignmentStyle> {
+struct ScalarEnumerationTraits<FormatStyle::NamespaceIndentationKind> {
static void enumeration(IO &IO,
- FormatStyle::EscapedNewlineAlignmentStyle &Value) {
- IO.enumCase(Value, "DontAlign", FormatStyle::ENAS_DontAlign);
- IO.enumCase(Value, "Left", FormatStyle::ENAS_Left);
- IO.enumCase(Value, "Right", FormatStyle::ENAS_Right);
-
- // For backward compatibility.
- IO.enumCase(Value, "true", FormatStyle::ENAS_Left);
- IO.enumCase(Value, "false", FormatStyle::ENAS_Right);
+ FormatStyle::NamespaceIndentationKind &Value) {
+ IO.enumCase(Value, "None", FormatStyle::NI_None);
+ IO.enumCase(Value, "Inner", FormatStyle::NI_Inner);
+ IO.enumCase(Value, "All", FormatStyle::NI_All);
}
};
@@ -473,6 +435,17 @@ template <> struct ScalarEnumerationTraits<FormatStyle::OperandAlignmentStyle> {
}
};
+template <>
+struct ScalarEnumerationTraits<FormatStyle::PackConstructorInitializersStyle> {
+ static void
+ enumeration(IO &IO, FormatStyle::PackConstructorInitializersStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::PCIS_Never);
+ IO.enumCase(Value, "BinPack", FormatStyle::PCIS_BinPack);
+ IO.enumCase(Value, "CurrentLine", FormatStyle::PCIS_CurrentLine);
+ IO.enumCase(Value, "NextLine", FormatStyle::PCIS_NextLine);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
static void enumeration(IO &IO, FormatStyle::PointerAlignmentStyle &Value) {
IO.enumCase(Value, "Middle", FormatStyle::PAS_Middle);
@@ -486,22 +459,31 @@ template <> struct ScalarEnumerationTraits<FormatStyle::PointerAlignmentStyle> {
};
template <>
-struct ScalarEnumerationTraits<FormatStyle::SeparateDefinitionStyle> {
- static void enumeration(IO &IO, FormatStyle::SeparateDefinitionStyle &Value) {
- IO.enumCase(Value, "Leave", FormatStyle::SDS_Leave);
- IO.enumCase(Value, "Always", FormatStyle::SDS_Always);
- IO.enumCase(Value, "Never", FormatStyle::SDS_Never);
+struct ScalarEnumerationTraits<FormatStyle::PPDirectiveIndentStyle> {
+ static void enumeration(IO &IO, FormatStyle::PPDirectiveIndentStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::PPDIS_None);
+ IO.enumCase(Value, "AfterHash", FormatStyle::PPDIS_AfterHash);
+ IO.enumCase(Value, "BeforeHash", FormatStyle::PPDIS_BeforeHash);
}
};
template <>
-struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> {
- static void
- enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) {
- IO.enumCase(Value, "Default", FormatStyle::SAPQ_Default);
- IO.enumCase(Value, "Before", FormatStyle::SAPQ_Before);
- IO.enumCase(Value, "After", FormatStyle::SAPQ_After);
- IO.enumCase(Value, "Both", FormatStyle::SAPQ_Both);
+struct ScalarEnumerationTraits<FormatStyle::QualifierAlignmentStyle> {
+ static void enumeration(IO &IO, FormatStyle::QualifierAlignmentStyle &Value) {
+ IO.enumCase(Value, "Leave", FormatStyle::QAS_Leave);
+ IO.enumCase(Value, "Left", FormatStyle::QAS_Left);
+ IO.enumCase(Value, "Right", FormatStyle::QAS_Right);
+ IO.enumCase(Value, "Custom", FormatStyle::QAS_Custom);
+ }
+};
+
+template <> struct MappingTraits<FormatStyle::RawStringFormat> {
+ static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
+ IO.mapOptional("Language", Format.Language);
+ IO.mapOptional("Delimiters", Format.Delimiters);
+ IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
+ IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter);
+ IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
}
};
@@ -527,34 +509,79 @@ struct ScalarEnumerationTraits<FormatStyle::RequiresClausePositionStyle> {
};
template <>
-struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensStyle> {
- static void enumeration(IO &IO, FormatStyle::SpaceBeforeParensStyle &Value) {
- IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
- IO.enumCase(Value, "ControlStatements",
- FormatStyle::SBPO_ControlStatements);
- IO.enumCase(Value, "ControlStatementsExceptControlMacros",
- FormatStyle::SBPO_ControlStatementsExceptControlMacros);
- IO.enumCase(Value, "NonEmptyParentheses",
- FormatStyle::SBPO_NonEmptyParentheses);
- IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
- IO.enumCase(Value, "Custom", FormatStyle::SBPO_Custom);
+struct ScalarEnumerationTraits<FormatStyle::RequiresExpressionIndentationKind> {
+ static void
+ enumeration(IO &IO, FormatStyle::RequiresExpressionIndentationKind &Value) {
+ IO.enumCase(Value, "Keyword", FormatStyle::REI_Keyword);
+ IO.enumCase(Value, "OuterScope", FormatStyle::REI_OuterScope);
+ }
+};
- // For backward compatibility.
- IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
- IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
- IO.enumCase(Value, "ControlStatementsExceptForEachMacros",
- FormatStyle::SBPO_ControlStatementsExceptControlMacros);
+template <>
+struct ScalarEnumerationTraits<FormatStyle::ReturnTypeBreakingStyle> {
+ static void enumeration(IO &IO, FormatStyle::ReturnTypeBreakingStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::RTBS_None);
+ IO.enumCase(Value, "All", FormatStyle::RTBS_All);
+ IO.enumCase(Value, "TopLevel", FormatStyle::RTBS_TopLevel);
+ IO.enumCase(Value, "TopLevelDefinitions",
+ FormatStyle::RTBS_TopLevelDefinitions);
+ IO.enumCase(Value, "AllDefinitions", FormatStyle::RTBS_AllDefinitions);
}
};
template <>
-struct ScalarEnumerationTraits<FormatStyle::BitFieldColonSpacingStyle> {
- static void enumeration(IO &IO,
- FormatStyle::BitFieldColonSpacingStyle &Value) {
- IO.enumCase(Value, "Both", FormatStyle::BFCS_Both);
- IO.enumCase(Value, "None", FormatStyle::BFCS_None);
- IO.enumCase(Value, "Before", FormatStyle::BFCS_Before);
- IO.enumCase(Value, "After", FormatStyle::BFCS_After);
+struct ScalarEnumerationTraits<FormatStyle::SeparateDefinitionStyle> {
+ static void enumeration(IO &IO, FormatStyle::SeparateDefinitionStyle &Value) {
+ IO.enumCase(Value, "Leave", FormatStyle::SDS_Leave);
+ IO.enumCase(Value, "Always", FormatStyle::SDS_Always);
+ IO.enumCase(Value, "Never", FormatStyle::SDS_Never);
+ }
+};
+
+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);
+ IO.enumCase(Value, "false", FormatStyle::SFS_None);
+ IO.enumCase(Value, "All", FormatStyle::SFS_All);
+ IO.enumCase(Value, "true", FormatStyle::SFS_All);
+ IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
+ IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly);
+ IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::ShortIfStyle> {
+ static void enumeration(IO &IO, FormatStyle::ShortIfStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::SIS_Never);
+ IO.enumCase(Value, "WithoutElse", FormatStyle::SIS_WithoutElse);
+ IO.enumCase(Value, "OnlyFirstIf", FormatStyle::SIS_OnlyFirstIf);
+ IO.enumCase(Value, "AllIfsAndElse", FormatStyle::SIS_AllIfsAndElse);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "Always", FormatStyle::SIS_OnlyFirstIf);
+ IO.enumCase(Value, "false", FormatStyle::SIS_Never);
+ IO.enumCase(Value, "true", FormatStyle::SIS_WithoutElse);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::ShortLambdaStyle> {
+ static void enumeration(IO &IO, FormatStyle::ShortLambdaStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::SLS_None);
+ IO.enumCase(Value, "false", FormatStyle::SLS_None);
+ IO.enumCase(Value, "Empty", FormatStyle::SLS_Empty);
+ IO.enumCase(Value, "Inline", FormatStyle::SLS_Inline);
+ IO.enumCase(Value, "All", FormatStyle::SLS_All);
+ IO.enumCase(Value, "true", FormatStyle::SLS_All);
}
};
@@ -579,6 +606,71 @@ struct ScalarEnumerationTraits<FormatStyle::SortJavaStaticImportOptions> {
}
};
+template <>
+struct ScalarEnumerationTraits<FormatStyle::SortUsingDeclarationsOptions> {
+ static void enumeration(IO &IO,
+ FormatStyle::SortUsingDeclarationsOptions &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::SUD_Never);
+ IO.enumCase(Value, "Lexicographic", FormatStyle::SUD_Lexicographic);
+ IO.enumCase(Value, "LexicographicNumeric",
+ FormatStyle::SUD_LexicographicNumeric);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "false", FormatStyle::SUD_Never);
+ IO.enumCase(Value, "true", FormatStyle::SUD_LexicographicNumeric);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<FormatStyle::SpaceAroundPointerQualifiersStyle> {
+ static void
+ enumeration(IO &IO, FormatStyle::SpaceAroundPointerQualifiersStyle &Value) {
+ IO.enumCase(Value, "Default", FormatStyle::SAPQ_Default);
+ IO.enumCase(Value, "Before", FormatStyle::SAPQ_Before);
+ IO.enumCase(Value, "After", FormatStyle::SAPQ_After);
+ IO.enumCase(Value, "Both", FormatStyle::SAPQ_Both);
+ }
+};
+
+template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> {
+ static void mapping(IO &IO, FormatStyle::SpaceBeforeParensCustom &Spacing) {
+ IO.mapOptional("AfterControlStatements", Spacing.AfterControlStatements);
+ IO.mapOptional("AfterForeachMacros", Spacing.AfterForeachMacros);
+ IO.mapOptional("AfterFunctionDefinitionName",
+ Spacing.AfterFunctionDefinitionName);
+ IO.mapOptional("AfterFunctionDeclarationName",
+ Spacing.AfterFunctionDeclarationName);
+ IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros);
+ IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator);
+ IO.mapOptional("AfterRequiresInClause", Spacing.AfterRequiresInClause);
+ IO.mapOptional("AfterRequiresInExpression",
+ Spacing.AfterRequiresInExpression);
+ IO.mapOptional("BeforeNonEmptyParentheses",
+ Spacing.BeforeNonEmptyParentheses);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<FormatStyle::SpaceBeforeParensStyle> {
+ static void enumeration(IO &IO, FormatStyle::SpaceBeforeParensStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::SBPO_Never);
+ IO.enumCase(Value, "ControlStatements",
+ FormatStyle::SBPO_ControlStatements);
+ IO.enumCase(Value, "ControlStatementsExceptControlMacros",
+ FormatStyle::SBPO_ControlStatementsExceptControlMacros);
+ IO.enumCase(Value, "NonEmptyParentheses",
+ FormatStyle::SBPO_NonEmptyParentheses);
+ IO.enumCase(Value, "Always", FormatStyle::SBPO_Always);
+ IO.enumCase(Value, "Custom", FormatStyle::SBPO_Custom);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "false", FormatStyle::SBPO_Never);
+ IO.enumCase(Value, "true", FormatStyle::SBPO_ControlStatements);
+ IO.enumCase(Value, "ControlStatementsExceptForEachMacros",
+ FormatStyle::SBPO_ControlStatementsExceptControlMacros);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> {
static void enumeration(IO &IO, FormatStyle::SpacesInAnglesStyle &Value) {
IO.enumCase(Value, "Never", FormatStyle::SIAS_Never);
@@ -591,11 +683,86 @@ template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> {
}
};
+template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {
+ static void mapping(IO &IO, FormatStyle::SpacesInLineComment &Space) {
+ // Transform the maximum to signed, to parse "-1" correctly
+ int signedMaximum = static_cast<int>(Space.Maximum);
+ IO.mapOptional("Minimum", Space.Minimum);
+ IO.mapOptional("Maximum", signedMaximum);
+ Space.Maximum = static_cast<unsigned>(signedMaximum);
+
+ if (Space.Maximum != -1u)
+ Space.Minimum = std::min(Space.Minimum, Space.Maximum);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::TrailingCommaStyle> {
+ static void enumeration(IO &IO, FormatStyle::TrailingCommaStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::TCS_None);
+ IO.enumCase(Value, "Wrapped", FormatStyle::TCS_Wrapped);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<FormatStyle::TrailingCommentsAlignmentKinds> {
+ static void enumeration(IO &IO,
+ FormatStyle::TrailingCommentsAlignmentKinds &Value) {
+ IO.enumCase(Value, "Leave", FormatStyle::TCAS_Leave);
+ IO.enumCase(Value, "Always", FormatStyle::TCAS_Always);
+ IO.enumCase(Value, "Never", FormatStyle::TCAS_Never);
+ }
+};
+
+template <> struct MappingTraits<FormatStyle::TrailingCommentsAlignmentStyle> {
+ static void enumInput(IO &IO,
+ FormatStyle::TrailingCommentsAlignmentStyle &Value) {
+ IO.enumCase(Value, "Leave",
+ FormatStyle::TrailingCommentsAlignmentStyle(
+ {FormatStyle::TCAS_Leave, 1}));
+
+ IO.enumCase(Value, "Always",
+ FormatStyle::TrailingCommentsAlignmentStyle(
+ {FormatStyle::TCAS_Always, 1}));
+
+ IO.enumCase(Value, "Never",
+ FormatStyle::TrailingCommentsAlignmentStyle(
+ {FormatStyle::TCAS_Never, 1}));
+
+ // For backwards compatibility
+ IO.enumCase(Value, "true",
+ FormatStyle::TrailingCommentsAlignmentStyle(
+ {FormatStyle::TCAS_Always, 1}));
+ IO.enumCase(Value, "false",
+ FormatStyle::TrailingCommentsAlignmentStyle(
+ {FormatStyle::TCAS_Never, 1}));
+ }
+
+ static void mapping(IO &IO,
+ FormatStyle::TrailingCommentsAlignmentStyle &Value) {
+ IO.mapOptional("Kind", Value.Kind);
+ IO.mapOptional("OverEmptyLines", Value.OverEmptyLines);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
+ static void enumeration(IO &IO, FormatStyle::UseTabStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::UT_Never);
+ IO.enumCase(Value, "false", FormatStyle::UT_Never);
+ IO.enumCase(Value, "Always", FormatStyle::UT_Always);
+ IO.enumCase(Value, "true", FormatStyle::UT_Always);
+ IO.enumCase(Value, "ForIndentation", FormatStyle::UT_ForIndentation);
+ IO.enumCase(Value, "ForContinuationAndIndentation",
+ FormatStyle::UT_ForContinuationAndIndentation);
+ IO.enumCase(Value, "AlignWithSpaces", FormatStyle::UT_AlignWithSpaces);
+ }
+};
+
template <> struct MappingTraits<FormatStyle> {
static void mapping(IO &IO, FormatStyle &Style) {
// When reading, read the language first, we need it for getPredefinedStyle.
IO.mapOptional("Language", Style.Language);
+ StringRef BasedOnStyle;
if (IO.outputting()) {
StringRef Styles[] = {"LLVM", "Google", "Chromium", "Mozilla",
"WebKit", "GNU", "Microsoft"};
@@ -604,11 +771,11 @@ template <> struct MappingTraits<FormatStyle> {
if (getPredefinedStyle(StyleName, Style.Language, &PredefinedStyle) &&
Style == PredefinedStyle) {
IO.mapOptional("# BasedOnStyle", StyleName);
+ BasedOnStyle = StyleName;
break;
}
}
} else {
- StringRef BasedOnStyle;
IO.mapOptional("BasedOnStyle", BasedOnStyle);
if (!BasedOnStyle.empty()) {
FormatStyle::LanguageKind OldLanguage = Style.Language;
@@ -622,9 +789,39 @@ template <> struct MappingTraits<FormatStyle> {
}
}
+ // Initialize some variables used in the parsing. The using logic is at the
+ // end.
+
+ // For backward compatibility:
+ // The default value of ConstructorInitializerAllOnOneLineOrOnePerLine was
+ // false unless BasedOnStyle was Google or Chromium whereas that of
+ // AllowAllConstructorInitializersOnNextLine was always true, so the
+ // equivalent default value of PackConstructorInitializers is PCIS_NextLine
+ // for Google/Chromium or PCIS_BinPack otherwise. If the deprecated options
+ // had a non-default value while PackConstructorInitializers has a default
+ // value, set the latter to an equivalent non-default value if needed.
+ const bool IsGoogleOrChromium = BasedOnStyle.equals_insensitive("google") ||
+ BasedOnStyle.equals_insensitive("chromium");
+ bool OnCurrentLine = IsGoogleOrChromium;
+ bool OnNextLine = true;
+
+ bool BreakBeforeInheritanceComma = false;
+ bool BreakConstructorInitializersBeforeComma = false;
+
+ bool DeriveLineEnding = true;
+ bool UseCRLF = false;
+
// For backward compatibility.
if (!IO.outputting()) {
IO.mapOptional("AlignEscapedNewlinesLeft", Style.AlignEscapedNewlines);
+ IO.mapOptional("AllowAllConstructorInitializersOnNextLine", OnNextLine);
+ IO.mapOptional("BreakBeforeInheritanceComma",
+ BreakBeforeInheritanceComma);
+ IO.mapOptional("BreakConstructorInitializersBeforeComma",
+ BreakConstructorInitializersBeforeComma);
+ IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
+ OnCurrentLine);
+ IO.mapOptional("DeriveLineEnding", DeriveLineEnding);
IO.mapOptional("DerivePointerBinding", Style.DerivePointerAlignment);
IO.mapOptional("IndentFunctionDeclarationAfterType",
Style.IndentWrappedFunctionNames);
@@ -632,6 +829,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("PointerBindsToType", Style.PointerAlignment);
IO.mapOptional("SpaceAfterControlStatementKeyword",
Style.SpaceBeforeParens);
+ IO.mapOptional("UseCRLF", UseCRLF);
}
IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
@@ -651,40 +849,24 @@ template <> struct MappingTraits<FormatStyle> {
Style.AllowAllArgumentsOnNextLine);
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
Style.AllowAllParametersOfDeclarationOnNextLine);
- IO.mapOptional("AllowShortEnumsOnASingleLine",
- Style.AllowShortEnumsOnASingleLine);
IO.mapOptional("AllowShortBlocksOnASingleLine",
Style.AllowShortBlocksOnASingleLine);
IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
Style.AllowShortCaseLabelsOnASingleLine);
+ IO.mapOptional("AllowShortEnumsOnASingleLine",
+ Style.AllowShortEnumsOnASingleLine);
IO.mapOptional("AllowShortFunctionsOnASingleLine",
Style.AllowShortFunctionsOnASingleLine);
- IO.mapOptional("AllowShortLambdasOnASingleLine",
- Style.AllowShortLambdasOnASingleLine);
IO.mapOptional("AllowShortIfStatementsOnASingleLine",
Style.AllowShortIfStatementsOnASingleLine);
+ IO.mapOptional("AllowShortLambdasOnASingleLine",
+ Style.AllowShortLambdasOnASingleLine);
IO.mapOptional("AllowShortLoopsOnASingleLine",
Style.AllowShortLoopsOnASingleLine);
IO.mapOptional("AlwaysBreakAfterDefinitionReturnType",
Style.AlwaysBreakAfterDefinitionReturnType);
IO.mapOptional("AlwaysBreakAfterReturnType",
Style.AlwaysBreakAfterReturnType);
-
- // If AlwaysBreakAfterDefinitionReturnType was specified but
- // AlwaysBreakAfterReturnType was not, initialize the latter from the
- // former for backwards compatibility.
- if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
- Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
- if (Style.AlwaysBreakAfterDefinitionReturnType ==
- FormatStyle::DRTBS_All) {
- Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
- } else if (Style.AlwaysBreakAfterDefinitionReturnType ==
- FormatStyle::DRTBS_TopLevel) {
- Style.AlwaysBreakAfterReturnType =
- FormatStyle::RTBS_TopLevelDefinitions;
- }
- }
-
IO.mapOptional("AlwaysBreakBeforeMultilineStrings",
Style.AlwaysBreakBeforeMultilineStrings);
IO.mapOptional("AlwaysBreakTemplateDeclarations",
@@ -692,61 +874,32 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("AttributeMacros", Style.AttributeMacros);
IO.mapOptional("BinPackArguments", Style.BinPackArguments);
IO.mapOptional("BinPackParameters", Style.BinPackParameters);
+ IO.mapOptional("BitFieldColonSpacing", Style.BitFieldColonSpacing);
IO.mapOptional("BraceWrapping", Style.BraceWrapping);
+ IO.mapOptional("BreakAfterAttributes", Style.BreakAfterAttributes);
+ IO.mapOptional("BreakAfterJavaFieldAnnotations",
+ Style.BreakAfterJavaFieldAnnotations);
+ IO.mapOptional("BreakArrays", Style.BreakArrays);
IO.mapOptional("BreakBeforeBinaryOperators",
Style.BreakBeforeBinaryOperators);
IO.mapOptional("BreakBeforeConceptDeclarations",
Style.BreakBeforeConceptDeclarations);
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
-
- bool BreakBeforeInheritanceComma = false;
- IO.mapOptional("BreakBeforeInheritanceComma", BreakBeforeInheritanceComma);
- IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList);
- // If BreakBeforeInheritanceComma was specified but
- // BreakInheritance was not, initialize the latter from the
- // former for backwards compatibility.
- if (BreakBeforeInheritanceComma &&
- Style.BreakInheritanceList == FormatStyle::BILS_BeforeColon) {
- Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma;
- }
-
+ IO.mapOptional("BreakBeforeInlineASMColon",
+ Style.BreakBeforeInlineASMColon);
IO.mapOptional("BreakBeforeTernaryOperators",
Style.BreakBeforeTernaryOperators);
-
- bool BreakConstructorInitializersBeforeComma = false;
- IO.mapOptional("BreakConstructorInitializersBeforeComma",
- BreakConstructorInitializersBeforeComma);
IO.mapOptional("BreakConstructorInitializers",
Style.BreakConstructorInitializers);
- // If BreakConstructorInitializersBeforeComma was specified but
- // BreakConstructorInitializers was not, initialize the latter from the
- // former for backwards compatibility.
- if (BreakConstructorInitializersBeforeComma &&
- Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon) {
- Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
- }
-
- IO.mapOptional("BreakAfterJavaFieldAnnotations",
- Style.BreakAfterJavaFieldAnnotations);
+ IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList);
IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals);
IO.mapOptional("ColumnLimit", Style.ColumnLimit);
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
- IO.mapOptional("QualifierAlignment", Style.QualifierAlignment);
-
- // Default Order for Left/Right based Qualifier alignment.
- if (Style.QualifierAlignment == FormatStyle::QAS_Right)
- Style.QualifierOrder = {"type", "const", "volatile"};
- else if (Style.QualifierAlignment == FormatStyle::QAS_Left)
- Style.QualifierOrder = {"const", "volatile", "type"};
- else if (Style.QualifierAlignment == FormatStyle::QAS_Custom)
- IO.mapOptional("QualifierOrder", Style.QualifierOrder);
-
IO.mapOptional("CompactNamespaces", Style.CompactNamespaces);
IO.mapOptional("ConstructorInitializerIndentWidth",
Style.ConstructorInitializerIndentWidth);
IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle);
- IO.mapOptional("DeriveLineEnding", Style.DeriveLineEnding);
IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment);
IO.mapOptional("DisableFormat", Style.DisableFormat);
IO.mapOptional("EmptyLineAfterAccessModifier",
@@ -755,68 +908,35 @@ template <> struct MappingTraits<FormatStyle> {
Style.EmptyLineBeforeAccessModifier);
IO.mapOptional("ExperimentalAutoDetectBinPacking",
Style.ExperimentalAutoDetectBinPacking);
-
- IO.mapOptional("PackConstructorInitializers",
- Style.PackConstructorInitializers);
- // For backward compatibility:
- // The default value of ConstructorInitializerAllOnOneLineOrOnePerLine was
- // false unless BasedOnStyle was Google or Chromium whereas that of
- // AllowAllConstructorInitializersOnNextLine was always true, so the
- // equivalent default value of PackConstructorInitializers is PCIS_NextLine
- // for Google/Chromium or PCIS_BinPack otherwise. If the deprecated options
- // had a non-default value while PackConstructorInitializers has a default
- // value, set the latter to an equivalent non-default value if needed.
- StringRef BasedOn;
- IO.mapOptional("BasedOnStyle", BasedOn);
- const bool IsGoogleOrChromium = BasedOn.equals_insensitive("google") ||
- BasedOn.equals_insensitive("chromium");
- bool OnCurrentLine = IsGoogleOrChromium;
- bool OnNextLine = true;
- IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine",
- OnCurrentLine);
- IO.mapOptional("AllowAllConstructorInitializersOnNextLine", OnNextLine);
- if (!IsGoogleOrChromium) {
- if (Style.PackConstructorInitializers == FormatStyle::PCIS_BinPack &&
- OnCurrentLine) {
- Style.PackConstructorInitializers = OnNextLine
- ? FormatStyle::PCIS_NextLine
- : FormatStyle::PCIS_CurrentLine;
- }
- } else if (Style.PackConstructorInitializers ==
- FormatStyle::PCIS_NextLine) {
- if (!OnCurrentLine)
- Style.PackConstructorInitializers = FormatStyle::PCIS_BinPack;
- else if (!OnNextLine)
- Style.PackConstructorInitializers = FormatStyle::PCIS_CurrentLine;
- }
-
IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
IO.mapOptional("ForEachMacros", Style.ForEachMacros);
IO.mapOptional("IfMacros", Style.IfMacros);
-
IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks);
IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories);
IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex);
IO.mapOptional("IncludeIsMainSourceRegex",
Style.IncludeStyle.IncludeIsMainSourceRegex);
IO.mapOptional("IndentAccessModifiers", Style.IndentAccessModifiers);
- IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks);
+ IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
+ IO.mapOptional("IndentExternBlock", Style.IndentExternBlock);
IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels);
IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
- IO.mapOptional("IndentExternBlock", Style.IndentExternBlock);
IO.mapOptional("IndentRequiresClause", Style.IndentRequiresClause);
IO.mapOptional("IndentWidth", Style.IndentWidth);
IO.mapOptional("IndentWrappedFunctionNames",
Style.IndentWrappedFunctionNames);
IO.mapOptional("InsertBraces", Style.InsertBraces);
+ IO.mapOptional("InsertNewlineAtEOF", Style.InsertNewlineAtEOF);
IO.mapOptional("InsertTrailingCommas", Style.InsertTrailingCommas);
+ IO.mapOptional("IntegerLiteralSeparator", Style.IntegerLiteralSeparator);
IO.mapOptional("JavaImportGroups", Style.JavaImportGroups);
IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
Style.KeepEmptyLinesAtTheStartOfBlocks);
IO.mapOptional("LambdaBodyIndentation", Style.LambdaBodyIndentation);
+ IO.mapOptional("LineEnding", Style.LineEnding);
IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
@@ -829,6 +949,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
IO.mapOptional("ObjCSpaceBeforeProtocolList",
Style.ObjCSpaceBeforeProtocolList);
+ IO.mapOptional("PackConstructorInitializers",
+ Style.PackConstructorInitializers);
IO.mapOptional("PenaltyBreakAssignment", Style.PenaltyBreakAssignment);
IO.mapOptional("PenaltyBreakBeforeFirstCallParameter",
Style.PenaltyBreakBeforeFirstCallParameter);
@@ -841,17 +963,28 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("PenaltyBreakTemplateDeclaration",
Style.PenaltyBreakTemplateDeclaration);
IO.mapOptional("PenaltyExcessCharacter", Style.PenaltyExcessCharacter);
- IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
- Style.PenaltyReturnTypeOnItsOwnLine);
IO.mapOptional("PenaltyIndentedWhitespace",
Style.PenaltyIndentedWhitespace);
+ IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
+ Style.PenaltyReturnTypeOnItsOwnLine);
IO.mapOptional("PointerAlignment", Style.PointerAlignment);
IO.mapOptional("PPIndentWidth", Style.PPIndentWidth);
+ IO.mapOptional("QualifierAlignment", Style.QualifierAlignment);
+ // Default Order for Left/Right based Qualifier alignment.
+ if (Style.QualifierAlignment == FormatStyle::QAS_Right)
+ Style.QualifierOrder = {"type", "const", "volatile"};
+ else if (Style.QualifierAlignment == FormatStyle::QAS_Left)
+ Style.QualifierOrder = {"const", "volatile", "type"};
+ else if (Style.QualifierAlignment == FormatStyle::QAS_Custom)
+ IO.mapOptional("QualifierOrder", Style.QualifierOrder);
IO.mapOptional("RawStringFormats", Style.RawStringFormats);
IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment);
IO.mapOptional("ReflowComments", Style.ReflowComments);
IO.mapOptional("RemoveBracesLLVM", Style.RemoveBracesLLVM);
+ IO.mapOptional("RemoveSemicolon", Style.RemoveSemicolon);
IO.mapOptional("RequiresClausePosition", Style.RequiresClausePosition);
+ IO.mapOptional("RequiresExpressionIndentation",
+ Style.RequiresExpressionIndentation);
IO.mapOptional("SeparateDefinitionBlocks", Style.SeparateDefinitionBlocks);
IO.mapOptional("ShortNamespaceLines", Style.ShortNamespaceLines);
IO.mapOptional("SortIncludes", Style.SortIncludes);
@@ -861,6 +994,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("SpaceAfterLogicalNot", Style.SpaceAfterLogicalNot);
IO.mapOptional("SpaceAfterTemplateKeyword",
Style.SpaceAfterTemplateKeyword);
+ IO.mapOptional("SpaceAroundPointerQualifiers",
+ Style.SpaceAroundPointerQualifiers);
IO.mapOptional("SpaceBeforeAssignmentOperators",
Style.SpaceBeforeAssignmentOperators);
IO.mapOptional("SpaceBeforeCaseColon", Style.SpaceBeforeCaseColon);
@@ -872,10 +1007,10 @@ template <> struct MappingTraits<FormatStyle> {
Style.SpaceBeforeInheritanceColon);
IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
IO.mapOptional("SpaceBeforeParensOptions", Style.SpaceBeforeParensOptions);
- IO.mapOptional("SpaceAroundPointerQualifiers",
- Style.SpaceAroundPointerQualifiers);
IO.mapOptional("SpaceBeforeRangeBasedForLoopColon",
Style.SpaceBeforeRangeBasedForLoopColon);
+ IO.mapOptional("SpaceBeforeSquareBrackets",
+ Style.SpaceBeforeSquareBrackets);
IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock);
IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
IO.mapOptional("SpacesBeforeTrailingComments",
@@ -891,83 +1026,67 @@ template <> struct MappingTraits<FormatStyle> {
Style.SpacesInLineCommentPrefix);
IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
- IO.mapOptional("SpaceBeforeSquareBrackets",
- Style.SpaceBeforeSquareBrackets);
- IO.mapOptional("BitFieldColonSpacing", Style.BitFieldColonSpacing);
IO.mapOptional("Standard", Style.Standard);
IO.mapOptional("StatementAttributeLikeMacros",
Style.StatementAttributeLikeMacros);
IO.mapOptional("StatementMacros", Style.StatementMacros);
IO.mapOptional("TabWidth", Style.TabWidth);
IO.mapOptional("TypenameMacros", Style.TypenameMacros);
- IO.mapOptional("UseCRLF", Style.UseCRLF);
IO.mapOptional("UseTab", Style.UseTab);
IO.mapOptional("WhitespaceSensitiveMacros",
Style.WhitespaceSensitiveMacros);
- }
-};
-template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
- static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
- IO.mapOptional("AfterCaseLabel", Wrapping.AfterCaseLabel);
- IO.mapOptional("AfterClass", Wrapping.AfterClass);
- IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
- IO.mapOptional("AfterEnum", Wrapping.AfterEnum);
- IO.mapOptional("AfterFunction", Wrapping.AfterFunction);
- IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace);
- IO.mapOptional("AfterObjCDeclaration", Wrapping.AfterObjCDeclaration);
- IO.mapOptional("AfterStruct", Wrapping.AfterStruct);
- IO.mapOptional("AfterUnion", Wrapping.AfterUnion);
- IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock);
- IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch);
- IO.mapOptional("BeforeElse", Wrapping.BeforeElse);
- IO.mapOptional("BeforeLambdaBody", Wrapping.BeforeLambdaBody);
- IO.mapOptional("BeforeWhile", Wrapping.BeforeWhile);
- IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
- IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
- IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
- IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
- }
-};
+ // If AlwaysBreakAfterDefinitionReturnType was specified but
+ // AlwaysBreakAfterReturnType was not, initialize the latter from the
+ // former for backwards compatibility.
+ if (Style.AlwaysBreakAfterDefinitionReturnType != FormatStyle::DRTBS_None &&
+ Style.AlwaysBreakAfterReturnType == FormatStyle::RTBS_None) {
+ if (Style.AlwaysBreakAfterDefinitionReturnType ==
+ FormatStyle::DRTBS_All) {
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_AllDefinitions;
+ } else if (Style.AlwaysBreakAfterDefinitionReturnType ==
+ FormatStyle::DRTBS_TopLevel) {
+ Style.AlwaysBreakAfterReturnType =
+ FormatStyle::RTBS_TopLevelDefinitions;
+ }
+ }
-template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> {
- static void mapping(IO &IO, FormatStyle::SpaceBeforeParensCustom &Spacing) {
- IO.mapOptional("AfterControlStatements", Spacing.AfterControlStatements);
- IO.mapOptional("AfterForeachMacros", Spacing.AfterForeachMacros);
- IO.mapOptional("AfterFunctionDefinitionName",
- Spacing.AfterFunctionDefinitionName);
- IO.mapOptional("AfterFunctionDeclarationName",
- Spacing.AfterFunctionDeclarationName);
- IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros);
- IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator);
- IO.mapOptional("AfterRequiresInClause", Spacing.AfterRequiresInClause);
- IO.mapOptional("AfterRequiresInExpression",
- Spacing.AfterRequiresInExpression);
- IO.mapOptional("BeforeNonEmptyParentheses",
- Spacing.BeforeNonEmptyParentheses);
- }
-};
+ // If BreakBeforeInheritanceComma was specified but BreakInheritance was
+ // not, initialize the latter from the former for backwards compatibility.
+ if (BreakBeforeInheritanceComma &&
+ Style.BreakInheritanceList == FormatStyle::BILS_BeforeColon) {
+ Style.BreakInheritanceList = FormatStyle::BILS_BeforeComma;
+ }
-template <> struct MappingTraits<FormatStyle::RawStringFormat> {
- static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
- IO.mapOptional("Language", Format.Language);
- IO.mapOptional("Delimiters", Format.Delimiters);
- IO.mapOptional("EnclosingFunctions", Format.EnclosingFunctions);
- IO.mapOptional("CanonicalDelimiter", Format.CanonicalDelimiter);
- IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
- }
-};
+ // If BreakConstructorInitializersBeforeComma was specified but
+ // BreakConstructorInitializers was not, initialize the latter from the
+ // former for backwards compatibility.
+ if (BreakConstructorInitializersBeforeComma &&
+ Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon) {
+ Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
+ }
-template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {
- static void mapping(IO &IO, FormatStyle::SpacesInLineComment &Space) {
- // Transform the maximum to signed, to parse "-1" correctly
- int signedMaximum = static_cast<int>(Space.Maximum);
- IO.mapOptional("Minimum", Space.Minimum);
- IO.mapOptional("Maximum", signedMaximum);
- Space.Maximum = static_cast<unsigned>(signedMaximum);
+ if (!IsGoogleOrChromium) {
+ if (Style.PackConstructorInitializers == FormatStyle::PCIS_BinPack &&
+ OnCurrentLine) {
+ Style.PackConstructorInitializers = OnNextLine
+ ? FormatStyle::PCIS_NextLine
+ : FormatStyle::PCIS_CurrentLine;
+ }
+ } else if (Style.PackConstructorInitializers ==
+ FormatStyle::PCIS_NextLine) {
+ if (!OnCurrentLine)
+ Style.PackConstructorInitializers = FormatStyle::PCIS_BinPack;
+ else if (!OnNextLine)
+ Style.PackConstructorInitializers = FormatStyle::PCIS_CurrentLine;
+ }
- if (Space.Maximum != -1u)
- Space.Minimum = std::min(Space.Minimum, Space.Maximum);
+ if (Style.LineEnding == FormatStyle::LE_DeriveLF) {
+ if (!DeriveLineEnding)
+ Style.LineEnding = UseCRLF ? FormatStyle::LE_CRLF : FormatStyle::LE_LF;
+ else if (UseCRLF)
+ Style.LineEnding = FormatStyle::LE_DeriveCRLF;
+ }
}
};
@@ -1181,7 +1300,6 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
LLVMStyle.AlignArrayOfStructures = FormatStyle::AIAS_None;
LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
- LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AlignConsecutiveAssignments = {};
LLVMStyle.AlignConsecutiveAssignments.Enabled = false;
LLVMStyle.AlignConsecutiveAssignments.AcrossEmptyLines = false;
@@ -1191,12 +1309,15 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlignConsecutiveBitFields = {};
LLVMStyle.AlignConsecutiveDeclarations = {};
LLVMStyle.AlignConsecutiveMacros = {};
+ LLVMStyle.AlignTrailingComments = {};
+ LLVMStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Always;
+ LLVMStyle.AlignTrailingComments.OverEmptyLines = 0;
LLVMStyle.AllowAllArgumentsOnNextLine = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
- LLVMStyle.AllowShortEnumsOnASingleLine = true;
- LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
+ LLVMStyle.AllowShortEnumsOnASingleLine = true;
+ LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
@@ -1205,12 +1326,9 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_MultiLine;
LLVMStyle.AttributeMacros.push_back("__capability");
+ LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both;
LLVMStyle.BinPackArguments = true;
LLVMStyle.BinPackParameters = true;
- LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
- LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
- LLVMStyle.BreakBeforeTernaryOperators = true;
- LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false,
/*AfterClass=*/false,
/*AfterControlStatement=*/FormatStyle::BWACS_Never,
@@ -1229,8 +1347,14 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
/*SplitEmptyFunction=*/true,
/*SplitEmptyRecord=*/true,
/*SplitEmptyNamespace=*/true};
- LLVMStyle.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
+ LLVMStyle.BreakAfterAttributes = FormatStyle::ABS_Never;
LLVMStyle.BreakAfterJavaFieldAnnotations = false;
+ LLVMStyle.BreakArrays = true;
+ LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
+ LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
+ LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
+ LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
+ LLVMStyle.BreakBeforeTernaryOperators = true;
LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon;
LLVMStyle.BreakStringLiterals = true;
@@ -1240,16 +1364,11 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.ConstructorInitializerIndentWidth = 4;
LLVMStyle.ContinuationIndentWidth = 4;
LLVMStyle.Cpp11BracedListStyle = true;
-
- // Off by default Qualifier ordering
- LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
-
- LLVMStyle.DeriveLineEnding = true;
LLVMStyle.DerivePointerAlignment = false;
+ LLVMStyle.DisableFormat = false;
LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never;
LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock;
LLVMStyle.ExperimentalAutoDetectBinPacking = false;
- LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack;
LLVMStyle.FixNamespaceComments = true;
LLVMStyle.ForEachMacros.push_back("foreach");
LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
@@ -1264,44 +1383,43 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.IndentAccessModifiers = false;
LLVMStyle.IndentCaseLabels = false;
LLVMStyle.IndentCaseBlocks = false;
+ LLVMStyle.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
LLVMStyle.IndentGotoLabels = true;
LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
LLVMStyle.IndentRequiresClause = true;
- LLVMStyle.IndentWrappedFunctionNames = false;
LLVMStyle.IndentWidth = 2;
- LLVMStyle.PPIndentWidth = -1;
+ LLVMStyle.IndentWrappedFunctionNames = false;
LLVMStyle.InsertBraces = false;
+ LLVMStyle.InsertNewlineAtEOF = false;
LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
+ LLVMStyle.IntegerLiteralSeparator = {/*Binary=*/0, /*Decimal=*/0, /*Hex=*/0};
LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
LLVMStyle.JavaScriptWrapImports = true;
- LLVMStyle.TabWidth = 8;
+ LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
LLVMStyle.LambdaBodyIndentation = FormatStyle::LBI_Signature;
+ LLVMStyle.LineEnding = FormatStyle::LE_DeriveLF;
LLVMStyle.MaxEmptyLinesToKeep = 1;
- LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;
LLVMStyle.NamespaceIndentation = FormatStyle::NI_None;
LLVMStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Auto;
LLVMStyle.ObjCBlockIndentWidth = 2;
LLVMStyle.ObjCBreakBeforeNestedBlockParam = true;
LLVMStyle.ObjCSpaceAfterProperty = false;
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
+ LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack;
LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
+ LLVMStyle.PPIndentWidth = -1;
+ LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
+ LLVMStyle.ReflowComments = true;
+ LLVMStyle.RemoveBracesLLVM = false;
+ LLVMStyle.RemoveSemicolon = false;
LLVMStyle.RequiresClausePosition = FormatStyle::RCPS_OwnLine;
+ LLVMStyle.RequiresExpressionIndentation = FormatStyle::REI_OuterScope;
LLVMStyle.SeparateDefinitionBlocks = FormatStyle::SDS_Leave;
LLVMStyle.ShortNamespaceLines = 1;
- LLVMStyle.SpacesBeforeTrailingComments = 1;
- LLVMStyle.Standard = FormatStyle::LS_Latest;
- LLVMStyle.UseCRLF = false;
- LLVMStyle.UseTab = FormatStyle::UT_Never;
- LLVMStyle.ReflowComments = true;
- LLVMStyle.RemoveBracesLLVM = false;
- LLVMStyle.SpacesInParentheses = false;
- LLVMStyle.SpacesInSquareBrackets = false;
- LLVMStyle.SpaceInEmptyBlock = false;
- LLVMStyle.SpaceInEmptyParentheses = false;
- LLVMStyle.SpacesInContainerLiterals = true;
- LLVMStyle.SpacesInCStyleCastParentheses = false;
- LLVMStyle.SpacesInLineCommentPrefix = {/*Minimum=*/1, /*Maximum=*/-1u};
+ LLVMStyle.SortIncludes = FormatStyle::SI_CaseSensitive;
+ LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before;
+ LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric;
LLVMStyle.SpaceAfterCStyleCast = false;
LLVMStyle.SpaceAfterLogicalNot = false;
LLVMStyle.SpaceAfterTemplateKeyword = true;
@@ -1318,9 +1436,27 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.SpaceBeforeAssignmentOperators = true;
LLVMStyle.SpaceBeforeCpp11BracedList = false;
LLVMStyle.SpaceBeforeSquareBrackets = false;
- LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both;
+ LLVMStyle.SpaceInEmptyBlock = false;
+ LLVMStyle.SpaceInEmptyParentheses = false;
+ LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never;
+ LLVMStyle.SpacesInContainerLiterals = true;
+ LLVMStyle.SpacesInCStyleCastParentheses = false;
+ LLVMStyle.SpacesInLineCommentPrefix = {/*Minimum=*/1, /*Maximum=*/-1u};
+ LLVMStyle.SpacesInParentheses = false;
+ LLVMStyle.SpacesInSquareBrackets = false;
LLVMStyle.SpacesInConditionalStatement = false;
+ LLVMStyle.Standard = FormatStyle::LS_Latest;
+ LLVMStyle.StatementAttributeLikeMacros.push_back("Q_EMIT");
+ LLVMStyle.StatementMacros.push_back("Q_UNUSED");
+ LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION");
+ LLVMStyle.TabWidth = 8;
+ LLVMStyle.UseTab = FormatStyle::UT_Never;
+ LLVMStyle.WhitespaceSensitiveMacros.push_back("BOOST_PP_STRINGIZE");
+ LLVMStyle.WhitespaceSensitiveMacros.push_back("CF_SWIFT_NAME");
+ LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME");
+ LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE");
+ LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE");
LLVMStyle.PenaltyBreakAssignment = prec::Assignment;
LLVMStyle.PenaltyBreakComment = 300;
@@ -1333,24 +1469,20 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational;
LLVMStyle.PenaltyIndentedWhitespace = 0;
- LLVMStyle.DisableFormat = false;
- LLVMStyle.SortIncludes = FormatStyle::SI_CaseSensitive;
- LLVMStyle.SortJavaStaticImport = FormatStyle::SJSIO_Before;
- LLVMStyle.SortUsingDeclarations = true;
- LLVMStyle.StatementAttributeLikeMacros.push_back("Q_EMIT");
- LLVMStyle.StatementMacros.push_back("Q_UNUSED");
- LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION");
- LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE");
- LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE");
- LLVMStyle.WhitespaceSensitiveMacros.push_back("BOOST_PP_STRINGIZE");
- LLVMStyle.WhitespaceSensitiveMacros.push_back("NS_SWIFT_NAME");
- LLVMStyle.WhitespaceSensitiveMacros.push_back("CF_SWIFT_NAME");
-
// Defaults that differ when not C++.
- if (Language == FormatStyle::LK_TableGen)
+ switch (Language) {
+ case FormatStyle::LK_TableGen:
LLVMStyle.SpacesInContainerLiterals = false;
- if (LLVMStyle.isJson())
+ break;
+ case FormatStyle::LK_Json:
LLVMStyle.ColumnLimit = 0;
+ break;
+ case FormatStyle::LK_Verilog:
+ LLVMStyle.IndentCaseLabels = true;
+ break;
+ default:
+ break;
+ }
return LLVMStyle;
}
@@ -1438,7 +1570,8 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
if (Language == FormatStyle::LK_Java) {
GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign;
- GoogleStyle.AlignTrailingComments = false;
+ GoogleStyle.AlignTrailingComments = {};
+ GoogleStyle.AlignTrailingComments.Kind = FormatStyle::TCAS_Never;
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
GoogleStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
@@ -1586,7 +1719,8 @@ FormatStyle getWebKitStyle() {
Style.AccessModifierOffset = -4;
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Style.AlignOperands = FormatStyle::OAS_DontAlign;
- Style.AlignTrailingComments = false;
+ Style.AlignTrailingComments = {};
+ Style.AlignTrailingComments.Kind = FormatStyle::TCAS_Never;
Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
@@ -1653,7 +1787,7 @@ FormatStyle getNoStyle() {
FormatStyle NoStyle = getLLVMStyle();
NoStyle.DisableFormat = true;
NoStyle.SortIncludes = FormatStyle::SI_Never;
- NoStyle.SortUsingDeclarations = false;
+ NoStyle.SortUsingDeclarations = FormatStyle::SUD_Never;
return NoStyle;
}
@@ -1710,9 +1844,7 @@ ParseError validateQualifierOrder(FormatStyle *Style) {
}
// Ensure the list has 'type' in it.
- auto type = std::find(Style->QualifierOrder.begin(),
- Style->QualifierOrder.end(), "type");
- if (type == Style->QualifierOrder.end())
+ if (!llvm::is_contained(Style->QualifierOrder, "type"))
return ParseError::MissingQualifierType;
return ParseError::Success;
@@ -1798,13 +1930,13 @@ std::string configurationAsText(const FormatStyle &Style) {
return Stream.str();
}
-llvm::Optional<FormatStyle>
+std::optional<FormatStyle>
FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
if (!Styles)
- return None;
+ return std::nullopt;
auto It = Styles->find(Language);
if (It == Styles->end())
- return None;
+ return std::nullopt;
FormatStyle Style = It->second;
Style.StyleSet = *this;
return Style;
@@ -1823,7 +1955,7 @@ void FormatStyle::FormatStyleSet::Add(FormatStyle Style) {
void FormatStyle::FormatStyleSet::Clear() { Styles.reset(); }
-llvm::Optional<FormatStyle>
+std::optional<FormatStyle>
FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
return StyleSet.Get(Language);
}
@@ -1833,9 +1965,7 @@ namespace {
class BracesInserter : public TokenAnalyzer {
public:
BracesInserter(const Environment &Env, const FormatStyle &Style)
- : TokenAnalyzer(Env, Style) {
- this->Style.RemoveBracesLLVM = false;
- }
+ : TokenAnalyzer(Env, Style) {}
std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
@@ -1851,35 +1981,44 @@ private:
void insertBraces(SmallVectorImpl<AnnotatedLine *> &Lines,
tooling::Replacements &Result) {
const auto &SourceMgr = Env.getSourceManager();
+ int OpeningBraceSurplus = 0;
for (AnnotatedLine *Line : Lines) {
insertBraces(Line->Children, Result);
- if (!Line->Affected)
+ if (!Line->Affected && OpeningBraceSurplus == 0)
continue;
for (FormatToken *Token = Line->First; Token && !Token->Finalized;
Token = Token->Next) {
- if (Token->BraceCount == 0)
+ int BraceCount = Token->BraceCount;
+ if (BraceCount == 0)
continue;
std::string Brace;
- if (Token->BraceCount < 0) {
- assert(Token->BraceCount == -1);
- Brace = '{';
+ if (BraceCount < 0) {
+ assert(BraceCount == -1);
+ if (!Line->Affected)
+ break;
+ Brace = Token->is(tok::comment) ? "\n{" : "{";
+ ++OpeningBraceSurplus;
} else {
- Brace = '\n' + std::string(Token->BraceCount, '}');
+ if (OpeningBraceSurplus == 0)
+ break;
+ if (OpeningBraceSurplus < BraceCount)
+ BraceCount = OpeningBraceSurplus;
+ Brace = '\n' + std::string(BraceCount, '}');
+ OpeningBraceSurplus -= BraceCount;
}
Token->BraceCount = 0;
const auto Start = Token->Tok.getEndLoc();
cantFail(Result.add(tooling::Replacement(SourceMgr, Start, 0, Brace)));
}
}
+ assert(OpeningBraceSurplus == 0);
}
};
class BracesRemover : public TokenAnalyzer {
public:
BracesRemover(const Environment &Env, const FormatStyle &Style)
- : TokenAnalyzer(Env, Style) {
- this->Style.InsertBraces = false;
- }
+ : TokenAnalyzer(Env, Style) {}
std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
@@ -1895,31 +2034,85 @@ private:
void removeBraces(SmallVectorImpl<AnnotatedLine *> &Lines,
tooling::Replacements &Result) {
const auto &SourceMgr = Env.getSourceManager();
- bool EndsWithComment = false;
- for (AnnotatedLine *Line : Lines) {
+ const auto End = Lines.end();
+ for (auto I = Lines.begin(); I != End; ++I) {
+ const auto Line = *I;
removeBraces(Line->Children, Result);
- if (Line->Affected) {
- for (FormatToken *Token = Line->First; Token && !Token->Finalized;
- Token = Token->Next) {
- if (!Token->Optional)
- continue;
- assert(Token->isOneOf(tok::l_brace, tok::r_brace));
- assert(Token->Previous || Token == Line->First);
- const FormatToken *Next = Token->Next;
- assert(Next || Token == Line->Last);
- const auto Start =
- (!Token->Previous && EndsWithComment) ||
- (Next && !(Next->isOneOf(tok::kw_else, tok::comment) &&
- Next->NewlinesBefore > 0))
- ? Token->Tok.getLocation()
- : Token->WhitespaceRange.getBegin();
- const auto Range =
- CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc());
- cantFail(Result.add(tooling::Replacement(SourceMgr, Range, "")));
+ if (!Line->Affected)
+ continue;
+ const auto NextLine = I + 1 == End ? nullptr : I[1];
+ for (auto Token = Line->First; Token && !Token->Finalized;
+ Token = Token->Next) {
+ if (!Token->Optional)
+ continue;
+ if (!Token->isOneOf(tok::l_brace, tok::r_brace))
+ continue;
+ auto Next = Token->Next;
+ assert(Next || Token == Line->Last);
+ if (!Next && NextLine)
+ Next = NextLine->First;
+ SourceLocation Start;
+ if (Next && Next->NewlinesBefore == 0 && Next->isNot(tok::eof)) {
+ Start = Token->Tok.getLocation();
+ Next->WhitespaceRange = Token->WhitespaceRange;
+ } else {
+ Start = Token->WhitespaceRange.getBegin();
}
+ const auto Range =
+ CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc());
+ cantFail(Result.add(tooling::Replacement(SourceMgr, Range, "")));
+ }
+ }
+ }
+};
+
+class SemiRemover : public TokenAnalyzer {
+public:
+ SemiRemover(const Environment &Env, const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
+
+ std::pair<tooling::Replacements, unsigned>
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override {
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
+ tooling::Replacements Result;
+ removeSemi(AnnotatedLines, Result);
+ return {Result, 0};
+ }
+
+private:
+ void removeSemi(SmallVectorImpl<AnnotatedLine *> &Lines,
+ tooling::Replacements &Result) {
+ const auto &SourceMgr = Env.getSourceManager();
+ const auto End = Lines.end();
+ for (auto I = Lines.begin(); I != End; ++I) {
+ const auto Line = *I;
+ removeSemi(Line->Children, Result);
+ if (!Line->Affected)
+ continue;
+ const auto NextLine = I + 1 == End ? nullptr : I[1];
+ for (auto Token = Line->First; Token && !Token->Finalized;
+ Token = Token->Next) {
+ if (!Token->Optional)
+ continue;
+ if (Token->isNot(tok::semi))
+ continue;
+ auto Next = Token->Next;
+ assert(Next || Token == Line->Last);
+ if (!Next && NextLine)
+ Next = NextLine->First;
+ SourceLocation Start;
+ if (Next && Next->NewlinesBefore == 0 && Next->isNot(tok::eof)) {
+ Start = Token->Tok.getLocation();
+ Next->WhitespaceRange = Token->WhitespaceRange;
+ } else {
+ Start = Token->WhitespaceRange.getBegin();
+ }
+ const auto Range =
+ CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc());
+ cantFail(Result.add(tooling::Replacement(SourceMgr, Range, "")));
}
- assert(Line->Last);
- EndsWithComment = Line->Last->is(tok::comment);
}
}
};
@@ -2031,11 +2224,11 @@ public:
WhitespaceManager Whitespaces(
Env.getSourceManager(), Style,
- Style.DeriveLineEnding
+ Style.LineEnding > FormatStyle::LE_CRLF
? WhitespaceManager::inputUsesCRLF(
Env.getSourceManager().getBufferData(Env.getFileID()),
- Style.UseCRLF)
- : Style.UseCRLF);
+ Style.LineEnding == FormatStyle::LE_DeriveCRLF)
+ : Style.LineEnding == FormatStyle::LE_CRLF);
ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
Env.getSourceManager(), Whitespaces, Encoding,
BinPackInconclusiveFunctions);
@@ -2123,9 +2316,11 @@ private:
}
}
if (Style.DerivePointerAlignment) {
- Style.PointerAlignment = countVariableAlignments(AnnotatedLines) <= 0
- ? FormatStyle::PAS_Left
- : FormatStyle::PAS_Right;
+ const auto NetRightCount = countVariableAlignments(AnnotatedLines);
+ if (NetRightCount > 0)
+ Style.PointerAlignment = FormatStyle::PAS_Right;
+ else if (NetRightCount < 0)
+ Style.PointerAlignment = FormatStyle::PAS_Left;
Style.ReferenceAlignment = FormatStyle::RAS_Pointer;
}
if (Style.Standard == FormatStyle::LS_Auto) {
@@ -2533,7 +2728,7 @@ private:
"UIView",
};
- for (auto Line : AnnotatedLines) {
+ for (auto *Line : AnnotatedLines) {
if (Line->First && (Line->First->TokenText.startswith("#") ||
Line->First->TokenText == "__pragma" ||
Line->First->TokenText == "_Pragma")) {
@@ -2758,13 +2953,6 @@ static void sortCppIncludes(const FormatStyle &Style,
}
}
-namespace {
-
-const char CppIncludeRegexPattern[] =
- R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";
-
-} // anonymous namespace
-
tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
ArrayRef<tooling::Range> Ranges,
StringRef FileName,
@@ -2774,7 +2962,6 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
.StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM
.Default(0);
unsigned SearchFrom = 0;
- llvm::Regex IncludeRegex(CppIncludeRegexPattern);
SmallVector<StringRef, 4> Matches;
SmallVector<IncludeDirective, 16> IncludesInBlock;
@@ -2831,7 +3018,7 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
bool MergeWithNextLine = Trimmed.endswith("\\");
if (!FormattingOff && !MergeWithNextLine) {
- if (IncludeRegex.match(Line, &Matches)) {
+ if (tooling::HeaderIncludes::IncludeRegex.match(Line, &Matches)) {
StringRef IncludeName = Matches[2];
if (Line.contains("/*") && !Line.contains("*/")) {
// #include with a start of a block comment, but without the end.
@@ -3109,8 +3296,8 @@ namespace {
inline bool isHeaderInsertion(const tooling::Replacement &Replace) {
return Replace.getOffset() == UINT_MAX && Replace.getLength() == 0 &&
- llvm::Regex(CppIncludeRegexPattern)
- .match(Replace.getReplacementText());
+ tooling::HeaderIncludes::IncludeRegex.match(
+ Replace.getReplacementText());
}
inline bool isHeaderDeletion(const tooling::Replacement &Replace) {
@@ -3162,17 +3349,18 @@ fixCppIncludeInsertions(StringRef Code, const tooling::Replacements &Replaces,
}
}
- llvm::Regex IncludeRegex = llvm::Regex(CppIncludeRegexPattern);
llvm::SmallVector<StringRef, 4> Matches;
for (const auto &R : HeaderInsertions) {
auto IncludeDirective = R.getReplacementText();
- bool Matched = IncludeRegex.match(IncludeDirective, &Matches);
+ bool Matched =
+ tooling::HeaderIncludes::IncludeRegex.match(IncludeDirective, &Matches);
assert(Matched && "Header insertion replacement must have replacement text "
"'#include ...'");
(void)Matched;
auto IncludeName = Matches[2];
auto Replace =
- Includes.insert(IncludeName.trim("\"<>"), IncludeName.startswith("<"));
+ Includes.insert(IncludeName.trim("\"<>"), IncludeName.startswith("<"),
+ tooling::IncludeDirective::Include);
if (Replace) {
auto Err = Result.add(*Replace);
if (Err) {
@@ -3203,7 +3391,7 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
// Make header insertion replacements insert new headers into correct blocks.
tooling::Replacements NewReplaces =
fixCppIncludeInsertions(Code, Replaces, Style);
- return processReplacements(Cleanup, Code, NewReplaces, Style);
+ return cantFail(processReplacements(Cleanup, Code, NewReplaces, Style));
}
namespace internal {
@@ -3215,6 +3403,9 @@ reformat(const FormatStyle &Style, StringRef Code,
FormatStyle Expanded = Style;
expandPresetsBraceWrapping(Expanded);
expandPresetsSpaceBeforeParens(Expanded);
+ Expanded.InsertBraces = false;
+ Expanded.RemoveBracesLLVM = false;
+ Expanded.RemoveSemicolon = false;
switch (Expanded.RequiresClausePosition) {
case FormatStyle::RCPS_SingleLine:
case FormatStyle::RCPS_WithPreceding:
@@ -3250,11 +3441,20 @@ reformat(const FormatStyle &Style, StringRef Code,
return {tooling::Replacements(), 0};
}
+ auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn,
+ NextStartColumn, LastStartColumn);
+ if (!Env)
+ return {};
+
typedef std::function<std::pair<tooling::Replacements, unsigned>(
const Environment &)>
AnalyzerPass;
SmallVector<AnalyzerPass, 8> Passes;
+ Passes.emplace_back([&](const Environment &Env) {
+ return IntegerLiteralSeparatorFixer().process(Env, Expanded);
+ });
+
if (Style.isCpp()) {
if (Style.QualifierAlignment != FormatStyle::QAS_Leave) {
Passes.emplace_back([&](const Environment &Env) {
@@ -3266,14 +3466,26 @@ reformat(const FormatStyle &Style, StringRef Code,
}
if (Style.InsertBraces) {
- Passes.emplace_back([&](const Environment &Env) {
- return BracesInserter(Env, Expanded).process();
+ FormatStyle S = Expanded;
+ S.InsertBraces = true;
+ Passes.emplace_back([&, S](const Environment &Env) {
+ return BracesInserter(Env, S).process(/*SkipAnnotation=*/true);
});
}
if (Style.RemoveBracesLLVM) {
- Passes.emplace_back([&](const Environment &Env) {
- return BracesRemover(Env, Expanded).process();
+ FormatStyle S = Expanded;
+ S.RemoveBracesLLVM = true;
+ Passes.emplace_back([&, S](const Environment &Env) {
+ return BracesRemover(Env, S).process(/*SkipAnnotation=*/true);
+ });
+ }
+
+ if (Style.RemoveSemicolon) {
+ FormatStyle S = Expanded;
+ S.RemoveSemicolon = true;
+ Passes.emplace_back([&, S](const Environment &Env) {
+ return SemiRemover(Env, S).process(/*SkipAnnotation=*/true);
});
}
@@ -3283,7 +3495,7 @@ reformat(const FormatStyle &Style, StringRef Code,
});
}
- if (Style.SortUsingDeclarations) {
+ if (Style.SortUsingDeclarations != FormatStyle::SUD_Never) {
Passes.emplace_back([&](const Environment &Env) {
return UsingDeclarationsSorter(Env, Expanded).process();
});
@@ -3299,7 +3511,7 @@ reformat(const FormatStyle &Style, StringRef Code,
if (Style.isJavaScript() &&
Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) {
Passes.emplace_back([&](const Environment &Env) {
- return JavaScriptRequoter(Env, Expanded).process();
+ return JavaScriptRequoter(Env, Expanded).process(/*SkipAnnotation=*/true);
});
}
@@ -3314,11 +3526,7 @@ reformat(const FormatStyle &Style, StringRef Code,
});
}
- auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn,
- NextStartColumn, LastStartColumn);
- if (!Env)
- return {};
- llvm::Optional<std::string> CurrentCode = None;
+ std::optional<std::string> CurrentCode;
tooling::Replacements Fixes;
unsigned Penalty = 0;
for (size_t I = 0, E = Passes.size(); I < E; ++I) {
diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp
index 832af463206c..f9f0d712bc16 100644
--- a/clang/lib/Format/FormatToken.cpp
+++ b/clang/lib/Format/FormatToken.cpp
@@ -56,7 +56,8 @@ bool FormatToken::isSimpleTypeSpecifier() const {
case tok::kw___ibm128:
case tok::kw_wchar_t:
case tok::kw_bool:
- case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case tok::annot_typename:
case tok::kw_char8_t:
case tok::kw_char16_t:
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 73e32979853f..9d055efd8007 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -20,6 +20,7 @@
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include <memory>
+#include <optional>
#include <unordered_set>
namespace clang {
@@ -39,7 +40,10 @@ namespace format {
TYPE(CastRParen) \
TYPE(ClassLBrace) \
TYPE(CompoundRequirementLBrace) \
+ /* ternary ?: expression */ \
TYPE(ConditionalExpr) \
+ /* the condition in an if statement */ \
+ TYPE(ConditionLParen) \
TYPE(ConflictAlternative) \
TYPE(ConflictEnd) \
TYPE(ConflictStart) \
@@ -67,6 +71,11 @@ namespace format {
TYPE(FunctionLBrace) \
TYPE(FunctionLikeOrFreestandingMacro) \
TYPE(FunctionTypeLParen) \
+ /* The colons as part of a C11 _Generic selection */ \
+ TYPE(GenericSelectionColon) \
+ /* The colon at the end of a goto label or a case label. Currently only used \
+ * for Verilog. */ \
+ TYPE(GotoLabelColon) \
TYPE(IfMacro) \
TYPE(ImplicitStringLiteral) \
TYPE(InheritanceColon) \
@@ -135,6 +144,16 @@ namespace format {
TYPE(UnaryOperator) \
TYPE(UnionLBrace) \
TYPE(UntouchableMacroFunc) \
+ /* like in begin : block */ \
+ TYPE(VerilogBlockLabelColon) \
+ /* The square bracket for the dimension part of the type name. \
+ * In 'logic [1:0] x[1:0]', only the first '['. This way we can have space \
+ * before the first bracket but not the second. */ \
+ TYPE(VerilogDimensionedTypeName) \
+ /* for the base in a number literal, not including the quote */ \
+ TYPE(VerilogNumberBase) \
+ /* Things inside the table in user-defined primitives. */ \
+ TYPE(VerilogTableItem) \
TYPE(Unknown)
/// Determines the semantic type of a syntactic token, e.g. whether "<" is a
@@ -231,7 +250,8 @@ struct FormatToken {
CanBreakBefore(false), ClosesTemplateDeclaration(false),
StartsBinaryExpression(false), EndsBinaryExpression(false),
PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false),
- Finalized(false), ClosesRequiresClause(false), BlockKind(BK_Unknown),
+ Finalized(false), ClosesRequiresClause(false),
+ EndsCppAttributeGroup(false), BlockKind(BK_Unknown),
Decision(FD_Unformatted), PackingKind(PPK_Inconclusive),
TypeIsFinalized(false), Type(TT_Unknown) {}
@@ -302,6 +322,9 @@ struct FormatToken {
/// \c true if this is the last token within requires clause.
unsigned ClosesRequiresClause : 1;
+ /// \c true if this token ends a group of C++ attributes.
+ unsigned EndsCppAttributeGroup : 1;
+
private:
/// Contains the kind of block if this token is a brace.
unsigned BlockKind : 2;
@@ -368,6 +391,9 @@ public:
}
bool isTypeFinalized() const { return TypeIsFinalized; }
+ /// Used to set an operator precedence explicitly.
+ prec::Level ForcedPrecedence = prec::Unknown;
+
/// The number of newlines immediately before the \c Token.
///
/// This can be used to determine what the user wrote in the original code
@@ -495,7 +521,7 @@ public:
// Contains all attributes related to how this token takes part
// in a configured macro expansion.
- llvm::Optional<MacroExpansion> MacroCtx;
+ std::optional<MacroExpansion> MacroCtx;
/// When macro expansion introduces nodes with children, those are marked as
/// \c MacroParent.
@@ -565,8 +591,12 @@ public:
}
bool isAccessSpecifier(bool ColonRequired = true) const {
- return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private) &&
- (!ColonRequired || (Next && Next->is(tok::colon)));
+ if (!isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private))
+ return false;
+ if (!ColonRequired)
+ return true;
+ const auto NextNonComment = getNextNonComment();
+ return NextNonComment && NextNonComment->is(tok::colon);
}
bool canBePointerOrReferenceQualifier() const {
@@ -577,9 +607,9 @@ public:
}
/// Determine whether the token is a simple-type-specifier.
- LLVM_NODISCARD bool isSimpleTypeSpecifier() const;
+ [[nodiscard]] bool isSimpleTypeSpecifier() const;
- LLVM_NODISCARD bool isTypeOrIdentifier() const;
+ [[nodiscard]] bool isTypeOrIdentifier() const;
bool isObjCAccessSpecifier() const {
return is(tok::at) && Next &&
@@ -658,7 +688,8 @@ public:
case tok::kw_static_assert:
case tok::kw__Atomic:
case tok::kw___attribute:
- case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case tok::kw_requires:
return true;
default:
@@ -697,12 +728,14 @@ public:
}
prec::Level getPrecedence() const {
+ if (ForcedPrecedence != prec::Unknown)
+ return ForcedPrecedence;
return getBinOpPrecedence(Tok.getKind(), /*GreaterThanIsOperator=*/true,
/*CPlusPlus11=*/true);
}
/// Returns the previous token ignoring comments.
- LLVM_NODISCARD FormatToken *getPreviousNonComment() const {
+ [[nodiscard]] FormatToken *getPreviousNonComment() const {
FormatToken *Tok = Previous;
while (Tok && Tok->is(tok::comment))
Tok = Tok->Previous;
@@ -710,7 +743,7 @@ public:
}
/// Returns the next token ignoring comments.
- LLVM_NODISCARD const FormatToken *getNextNonComment() const {
+ [[nodiscard]] const FormatToken *getNextNonComment() const {
const FormatToken *Tok = Next;
while (Tok && Tok->is(tok::comment))
Tok = Tok->Next;
@@ -719,7 +752,7 @@ public:
/// Returns \c true if this tokens starts a block-type list, i.e. a
/// list that should be indented with a block indent.
- LLVM_NODISCARD bool opensBlockOrBlockTypeList(const FormatStyle &Style) const;
+ [[nodiscard]] bool opensBlockOrBlockTypeList(const FormatStyle &Style) const;
/// Returns whether the token is the left square bracket of a C++
/// structured binding declaration.
@@ -988,6 +1021,7 @@ struct AdditionalKeywords {
kw_when = &IdentTable.get("when");
kw_where = &IdentTable.get("where");
+ // Verilog keywords
kw_always = &IdentTable.get("always");
kw_always_comb = &IdentTable.get("always_comb");
kw_always_ff = &IdentTable.get("always_ff");
@@ -1119,6 +1153,7 @@ struct AdditionalKeywords {
// Symbols that are treated as keywords.
kw_verilogHash = &IdentTable.get("#");
kw_verilogHashHash = &IdentTable.get("##");
+ kw_apostrophe = &IdentTable.get("\'");
// Keep this at the end of the constructor to make sure everything here
// is
@@ -1511,11 +1546,14 @@ struct AdditionalKeywords {
IdentifierInfo *kw_verilogHash;
IdentifierInfo *kw_verilogHashHash;
+ // Symbols in Verilog that don't exist in C++.
+ IdentifierInfo *kw_apostrophe;
+
/// Returns \c true if \p Tok is a keyword or an identifier.
bool isWordLike(const FormatToken &Tok) const {
// getIdentifierinfo returns non-null for keywords as well as identifiers.
return Tok.Tok.getIdentifierInfo() != nullptr &&
- !Tok.isOneOf(kw_verilogHash, kw_verilogHashHash);
+ !Tok.isOneOf(kw_verilogHash, kw_verilogHashHash, kw_apostrophe);
}
/// Returns \c true if \p Tok is a true JavaScript identifier, returns
@@ -1644,6 +1682,11 @@ struct AdditionalKeywords {
}
}
+ bool isVerilogWordOperator(const FormatToken &Tok) const {
+ return Tok.isOneOf(kw_before, kw_intersect, kw_dist, kw_iff, kw_inside,
+ kw_with);
+ }
+
bool isVerilogIdentifier(const FormatToken &Tok) const {
switch (Tok.Tok.getKind()) {
case tok::kw_case:
@@ -1724,10 +1767,29 @@ struct AdditionalKeywords {
kw_join_any, kw_join_none);
}
- /// Whether the token begins a block.
- bool isBlockBegin(const FormatToken &Tok, const FormatStyle &Style) const {
- return Tok.is(TT_MacroBlockBegin) ||
- (Style.isVerilog() ? isVerilogBegin(Tok) : Tok.is(tok::l_brace));
+ /// Returns whether \p Tok is a Verilog keyword that opens a module, etc.
+ bool isVerilogHierarchy(const FormatToken &Tok) const {
+ if (Tok.endsSequence(kw_function, kw_with))
+ return false;
+ if (Tok.is(kw_property)) {
+ const FormatToken *Prev = Tok.getPreviousNonComment();
+ return !(Prev &&
+ Prev->isOneOf(tok::kw_restrict, kw_assert, kw_assume, kw_cover));
+ }
+ return Tok.isOneOf(tok::kw_case, tok::kw_class, kw_function, kw_module,
+ kw_interface, kw_package, kw_casex, kw_casez, kw_checker,
+ kw_clocking, kw_covergroup, kw_macromodule, kw_primitive,
+ kw_program, kw_property, kw_randcase, kw_randsequence,
+ kw_task);
+ }
+
+ bool isVerilogEndOfLabel(const FormatToken &Tok) const {
+ const FormatToken *Next = Tok.getNextNonComment();
+ // In Verilog the colon in a default label is optional.
+ return Tok.is(TT_GotoLabelColon) ||
+ (Tok.is(tok::kw_default) &&
+ !(Next && Next->isOneOf(tok::colon, tok::semi, kw_clocking, kw_iff,
+ kw_input, kw_output, kw_sequence)));
}
private:
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index 3f9b68ccbb39..f8f5f7112188 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -193,6 +193,78 @@ void FormatTokenLexer::tryMergePreviousTokens() {
if (tryMergeTokens(JavaRightLogicalShiftAssign, TT_BinaryOperator))
return;
}
+
+ if (Style.isVerilog()) {
+ // Merge the number following a base like `'h?a0`.
+ if (Tokens.size() >= 3 && Tokens.end()[-3]->is(TT_VerilogNumberBase) &&
+ Tokens.end()[-2]->is(tok::numeric_constant) &&
+ Tokens.back()->isOneOf(tok::numeric_constant, tok::identifier,
+ tok::question) &&
+ tryMergeTokens(2, TT_Unknown)) {
+ return;
+ }
+ // Part select.
+ if (tryMergeTokensAny({{tok::minus, tok::colon}, {tok::plus, tok::colon}},
+ TT_BitFieldColon)) {
+ return;
+ }
+ // Xnor. The combined token is treated as a caret which can also be either a
+ // unary or binary operator. The actual type is determined in
+ // TokenAnnotator. We also check the token length so we know it is not
+ // already a merged token.
+ if (Tokens.back()->TokenText.size() == 1 &&
+ tryMergeTokensAny({{tok::caret, tok::tilde}, {tok::tilde, tok::caret}},
+ TT_BinaryOperator)) {
+ Tokens.back()->Tok.setKind(tok::caret);
+ return;
+ }
+ // Signed shift and distribution weight.
+ if (tryMergeTokens({tok::less, tok::less}, TT_BinaryOperator)) {
+ Tokens.back()->Tok.setKind(tok::lessless);
+ return;
+ }
+ if (tryMergeTokens({tok::greater, tok::greater}, TT_BinaryOperator)) {
+ Tokens.back()->Tok.setKind(tok::greatergreater);
+ return;
+ }
+ if (tryMergeTokensAny({{tok::lessless, tok::equal},
+ {tok::lessless, tok::lessequal},
+ {tok::greatergreater, tok::equal},
+ {tok::greatergreater, tok::greaterequal},
+ {tok::colon, tok::equal},
+ {tok::colon, tok::slash}},
+ TT_BinaryOperator)) {
+ Tokens.back()->ForcedPrecedence = prec::Assignment;
+ return;
+ }
+ // Exponentiation, signed shift, case equality, and wildcard equality.
+ if (tryMergeTokensAny({{tok::star, tok::star},
+ {tok::lessless, tok::less},
+ {tok::greatergreater, tok::greater},
+ {tok::exclaimequal, tok::equal},
+ {tok::exclaimequal, tok::question},
+ {tok::equalequal, tok::equal},
+ {tok::equalequal, tok::question}},
+ TT_BinaryOperator)) {
+ return;
+ }
+ // Module paths in specify blocks and implications in properties.
+ if (tryMergeTokensAny({{tok::plusequal, tok::greater},
+ {tok::plus, tok::star, tok::greater},
+ {tok::minusequal, tok::greater},
+ {tok::minus, tok::star, tok::greater},
+ {tok::less, tok::arrow},
+ {tok::equal, tok::greater},
+ {tok::star, tok::greater},
+ {tok::pipeequal, tok::greater},
+ {tok::pipe, tok::arrow},
+ {tok::hash, tok::minus, tok::hash},
+ {tok::hash, tok::equal, tok::hash}},
+ TT_BinaryOperator)) {
+ Tokens.back()->ForcedPrecedence = prec::Comma;
+ return;
+ }
+ }
}
bool FormatTokenLexer::tryMergeNSStringLiteral() {
@@ -240,36 +312,32 @@ bool FormatTokenLexer::tryMergeCSharpStringLiteral() {
return false;
// Look for @"aaaaaa" or $"aaaaaa".
- auto &String = *(Tokens.end() - 1);
- if (!String->is(tok::string_literal))
+ const auto String = *(Tokens.end() - 1);
+ if (String->isNot(tok::string_literal))
return false;
- auto &At = *(Tokens.end() - 2);
- if (!(At->is(tok::at) || At->TokenText == "$"))
+ auto Prefix = *(Tokens.end() - 2);
+ if (Prefix->isNot(tok::at) && Prefix->TokenText != "$")
return false;
- if (Tokens.size() > 2 && At->is(tok::at)) {
- auto &Dollar = *(Tokens.end() - 3);
- if (Dollar->TokenText == "$") {
- // This looks like $@"aaaaa" so we need to combine all 3 tokens.
- Dollar->Tok.setKind(tok::string_literal);
- Dollar->TokenText =
- StringRef(Dollar->TokenText.begin(),
- String->TokenText.end() - Dollar->TokenText.begin());
- Dollar->ColumnWidth += (At->ColumnWidth + String->ColumnWidth);
- Dollar->setType(TT_CSharpStringLiteral);
+ if (Tokens.size() > 2) {
+ const auto Tok = *(Tokens.end() - 3);
+ if ((Tok->TokenText == "$" && Prefix->is(tok::at)) ||
+ (Tok->is(tok::at) && Prefix->TokenText == "$")) {
+ // This looks like $@"aaa" or @$"aaa" so we need to combine all 3 tokens.
+ Tok->ColumnWidth += Prefix->ColumnWidth;
Tokens.erase(Tokens.end() - 2);
- Tokens.erase(Tokens.end() - 1);
- return true;
+ Prefix = Tok;
}
}
// Convert back into just a string_literal.
- At->Tok.setKind(tok::string_literal);
- At->TokenText = StringRef(At->TokenText.begin(),
- String->TokenText.end() - At->TokenText.begin());
- At->ColumnWidth += String->ColumnWidth;
- At->setType(TT_CSharpStringLiteral);
+ Prefix->Tok.setKind(tok::string_literal);
+ Prefix->TokenText =
+ StringRef(Prefix->TokenText.begin(),
+ String->TokenText.end() - Prefix->TokenText.begin());
+ Prefix->ColumnWidth += String->ColumnWidth;
+ Prefix->setType(TT_CSharpStringLiteral);
Tokens.erase(Tokens.end() - 1);
return true;
}
@@ -303,9 +371,11 @@ bool FormatTokenLexer::tryMergeNullishCoalescingEqual() {
bool FormatTokenLexer::tryMergeCSharpKeywordVariables() {
if (Tokens.size() < 2)
return false;
- auto &At = *(Tokens.end() - 2);
- auto &Keyword = *(Tokens.end() - 1);
- if (!At->is(tok::at))
+ const auto At = *(Tokens.end() - 2);
+ if (At->isNot(tok::at))
+ return false;
+ const auto Keyword = *(Tokens.end() - 1);
+ if (Keyword->TokenText == "$")
return false;
if (!Keywords.isCSharpKeyword(*Keyword))
return false;
@@ -412,15 +482,28 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
SmallVectorImpl<FormatToken *>::const_iterator First =
Tokens.end() - Kinds.size();
- if (!First[0]->is(Kinds[0]))
+ for (unsigned i = 0; i < Kinds.size(); ++i)
+ if (!First[i]->is(Kinds[i]))
+ return false;
+
+ return tryMergeTokens(Kinds.size(), NewType);
+}
+
+bool FormatTokenLexer::tryMergeTokens(size_t Count, TokenType NewType) {
+ if (Tokens.size() < Count)
return false;
+
+ SmallVectorImpl<FormatToken *>::const_iterator First = Tokens.end() - Count;
unsigned AddLength = 0;
- for (unsigned i = 1; i < Kinds.size(); ++i) {
- if (!First[i]->is(Kinds[i]) || First[i]->hasWhitespaceBefore())
+ for (size_t i = 1; i < Count; ++i) {
+ // If there is whitespace separating the token and the previous one,
+ // they should not be merged.
+ if (First[i]->hasWhitespaceBefore())
return false;
AddLength += First[i]->TokenText.size();
}
- Tokens.resize(Tokens.size() - Kinds.size() + 1);
+
+ Tokens.resize(Tokens.size() - Count + 1);
First[0]->TokenText = StringRef(First[0]->TokenText.data(),
First[0]->TokenText.size() + AddLength);
First[0]->ColumnWidth += AddLength;
@@ -428,6 +511,13 @@ bool FormatTokenLexer::tryMergeTokens(ArrayRef<tok::TokenKind> Kinds,
return true;
}
+bool FormatTokenLexer::tryMergeTokensAny(
+ ArrayRef<ArrayRef<tok::TokenKind>> Kinds, TokenType NewType) {
+ return llvm::any_of(Kinds, [this, NewType](ArrayRef<tok::TokenKind> Kinds) {
+ return tryMergeTokens(Kinds, NewType);
+ });
+}
+
// Returns \c true if \p Tok can only be followed by an operand in JavaScript.
bool FormatTokenLexer::precedesOperand(FormatToken *Tok) {
// NB: This is not entirely correct, as an r_paren can introduce an operand
@@ -591,7 +681,7 @@ void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
bool Verbatim = false;
bool Interpolated = false;
- if (TokenText.startswith(R"($@")")) {
+ if (TokenText.startswith(R"($@")") || TokenText.startswith(R"(@$")")) {
Verbatim = true;
Interpolated = true;
} else if (TokenText.startswith(R"(@")")) {
@@ -670,6 +760,7 @@ void FormatTokenLexer::handleTemplateStrings() {
for (; Offset != Lex->getBuffer().end(); ++Offset) {
if (Offset[0] == '`') {
StateStack.pop();
+ ++Offset;
break;
}
if (Offset[0] == '\\') {
@@ -678,12 +769,12 @@ void FormatTokenLexer::handleTemplateStrings() {
Offset[1] == '{') {
// '${' introduces an expression interpolation in the template string.
StateStack.push(LexerState::NORMAL);
- ++Offset;
+ Offset += 2;
break;
}
}
- StringRef LiteralText(TmplBegin, Offset - TmplBegin + 1);
+ StringRef LiteralText(TmplBegin, Offset - TmplBegin);
BacktickToken->setType(TT_TemplateString);
BacktickToken->Tok.setKind(tok::string_literal);
BacktickToken->TokenText = LiteralText;
@@ -704,9 +795,7 @@ void FormatTokenLexer::handleTemplateStrings() {
StartColumn, Style.TabWidth, Encoding);
}
- SourceLocation loc = Offset < Lex->getBuffer().end()
- ? Lex->getSourceLocation(Offset + 1)
- : SourceMgr.getLocForEndOfFile(ID);
+ SourceLocation loc = Lex->getSourceLocation(Offset);
resetLexer(SourceMgr.getFileOffset(loc));
}
@@ -935,7 +1024,7 @@ FormatToken *FormatTokenLexer::getNextToken() {
// the same as a single LF.
if (i + 1 < e && Text[i + 1] == '\n')
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case '\n':
++FormatTok->NewlinesBefore;
if (!InEscape)
@@ -1004,12 +1093,19 @@ FormatToken *FormatTokenLexer::getNextToken() {
}
if (Style.isVerilog()) {
+ static const llvm::Regex NumberBase("^s?[bdho]", llvm::Regex::IgnoreCase);
+ SmallVector<StringRef, 1> Matches;
// Verilog uses the backtick instead of the hash for preprocessor stuff.
// And it uses the hash for delays and parameter lists. In order to continue
// using `tok::hash` in other places, the backtick gets marked as the hash
// here. And in order to tell the backtick and hash apart for
// Verilog-specific stuff, the hash becomes an identifier.
- if (FormatTok->isOneOf(tok::hash, tok::hashhash)) {
+ if (FormatTok->is(tok::numeric_constant)) {
+ // In Verilog the quote is not part of a number.
+ auto Quote = FormatTok->TokenText.find('\'');
+ if (Quote != StringRef::npos)
+ truncateToken(Quote);
+ } else if (FormatTok->isOneOf(tok::hash, tok::hashhash)) {
FormatTok->Tok.setKind(tok::raw_identifier);
} else if (FormatTok->is(tok::raw_identifier)) {
if (FormatTok->TokenText == "`") {
@@ -1018,6 +1114,15 @@ FormatToken *FormatTokenLexer::getNextToken() {
} else if (FormatTok->TokenText == "``") {
FormatTok->Tok.setIdentifierInfo(nullptr);
FormatTok->Tok.setKind(tok::hashhash);
+ } else if (Tokens.size() > 0 &&
+ Tokens.back()->is(Keywords.kw_apostrophe) &&
+ NumberBase.match(FormatTok->TokenText, &Matches)) {
+ // In Verilog in a based number literal like `'b10`, there may be
+ // whitespace between `'b` and `10`. Therefore we handle the base and
+ // the rest of the number literal as two tokens. But if there is no
+ // space in the input code, we need to manually separate the two parts.
+ truncateToken(Matches[0].size());
+ FormatTok->setFinalizedType(TT_VerilogNumberBase);
}
}
}
@@ -1060,6 +1165,13 @@ FormatToken *FormatTokenLexer::getNextToken() {
StateStack.push(LexerState::TOKEN_STASHED);
}
+ if (Style.isVerilog() && Tokens.size() > 0 &&
+ Tokens.back()->is(TT_VerilogNumberBase) &&
+ FormatTok->Tok.isOneOf(tok::identifier, tok::question)) {
+ // Mark the number following a base like `'h?a0` as a number.
+ FormatTok->Tok.setKind(tok::numeric_constant);
+ }
+
// Now FormatTok is the next non-whitespace token.
StringRef Text = FormatTok->TokenText;
diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h
index bff2c181d81e..950305a37d68 100644
--- a/clang/lib/Format/FormatTokenLexer.h
+++ b/clang/lib/Format/FormatTokenLexer.h
@@ -60,7 +60,14 @@ private:
bool tryMergeForEach();
bool tryTransformTryUsageForC();
+ // Merge the most recently lexed tokens into a single token if their kinds are
+ // correct.
bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType);
+ // Merge without checking their kinds.
+ bool tryMergeTokens(size_t Count, TokenType NewType);
+ // Merge if their kinds match any one of Kinds.
+ bool tryMergeTokensAny(ArrayRef<ArrayRef<tok::TokenKind>> Kinds,
+ TokenType NewType);
// Returns \c true if \p Tok can only be followed by an operand in JavaScript.
bool precedesOperand(FormatToken *Tok);
diff --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
new file mode 100644
index 000000000000..ef07ab06760b
--- /dev/null
+++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
@@ -0,0 +1,199 @@
+//===--- IntegerLiteralSeparatorFixer.cpp -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements IntegerLiteralSeparatorFixer that fixes C++ integer
+/// literal separators.
+///
+//===----------------------------------------------------------------------===//
+
+#include "IntegerLiteralSeparatorFixer.h"
+
+namespace clang {
+namespace format {
+
+enum class Base { Binary, Decimal, Hex, Other };
+
+static Base getBase(const StringRef IntegerLiteral) {
+ assert(IntegerLiteral.size() > 1);
+
+ if (IntegerLiteral[0] > '0') {
+ assert(IntegerLiteral[0] <= '9');
+ return Base::Decimal;
+ }
+
+ assert(IntegerLiteral[0] == '0');
+
+ switch (IntegerLiteral[1]) {
+ case 'b':
+ case 'B':
+ return Base::Binary;
+ case 'x':
+ case 'X':
+ return Base::Hex;
+ default:
+ return Base::Other;
+ }
+}
+
+std::pair<tooling::Replacements, unsigned>
+IntegerLiteralSeparatorFixer::process(const Environment &Env,
+ const FormatStyle &Style) {
+ switch (Style.Language) {
+ case FormatStyle::LK_Cpp:
+ case FormatStyle::LK_ObjC:
+ Separator = '\'';
+ break;
+ case FormatStyle::LK_CSharp:
+ case FormatStyle::LK_Java:
+ case FormatStyle::LK_JavaScript:
+ Separator = '_';
+ break;
+ default:
+ return {};
+ }
+
+ const auto &Option = Style.IntegerLiteralSeparator;
+ const auto Binary = Option.Binary;
+ const auto Decimal = Option.Decimal;
+ const auto Hex = Option.Hex;
+ const bool SkipBinary = Binary == 0;
+ const bool SkipDecimal = Decimal == 0;
+ const bool SkipHex = Hex == 0;
+
+ if (SkipBinary && SkipDecimal && SkipHex)
+ return {};
+
+ const auto &SourceMgr = Env.getSourceManager();
+ AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());
+
+ const auto ID = Env.getFileID();
+ const auto LangOpts = getFormattingLangOpts(Style);
+ Lexer Lex(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, LangOpts);
+ Lex.SetCommentRetentionState(true);
+
+ Token Tok;
+ tooling::Replacements Result;
+
+ for (bool Skip = false; !Lex.LexFromRawLexer(Tok);) {
+ auto Length = Tok.getLength();
+ if (Length < 2)
+ continue;
+ auto Location = Tok.getLocation();
+ auto Text = StringRef(SourceMgr.getCharacterData(Location), Length);
+ if (Tok.is(tok::comment)) {
+ if (Text == "// clang-format off" || Text == "/* clang-format off */")
+ Skip = true;
+ else if (Text == "// clang-format on" || Text == "/* clang-format on */")
+ Skip = false;
+ continue;
+ }
+ if (Skip || Tok.isNot(tok::numeric_constant) || Text[0] == '.' ||
+ !AffectedRangeMgr.affectsCharSourceRange(
+ CharSourceRange::getCharRange(Location, Tok.getEndLoc()))) {
+ continue;
+ }
+ const auto B = getBase(Text);
+ const bool IsBase2 = B == Base::Binary;
+ const bool IsBase10 = B == Base::Decimal;
+ const bool IsBase16 = B == Base::Hex;
+ if ((IsBase2 && SkipBinary) || (IsBase10 && SkipDecimal) ||
+ (IsBase16 && SkipHex) || B == Base::Other) {
+ continue;
+ }
+ if ((IsBase10 && Text.find_last_of(".eEfFdDmM") != StringRef::npos) ||
+ (IsBase16 && Text.find_last_of(".pP") != StringRef::npos)) {
+ continue;
+ }
+ if (((IsBase2 && Binary < 0) || (IsBase10 && Decimal < 0) ||
+ (IsBase16 && Hex < 0)) &&
+ Text.find(Separator) == StringRef::npos) {
+ continue;
+ }
+ const auto Start = Text[0] == '0' ? 2 : 0;
+ auto End = Text.find_first_of("uUlLzZn");
+ if (End == StringRef::npos)
+ End = Length;
+ if (Start > 0 || End < Length) {
+ Length = End - Start;
+ Text = Text.substr(Start, Length);
+ }
+ auto DigitsPerGroup = Decimal;
+ if (IsBase2)
+ DigitsPerGroup = Binary;
+ else if (IsBase16)
+ DigitsPerGroup = Hex;
+ if (DigitsPerGroup > 0 && checkSeparator(Text, DigitsPerGroup))
+ continue;
+ if (Start > 0)
+ Location = Location.getLocWithOffset(Start);
+ cantFail(Result.add(tooling::Replacement(SourceMgr, Location, Length,
+ format(Text, DigitsPerGroup))));
+ }
+
+ return {Result, 0};
+}
+
+bool IntegerLiteralSeparatorFixer::checkSeparator(
+ const StringRef IntegerLiteral, int DigitsPerGroup) const {
+ assert(DigitsPerGroup > 0);
+
+ int I = 0;
+ for (auto C : llvm::reverse(IntegerLiteral)) {
+ if (C == Separator) {
+ if (I < DigitsPerGroup)
+ return false;
+ I = 0;
+ } else {
+ ++I;
+ if (I == DigitsPerGroup)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+std::string IntegerLiteralSeparatorFixer::format(const StringRef IntegerLiteral,
+ int DigitsPerGroup) const {
+ assert(DigitsPerGroup != 0);
+
+ std::string Formatted;
+
+ if (DigitsPerGroup < 0) {
+ for (auto C : IntegerLiteral)
+ if (C != Separator)
+ Formatted.push_back(C);
+ return Formatted;
+ }
+
+ int DigitCount = 0;
+ for (auto C : IntegerLiteral)
+ if (C != Separator)
+ ++DigitCount;
+
+ int Remainder = DigitCount % DigitsPerGroup;
+
+ int I = 0;
+ for (auto C : IntegerLiteral) {
+ if (C == Separator)
+ continue;
+ if (I == (Remainder > 0 ? Remainder : DigitsPerGroup)) {
+ Formatted.push_back(Separator);
+ I = 0;
+ Remainder = 0;
+ }
+ Formatted.push_back(C);
+ ++I;
+ }
+
+ return Formatted;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.h b/clang/lib/Format/IntegerLiteralSeparatorFixer.h
new file mode 100644
index 000000000000..156bf5c14fca
--- /dev/null
+++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.h
@@ -0,0 +1,38 @@
+//===--- IntegerLiteralSeparatorFixer.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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file declares IntegerLiteralSeparatorFixer that fixes C++ integer
+/// literal separators.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_INTEGERLITERALSEPARATORFIXER_H
+#define LLVM_CLANG_LIB_FORMAT_INTEGERLITERALSEPARATORFIXER_H
+
+#include "TokenAnalyzer.h"
+
+namespace clang {
+namespace format {
+
+class IntegerLiteralSeparatorFixer {
+public:
+ std::pair<tooling::Replacements, unsigned> process(const Environment &Env,
+ const FormatStyle &Style);
+
+private:
+ bool checkSeparator(const StringRef IntegerLiteral, int DigitsPerGroup) const;
+ std::string format(const StringRef IntegerLiteral, int DigitsPerGroup) const;
+
+ char Separator;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif
diff --git a/clang/lib/Format/MacroCallReconstructor.cpp b/clang/lib/Format/MacroCallReconstructor.cpp
index ccff183cf0da..1c295477a922 100644
--- a/clang/lib/Format/MacroCallReconstructor.cpp
+++ b/clang/lib/Format/MacroCallReconstructor.cpp
@@ -35,9 +35,8 @@ void forEachToken(const UnwrappedLine &Line, const T &Call,
for (const auto &N : Line.Tokens) {
Call(N.Tok, Parent, First);
First = false;
- for (const auto &Child : N.Children) {
+ for (const auto &Child : N.Children)
forEachToken(Child, Call, N.Tok);
- }
}
}
@@ -61,7 +60,8 @@ void MacroCallReconstructor::addLine(const UnwrappedLine &Line) {
UnwrappedLine MacroCallReconstructor::takeResult() && {
finalize();
- assert(Result.Tokens.size() == 1 && Result.Tokens.front()->Children.size() == 1);
+ assert(Result.Tokens.size() == 1 &&
+ Result.Tokens.front()->Children.size() == 1);
UnwrappedLine Final =
createUnwrappedLine(*Result.Tokens.front()->Children.front(), Level);
assert(!Final.Tokens.empty());
@@ -194,9 +194,8 @@ FormatToken *MacroCallReconstructor::getParentInResult(FormatToken *Parent) {
FormatToken *Mapped = SpelledParentToReconstructedParent.lookup(Parent);
if (!Mapped)
return Parent;
- for (; Mapped; Mapped = SpelledParentToReconstructedParent.lookup(Parent)) {
+ for (; Mapped; Mapped = SpelledParentToReconstructedParent.lookup(Parent))
Parent = Mapped;
- }
// If we use a different token than the parent in the expanded token stream
// as parent, mark it as a special parent, so the formatting code knows it
// needs to have its children formatted.
@@ -216,9 +215,8 @@ void MacroCallReconstructor::reconstruct(FormatToken *Token) {
// If the order of tokens in the expanded token stream is not the
// same as the order of tokens in the reconstructed stream, we need
// to reconstruct tokens that arrive later in the stream.
- if (Token->MacroCtx->Role != MR_Hidden) {
+ if (Token->MacroCtx->Role != MR_Hidden)
reconstructActiveCallUntil(Token);
- }
}
assert(!ActiveExpansions.empty());
if (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE) {
@@ -275,7 +273,7 @@ void MacroCallReconstructor::startReconstruction(FormatToken *Token) {
// Note that the token's expanded from stack is inside-to-outside, and the
// expansions for which this token is not the first are the outermost ones.
ArrayRef<FormatToken *> StartedMacros =
- makeArrayRef(Token->MacroCtx->ExpandedFrom)
+ ArrayRef(Token->MacroCtx->ExpandedFrom)
.drop_back(ActiveExpansions.size());
assert(StartedMacros.size() == Token->MacroCtx->StartOfExpansion);
// We reconstruct macro calls outside-to-inside.
@@ -334,9 +332,8 @@ void MacroCallReconstructor::endReconstruction(FormatToken *Token) {
bool PreviousLevel =
Token->MacroCtx &&
(ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size());
- if (!ClosingParen && !TrailingComment && !PreviousLevel) {
+ if (!ClosingParen && !TrailingComment && !PreviousLevel)
llvm::dbgs() << "At token: " << Token->TokenText << "\n";
- }
// In addition to the following cases, we can also run into this
// when a macro call had more arguments than expected; in that case,
// the comma and the remaining tokens in the macro call will potentially
@@ -392,9 +389,8 @@ bool MacroCallReconstructor::processNextReconstructed() {
++ActiveExpansions.back().SpelledI;
if (Token->MacroCtx) {
// Skip tokens that are not part of the macro call.
- if (Token->MacroCtx->Role == MR_Hidden) {
+ if (Token->MacroCtx->Role == MR_Hidden)
return false;
- }
// Skip tokens we already expanded during an inner reconstruction.
// For example, given: #define ID(x) {x}
// And the call: ID(ID(f))
@@ -403,9 +399,8 @@ bool MacroCallReconstructor::processNextReconstructed() {
// ID({f}) -> {{f}}
// We reconstruct f during the first reconstruction, and skip it during the
// second reconstruction.
- if (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size()) {
+ if (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size())
return false;
- }
}
// Tokens that do not have a macro context are tokens in that are part of the
// macro call that have not taken part in expansion.
diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp
index 61f17cae383e..cef8b36ff758 100644
--- a/clang/lib/Format/QualifierAlignmentFixer.cpp
+++ b/clang/lib/Format/QualifierAlignmentFixer.cpp
@@ -18,6 +18,7 @@
#include "llvm/Support/Regex.h"
#include <algorithm>
+#include <optional>
#define DEBUG_TYPE "format-qualifier-alignment-fixer"
@@ -66,7 +67,7 @@ std::pair<tooling::Replacements, unsigned> QualifierAlignmentFixer::analyze(
NextStartColumn, LastStartColumn);
if (!Env)
return {};
- llvm::Optional<std::string> CurrentCode = None;
+ std::optional<std::string> CurrentCode;
tooling::Replacements Fixes;
for (size_t I = 0, E = Passes.size(); I < E; ++I) {
std::pair<tooling::Replacements, unsigned> PassFixes = Passes[I](*Env);
@@ -413,6 +414,7 @@ tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier(
.Case("inline", tok::kw_inline)
.Case("constexpr", tok::kw_constexpr)
.Case("restrict", tok::kw_restrict)
+ .Case("friend", tok::kw_friend)
.Default(tok::identifier);
}
diff --git a/clang/lib/Format/TokenAnalyzer.cpp b/clang/lib/Format/TokenAnalyzer.cpp
index 0a775c0a87ed..77e403581a0d 100644
--- a/clang/lib/Format/TokenAnalyzer.cpp
+++ b/clang/lib/Format/TokenAnalyzer.cpp
@@ -97,7 +97,8 @@ TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style)
<< "\n");
}
-std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() {
+std::pair<tooling::Replacements, unsigned>
+TokenAnalyzer::process(bool SkipAnnotation) {
tooling::Replacements Result;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
IdentifierTable IdentTable(getFormattingLangOpts(Style));
@@ -121,7 +122,8 @@ std::pair<tooling::Replacements, unsigned> TokenAnalyzer::process() {
TokenAnnotator Annotator(Style, Lex.getKeywords());
for (const UnwrappedLine &Line : Lines) {
AnnotatedLines.push_back(new AnnotatedLine(Line));
- Annotator.annotate(*AnnotatedLines.back());
+ if (!SkipAnnotation)
+ Annotator.annotate(*AnnotatedLines.back());
}
std::pair<tooling::Replacements, unsigned> RunResult =
diff --git a/clang/lib/Format/TokenAnalyzer.h b/clang/lib/Format/TokenAnalyzer.h
index aaca518df41f..e5cc1287c616 100644
--- a/clang/lib/Format/TokenAnalyzer.h
+++ b/clang/lib/Format/TokenAnalyzer.h
@@ -89,7 +89,8 @@ class TokenAnalyzer : public UnwrappedLineConsumer {
public:
TokenAnalyzer(const Environment &Env, const FormatStyle &Style);
- std::pair<tooling::Replacements, unsigned> process();
+ std::pair<tooling::Replacements, unsigned>
+ process(bool SkipAnnotation = false);
protected:
virtual std::pair<tooling::Replacements, unsigned>
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 5991cf23d5dc..49c30ca78deb 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -71,6 +71,38 @@ static bool isKeywordWithCondition(const FormatToken &Tok) {
tok::kw_constexpr, tok::kw_catch);
}
+/// Returns \c true if the token starts a C++ attribute, \c false otherwise.
+static bool isCppAttribute(bool IsCpp, const FormatToken &Tok) {
+ if (!IsCpp || !Tok.startsSequence(tok::l_square, tok::l_square))
+ return false;
+ // The first square bracket is part of an ObjC array literal
+ if (Tok.Previous && Tok.Previous->is(tok::at))
+ return false;
+ const FormatToken *AttrTok = Tok.Next->Next;
+ if (!AttrTok)
+ return false;
+ // C++17 '[[using ns: foo, bar(baz, blech)]]'
+ // We assume nobody will name an ObjC variable 'using'.
+ if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon))
+ return true;
+ if (AttrTok->isNot(tok::identifier))
+ return false;
+ while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) {
+ // ObjC message send. We assume nobody will use : in a C++11 attribute
+ // specifier parameter, although this is technically valid:
+ // [[foo(:)]].
+ if (AttrTok->is(tok::colon) ||
+ AttrTok->startsSequence(tok::identifier, tok::identifier) ||
+ AttrTok->startsSequence(tok::r_paren, tok::identifier)) {
+ return false;
+ }
+ if (AttrTok->is(tok::ellipsis))
+ return true;
+ AttrTok = AttrTok->Next;
+ }
+ return AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square);
+}
+
/// A parser that gathers additional information about tokens.
///
/// The \c TokenAnnotator tries to match parenthesis and square brakets and
@@ -134,10 +166,9 @@ private:
// parameter cases, but should not alter program semantics.
if (CurrentToken->Next && CurrentToken->Next->is(tok::greater) &&
Left->ParentBracket != tok::less &&
- (isKeywordWithCondition(*Line.First) ||
- CurrentToken->getStartOfNonWhitespace() ==
- CurrentToken->Next->getStartOfNonWhitespace().getLocWithOffset(
- -1))) {
+ CurrentToken->getStartOfNonWhitespace() ==
+ CurrentToken->Next->getStartOfNonWhitespace().getLocWithOffset(
+ -1)) {
return false;
}
Left->MatchingParen = CurrentToken;
@@ -238,11 +269,13 @@ private:
}
bool StartsObjCMethodExpr = false;
- if (FormatToken *MaybeSel = OpeningParen.Previous) {
- // @selector( starts a selector.
- if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous &&
- MaybeSel->Previous->is(tok::at)) {
- StartsObjCMethodExpr = true;
+ if (!Style.isVerilog()) {
+ if (FormatToken *MaybeSel = OpeningParen.Previous) {
+ // @selector( starts a selector.
+ if (MaybeSel->isObjCAtKeyword(tok::objc_selector) &&
+ MaybeSel->Previous && MaybeSel->Previous->is(tok::at)) {
+ StartsObjCMethodExpr = true;
+ }
}
}
@@ -287,6 +320,12 @@ private:
} else if (isLambdaParameterList(&OpeningParen)) {
// This is a parameter list of a lambda expression.
Contexts.back().IsExpression = false;
+ } else if (OpeningParen.is(TT_RequiresExpressionLParen)) {
+ Contexts.back().IsExpression = false;
+ } else if (OpeningParen.Previous &&
+ OpeningParen.Previous->is(tok::kw__Generic)) {
+ Contexts.back().ContextType = Context::C11GenericSelection;
+ Contexts.back().IsExpression = true;
} else if (Line.InPPDirective &&
(!OpeningParen.Previous ||
!OpeningParen.Previous->is(tok::identifier))) {
@@ -300,7 +339,8 @@ private:
Contexts.back().ContextType = Context::ForEachMacro;
Contexts.back().IsExpression = false;
} else if (OpeningParen.Previous && OpeningParen.Previous->MatchingParen &&
- OpeningParen.Previous->MatchingParen->is(TT_ObjCBlockLParen)) {
+ OpeningParen.Previous->MatchingParen->isOneOf(
+ TT_ObjCBlockLParen, TT_FunctionTypeLParen)) {
Contexts.back().IsExpression = false;
} else if (!Line.MustBeDeclaration && !Line.InPPDirective) {
bool IsForOrCatch =
@@ -310,13 +350,15 @@ private:
}
// Infer the role of the l_paren based on the previous token if we haven't
- // detected one one yet.
+ // detected one yet.
if (PrevNonComment && OpeningParen.is(TT_Unknown)) {
if (PrevNonComment->is(tok::kw___attribute)) {
OpeningParen.setType(TT_AttributeParen);
} else if (PrevNonComment->isOneOf(TT_TypenameMacro, tok::kw_decltype,
- tok::kw_typeof, tok::kw__Atomic,
- tok::kw___underlying_type)) {
+ tok::kw_typeof,
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
+#include "clang/Basic/TransformTypeTraits.def"
+ tok::kw__Atomic)) {
OpeningParen.setType(TT_TypeDeclarationParen);
// decltype() and typeof() usually contain expressions.
if (PrevNonComment->isOneOf(tok::kw_decltype, tok::kw_typeof))
@@ -357,7 +399,8 @@ private:
FormatToken *Next = CurrentToken->Next;
if (PrevPrev && PrevPrev->is(tok::identifier) &&
Prev->isOneOf(tok::star, tok::amp, tok::ampamp) &&
- CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) {
+ CurrentToken->is(tok::identifier) &&
+ !Next->isOneOf(tok::equal, tok::l_brace)) {
Prev->setType(TT_BinaryOperator);
LookForDecls = false;
}
@@ -532,34 +575,7 @@ private:
}
bool isCpp11AttributeSpecifier(const FormatToken &Tok) {
- if (!Style.isCpp() || !Tok.startsSequence(tok::l_square, tok::l_square))
- return false;
- // The first square bracket is part of an ObjC array literal
- if (Tok.Previous && Tok.Previous->is(tok::at))
- return false;
- const FormatToken *AttrTok = Tok.Next->Next;
- if (!AttrTok)
- return false;
- // C++17 '[[using ns: foo, bar(baz, blech)]]'
- // We assume nobody will name an ObjC variable 'using'.
- if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon))
- return true;
- if (AttrTok->isNot(tok::identifier))
- return false;
- while (AttrTok && !AttrTok->startsSequence(tok::r_square, tok::r_square)) {
- // ObjC message send. We assume nobody will use : in a C++11 attribute
- // specifier parameter, although this is technically valid:
- // [[foo(:)]].
- if (AttrTok->is(tok::colon) ||
- AttrTok->startsSequence(tok::identifier, tok::identifier) ||
- AttrTok->startsSequence(tok::r_paren, tok::identifier)) {
- return false;
- }
- if (AttrTok->is(tok::ellipsis))
- return true;
- AttrTok = AttrTok->Next;
- }
- return AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square);
+ return isCppAttribute(Style.isCpp(), Tok);
}
bool parseSquare() {
@@ -582,8 +598,9 @@ private:
(Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
Contexts.back().ContextType == Context::TemplateArgument);
- bool IsCpp11AttributeSpecifier = isCpp11AttributeSpecifier(*Left) ||
- Contexts.back().InCpp11AttributeSpecifier;
+ const bool IsInnerSquare = Contexts.back().InCpp11AttributeSpecifier;
+ const bool IsCpp11AttributeSpecifier =
+ isCpp11AttributeSpecifier(*Left) || IsInnerSquare;
// Treat C# Attributes [STAThread] much like C++ attributes [[...]].
bool IsCSharpAttributeSpecifier =
@@ -618,6 +635,8 @@ private:
Left->setType(TT_InlineASMSymbolicNameLSquare);
} else if (IsCpp11AttributeSpecifier) {
Left->setType(TT_AttributeSquare);
+ if (!IsInnerSquare && Left->Previous)
+ Left->Previous->EndsCppAttributeGroup = false;
} else if (Style.isJavaScript() && Parent &&
Contexts.back().ContextKind == tok::l_brace &&
Parent->isOneOf(tok::l_brace, tok::comma)) {
@@ -691,8 +710,11 @@ private:
while (CurrentToken) {
if (CurrentToken->is(tok::r_square)) {
- if (IsCpp11AttributeSpecifier)
+ if (IsCpp11AttributeSpecifier) {
CurrentToken->setType(TT_AttributeSquare);
+ if (!IsInnerSquare)
+ CurrentToken->EndsCppAttributeGroup = true;
+ }
if (IsCSharpAttributeSpecifier) {
CurrentToken->setType(TT_AttributeSquare);
} else if (((CurrentToken->Next &&
@@ -761,7 +783,8 @@ private:
// Remember that this is a [[using ns: foo]] C++ attribute, so we
// don't add a space before the colon (unlike other colons).
CurrentToken->setType(TT_AttributeColon);
- } else if (Left->isOneOf(TT_ArraySubscriptLSquare,
+ } else if (!Style.isVerilog() && !Line.InPragmaDirective &&
+ Left->isOneOf(TT_ArraySubscriptLSquare,
TT_DesignatedInitializerLSquare)) {
Left->setType(TT_ObjCMethodExpr);
StartsObjCMethodExpr = true;
@@ -914,6 +937,10 @@ private:
bool consumeToken() {
FormatToken *Tok = CurrentToken;
next();
+ // In Verilog primitives' state tables, `:`, `?`, and `-` aren't normal
+ // operators.
+ if (Tok->is(TT_VerilogTableItem))
+ return true;
switch (Tok->Tok.getKind()) {
case tok::plus:
case tok::minus:
@@ -947,6 +974,25 @@ private:
Tok->setType(TT_CSharpNamedArgumentColon);
break;
}
+ } else if (Style.isVerilog() && Tok->isNot(TT_BinaryOperator)) {
+ // The distribution weight operators are labeled
+ // TT_BinaryOperator by the lexer.
+ if (Keywords.isVerilogEnd(*Tok->Previous) ||
+ Keywords.isVerilogBegin(*Tok->Previous)) {
+ Tok->setType(TT_VerilogBlockLabelColon);
+ } else if (Contexts.back().ContextKind == tok::l_square) {
+ Tok->setType(TT_BitFieldColon);
+ } else if (Contexts.back().ColonIsDictLiteral) {
+ Tok->setType(TT_DictLiteral);
+ } else if (Contexts.size() == 1) {
+ // In Verilog a case label doesn't have the case keyword. We
+ // assume a colon following an expression is a case label.
+ // Colons from ?: are annotated in parseConditional().
+ Tok->setType(TT_GotoLabelColon);
+ if (Line.Level > 1 || (!Line.InPPDirective && Line.Level > 0))
+ --Line.Level;
+ }
+ break;
}
if (Line.First->isOneOf(Keywords.kw_module, Keywords.kw_import) ||
Line.First->startsSequence(tok::kw_export, Keywords.kw_module) ||
@@ -991,6 +1037,8 @@ private:
}
} else if (Contexts.back().ColonIsForRangeExpr) {
Tok->setType(TT_RangeBasedForLoopColon);
+ } else if (Contexts.back().ContextType == Context::C11GenericSelection) {
+ Tok->setType(TT_GenericSelectionColon);
} else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
Tok->setType(TT_BitFieldColon);
} else if (Contexts.size() == 1 &&
@@ -1019,7 +1067,8 @@ private:
// This handles a special macro in ObjC code where selectors including
// the colon are passed as macro arguments.
Tok->setType(TT_ObjCMethodExpr);
- } else if (Contexts.back().ContextKind == tok::l_paren) {
+ } else if (Contexts.back().ContextKind == tok::l_paren &&
+ !Line.InPragmaDirective) {
Tok->setType(TT_InlineASMColon);
}
break;
@@ -1035,7 +1084,7 @@ private:
CurrentToken->isOneOf(tok::kw_constexpr, tok::identifier)) {
next();
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_while:
if (CurrentToken && CurrentToken->is(tok::l_paren)) {
next();
@@ -1082,7 +1131,7 @@ private:
!Contexts.back().IsExpression && !Line.startsWith(TT_ObjCProperty) &&
!Tok->isOneOf(TT_TypeDeclarationParen, TT_RequiresExpressionLParen) &&
(!Tok->Previous ||
- !Tok->Previous->isOneOf(tok::kw___attribute,
+ !Tok->Previous->isOneOf(tok::kw___attribute, TT_RequiresClause,
TT_LeadingJavaAnnotation))) {
Line.MightBeFunctionDecl = true;
}
@@ -1147,13 +1196,17 @@ private:
if (CurrentToken->isOneOf(tok::star, tok::amp))
CurrentToken->setType(TT_PointerOrReference);
consumeToken();
- if (CurrentToken && CurrentToken->is(tok::comma) &&
+ if (!CurrentToken)
+ continue;
+ if (CurrentToken->is(tok::comma) &&
CurrentToken->Previous->isNot(tok::kw_operator)) {
break;
}
- if (CurrentToken && CurrentToken->Previous->isOneOf(
- TT_BinaryOperator, TT_UnaryOperator, tok::comma,
- tok::star, tok::arrow, tok::amp, tok::ampamp)) {
+ if (CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator,
+ tok::comma, tok::star, tok::arrow,
+ tok::amp, tok::ampamp) ||
+ // User defined literal.
+ CurrentToken->Previous->TokenText.startswith("\"\"")) {
CurrentToken->Previous->setType(TT_OverloadedOperator);
}
}
@@ -1215,6 +1268,13 @@ private:
if (Contexts.back().ContextType == Context::ForEachMacro)
Contexts.back().IsExpression = true;
break;
+ case tok::kw_default:
+ // Unindent case labels.
+ if (Style.isVerilog() && Keywords.isVerilogEndOfLabel(*Tok) &&
+ (Line.Level > 1 || (!Line.InPPDirective && Line.Level > 0))) {
+ --Line.Level;
+ }
+ break;
case tok::identifier:
if (Tok->isOneOf(Keywords.kw___has_include,
Keywords.kw___has_include_next)) {
@@ -1224,6 +1284,8 @@ private:
Tok->Next->isNot(tok::l_paren)) {
Tok->setType(TT_CSharpGenericTypeConstraint);
parseCSharpGenericTypeConstraint();
+ if (Tok->getPreviousNonComment() == nullptr)
+ Line.IsContinuation = true;
}
break;
case tok::arrow:
@@ -1232,6 +1294,10 @@ private:
Tok->setType(TT_TrailingReturnArrow);
}
break;
+ case tok::eof:
+ if (Style.InsertNewlineAtEOF && Tok->NewlinesBefore == 0)
+ Tok->NewlinesBefore = 1;
+ break;
default:
break;
}
@@ -1298,11 +1364,12 @@ private:
if (CurrentToken &&
CurrentToken->isOneOf(Keywords.kw_mark, Keywords.kw_option,
Keywords.kw_region)) {
- bool IsMark = CurrentToken->is(Keywords.kw_mark);
+ bool IsMarkOrRegion =
+ CurrentToken->isOneOf(Keywords.kw_mark, Keywords.kw_region);
next();
next(); // Consume first token (so we fix leading whitespace).
while (CurrentToken) {
- if (IsMark || CurrentToken->Previous->is(TT_BinaryOperator))
+ if (IsMarkOrRegion || CurrentToken->Previous->is(TT_BinaryOperator))
CurrentToken->setType(TT_ImplicitStringLiteral);
next();
}
@@ -1390,7 +1457,7 @@ public:
if (!CurrentToken)
return LT_Invalid;
NonTemplateLess.clear();
- if (CurrentToken->is(tok::hash)) {
+ if (!Line.InMacroBody && CurrentToken->is(tok::hash)) {
// We were not yet allowed to use C++17 optional when this was being
// written. So we used LT_Invalid to mark that the line is not a
// preprocessor directive.
@@ -1405,8 +1472,8 @@ public:
IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo();
if ((Style.Language == FormatStyle::LK_Java &&
CurrentToken->is(Keywords.kw_package)) ||
- (Info && Info->getPPKeywordID() == tok::pp_import &&
- CurrentToken->Next &&
+ (!Style.isVerilog() && Info &&
+ Info->getPPKeywordID() == tok::pp_import && CurrentToken->Next &&
CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier,
tok::kw_static))) {
next();
@@ -1571,6 +1638,8 @@ private:
StructArrayInitializer,
// Like in `static_cast<int>`.
TemplateArgument,
+ // C11 _Generic selection.
+ C11GenericSelection,
} ContextType = Unknown;
};
@@ -1628,8 +1697,8 @@ private:
if (!Tok)
return false;
- if (Tok->isOneOf(tok::kw_class, tok::kw_enum, tok::kw_concept,
- tok::kw_struct, tok::kw_using)) {
+ if (Tok->isOneOf(tok::kw_class, tok::kw_enum, tok::kw_struct,
+ tok::kw_using)) {
return false;
}
@@ -1754,21 +1823,8 @@ private:
FormatToken *LeadingIdentifier =
Current.Previous->MatchingParen->Previous;
- // Differentiate a deduction guide by seeing the
- // > of the template prior to the leading identifier.
- if (LeadingIdentifier) {
- FormatToken *PriorLeadingIdentifier = LeadingIdentifier->Previous;
- // Skip back past explicit decoration
- if (PriorLeadingIdentifier &&
- PriorLeadingIdentifier->is(tok::kw_explicit)) {
- PriorLeadingIdentifier = PriorLeadingIdentifier->Previous;
- }
-
- return PriorLeadingIdentifier &&
- (PriorLeadingIdentifier->is(TT_TemplateCloser) ||
- PriorLeadingIdentifier->ClosesRequiresClause) &&
- LeadingIdentifier->TokenText == Current.Next->TokenText;
- }
+ return LeadingIdentifier &&
+ LeadingIdentifier->TokenText == Current.Next->TokenText;
}
}
return false;
@@ -1842,7 +1898,8 @@ private:
Current,
Contexts.back().CanBeExpression && Contexts.back().IsExpression,
Contexts.back().ContextType == Context::TemplateArgument));
- } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
+ } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret) ||
+ (Style.isVerilog() && Current.is(tok::pipe))) {
Current.setType(determinePlusMinusCaretUsage(Current));
if (Current.is(TT_UnaryOperator) && Current.is(tok::caret))
Contexts.back().CaretFound = true;
@@ -1886,7 +1943,7 @@ private:
!Current.Next->isBinaryOperator() &&
!Current.Next->isOneOf(tok::semi, tok::colon, tok::l_brace,
tok::comma, tok::period, tok::arrow,
- tok::coloncolon)) {
+ tok::coloncolon, tok::kw_noexcept)) {
if (FormatToken *AfterParen = Current.MatchingParen->Next) {
// Make sure this isn't the return type of an Obj-C block declaration
if (AfterParen->isNot(tok::caret)) {
@@ -1943,7 +2000,9 @@ private:
} else if (Current.isOneOf(tok::identifier, tok::kw_const, tok::kw_noexcept,
tok::kw_requires) &&
Current.Previous &&
- !Current.Previous->isOneOf(tok::equal, tok::at) &&
+ !Current.Previous->isOneOf(tok::equal, tok::at,
+ TT_CtorInitializerComma,
+ TT_CtorInitializerColon) &&
Line.MightBeFunctionDecl && Contexts.size() == 1) {
// Line.MightBeFunctionDecl can only be true after the parentheses of a
// function declaration have been found.
@@ -2029,6 +2088,12 @@ private:
if (PreviousNotConst->isSimpleTypeSpecifier())
return true;
+ // type[] a in Java
+ if (Style.Language == FormatStyle::LK_Java &&
+ PreviousNotConst->is(tok::r_square)) {
+ return true;
+ }
+
// const a = in JavaScript.
return Style.isJavaScript() && PreviousNotConst->is(tok::kw_const);
}
@@ -2066,6 +2131,9 @@ private:
if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen)
return false;
+ if (Tok.MatchingParen->is(TT_OverloadedOperatorLParen))
+ return false;
+
FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
if (LeftOfParens) {
// If there is a closing parenthesis left of the current
@@ -2110,7 +2178,7 @@ private:
// before the parentheses, this is unlikely to be a cast.
if (LeftOfParens->Tok.getIdentifierInfo() &&
!LeftOfParens->isOneOf(Keywords.kw_in, tok::kw_return, tok::kw_case,
- tok::kw_delete)) {
+ tok::kw_delete, tok::kw_throw)) {
return false;
}
@@ -2293,7 +2361,8 @@ private:
return TT_BinaryOperator;
if (!NextToken ||
- NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_noexcept) ||
+ NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_noexcept, tok::comma,
+ tok::r_paren) ||
NextToken->canBePointerOrReferenceQualifier() ||
(NextToken->is(tok::l_brace) && !NextToken->getNextNonComment())) {
return TT_PointerOrReference;
@@ -2326,28 +2395,19 @@ private:
// case, the matching `{` is on the same unwrapped line, so check for the
// presence of the matching brace to distinguish between those.
if (PrevToken->is(tok::r_brace) && Tok.is(tok::star) &&
- !PrevToken->MatchingParen)
+ !PrevToken->MatchingParen) {
return TT_PointerOrReference;
+ }
- // For "} &&"
- if (PrevToken->is(tok::r_brace) && Tok.is(tok::ampamp)) {
- const FormatToken *MatchingLBrace = PrevToken->MatchingParen;
-
- // We check whether there is a TemplateCloser(">") to indicate it's a
- // template or not. If it's not a template, "&&" is likely a reference
- // operator.
- // struct {} &&ref = {};
- if (!MatchingLBrace)
- return TT_PointerOrReference;
- FormatToken *BeforeLBrace = MatchingLBrace->getPreviousNonComment();
- if (!BeforeLBrace || BeforeLBrace->isNot(TT_TemplateCloser))
- return TT_PointerOrReference;
-
- // If it is a template, "&&" is a binary operator.
- // enable_if<>{} && ...
- return TT_BinaryOperator;
+ // if (Class* obj { function() })
+ if (PrevToken->Tok.isAnyIdentifier() && NextToken->Tok.isAnyIdentifier() &&
+ NextToken->Next && NextToken->Next->is(tok::l_brace)) {
+ return TT_PointerOrReference;
}
+ if (PrevToken->endsSequence(tok::r_square, tok::l_square, tok::kw_delete))
+ return TT_UnaryOperator;
+
if (PrevToken->Tok.isLiteral() ||
PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,
tok::kw_false, tok::r_brace)) {
@@ -2529,7 +2589,7 @@ public:
(Start->Previous &&
Start->Previous->isOneOf(TT_RequiresClause,
TT_RequiresClauseInARequiresExpression))
- ? [this](){
+ ? [this]() {
auto Ret = Current ? Current : Line.Last;
while (!Ret->ClosesRequiresClause && Ret->Previous)
Ret = Ret->Previous;
@@ -2584,13 +2644,19 @@ private:
}
if (Current->is(TT_BinaryOperator) || Current->is(tok::comma))
return Current->getPrecedence();
- if (Current->isOneOf(tok::period, tok::arrow))
+ if (Current->isOneOf(tok::period, tok::arrow) &&
+ Current->isNot(TT_TrailingReturnArrow)) {
return PrecedenceArrowAndPeriod;
+ }
if ((Style.Language == FormatStyle::LK_Java || Style.isJavaScript()) &&
Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements,
Keywords.kw_throws)) {
return 0;
}
+ // In Verilog case labels are not on separate lines straight out of
+ // UnwrappedLineParser. The colon is not part of an expression.
+ if (Style.isVerilog() && Current->is(tok::colon))
+ return 0;
}
return -1;
}
@@ -2670,15 +2736,18 @@ void TokenAnnotator::setCommentLineLevels(
NextNonCommentLine->First->NewlinesBefore <= 1 &&
NextNonCommentLine->First->OriginalColumn ==
Line->First->OriginalColumn) {
+ const bool PPDirectiveOrImportStmt =
+ NextNonCommentLine->Type == LT_PreprocessorDirective ||
+ NextNonCommentLine->Type == LT_ImportStatement;
+ if (PPDirectiveOrImportStmt)
+ Line->Type = LT_CommentAbovePPDirective;
// Align comments for preprocessor lines with the # in column 0 if
// preprocessor lines are not indented. Otherwise, align with the next
// line.
- Line->Level =
- (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
- (NextNonCommentLine->Type == LT_PreprocessorDirective ||
- NextNonCommentLine->Type == LT_ImportStatement))
- ? 0
- : NextNonCommentLine->Level;
+ Line->Level = Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
+ PPDirectiveOrImportStmt
+ ? 0
+ : NextNonCommentLine->Level;
} else {
NextNonCommentLine = Line->First->isNot(tok::r_brace) ? Line : nullptr;
}
@@ -2774,7 +2843,7 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
if (!Current.is(TT_StartOfName) || Current.NestingLevel != 0)
return false;
for (; Next; Next = Next->Next) {
- if (Next->is(TT_TemplateOpener)) {
+ if (Next->is(TT_TemplateOpener) && Next->MatchingParen) {
Next = Next->MatchingParen;
} else if (Next->is(tok::coloncolon)) {
Next = Next->Next;
@@ -2786,6 +2855,10 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
}
if (!Next->is(tok::identifier))
return false;
+ } else if (isCppAttribute(IsCpp, *Next)) {
+ Next = Next->MatchingParen;
+ if (!Next)
+ return false;
} else if (Next->is(tok::l_paren)) {
break;
} else {
@@ -2867,6 +2940,18 @@ bool TokenAnnotator::mustBreakForReturnType(const AnnotatedLine &Line) const {
return false;
}
+static bool mustBreakAfterAttributes(const FormatToken &Tok,
+ const FormatStyle &Style) {
+ switch (Style.BreakAfterAttributes) {
+ case FormatStyle::ABS_Always:
+ return true;
+ case FormatStyle::ABS_Leave:
+ return Tok.NewlinesBefore > 0;
+ default:
+ return false;
+ }
+}
+
void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
for (AnnotatedLine *ChildLine : Line.Children)
calculateFormattingInformation(*ChildLine);
@@ -2882,9 +2967,22 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
if (AlignArrayOfStructures)
calculateArrayInitializerColumnList(Line);
+ for (FormatToken *Tok = Current, *AfterLastAttribute = nullptr; Tok;
+ Tok = Tok->Next) {
+ if (isFunctionDeclarationName(Style.isCpp(), *Tok, Line)) {
+ Tok->setType(TT_FunctionDeclarationName);
+ if (AfterLastAttribute &&
+ mustBreakAfterAttributes(*AfterLastAttribute, Style)) {
+ AfterLastAttribute->MustBreakBefore = true;
+ Line.ReturnTypeWrapped = true;
+ }
+ break;
+ }
+ if (Tok->Previous->EndsCppAttributeGroup)
+ AfterLastAttribute = Tok;
+ }
+
while (Current) {
- if (isFunctionDeclarationName(Style.isCpp(), *Current, Line))
- Current->setType(TT_FunctionDeclarationName);
const FormatToken *Prev = Current->Previous;
if (Current->is(TT_LineComment)) {
if (Prev->is(BK_BracedInit) && Prev->opensScope()) {
@@ -3057,6 +3155,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(tok::semi))
return 0;
+ // Language specific handling.
if (Style.Language == FormatStyle::LK_Java) {
if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_throws))
return 1;
@@ -3076,13 +3175,16 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
// Prefer breaking call chains (".foo") over empty "{}", "[]" or "()".
if (Left.opensScope() && Right.closesScope())
return 200;
+ } else if (Style.isProto()) {
+ if (Right.is(tok::l_square))
+ return 1;
+ if (Right.is(tok::period))
+ return 500;
}
if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
return 1;
if (Right.is(tok::l_square)) {
- if (Style.Language == FormatStyle::LK_Proto)
- return 1;
if (Left.is(tok::r_square))
return 200;
// Slightly prefer formatting local lambda definitions like functions.
@@ -3095,10 +3197,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
}
}
- if (Left.is(tok::coloncolon) ||
- (Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto)) {
+ if (Left.is(tok::coloncolon))
return 500;
- }
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
Right.is(tok::kw_operator)) {
if (Line.startsWith(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
@@ -3117,7 +3217,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
return 160;
if (Left.is(TT_CastRParen))
return 100;
- if (Left.isOneOf(tok::kw_class, tok::kw_struct))
+ if (Left.isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union))
return 5000;
if (Left.is(tok::comment))
return 1000;
@@ -3193,7 +3293,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
return 100;
}
if (Left.is(tok::l_paren) && Left.Previous &&
- (Left.Previous->is(tok::kw_for) || Left.Previous->isIf())) {
+ (Left.Previous->isOneOf(tok::kw_for, tok::kw__Generic) ||
+ Left.Previous->isIf())) {
return 1000;
}
if (Left.is(tok::equal) && InFunctionDecl)
@@ -3281,6 +3382,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
!Right.isOneOf(tok::semi, tok::r_paren, tok::hashhash)) {
return true;
}
+ if (Left.is(tok::kw_throw) && Right.is(tok::l_paren) && Right.MatchingParen &&
+ Right.MatchingParen->is(TT_CastRParen)) {
+ return true;
+ }
if (Style.isJson() && Left.is(tok::string_literal) && Right.is(tok::colon))
return false;
if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java)
@@ -3310,6 +3415,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
}
}
+ // trailing return type 'auto': []() -> auto {}, auto foo() -> auto {}
+ if (Left.is(tok::kw_auto) && Right.isOneOf(TT_LambdaLBrace, TT_FunctionLBrace,
+ // function return type 'auto'
+ TT_FunctionTypeLParen)) {
+ return true;
+ }
+
// auto{x} auto(x)
if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace))
return false;
@@ -3362,7 +3474,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return false;
return !Style.Cpp11BracedListStyle;
}
- return false;
+ // Don't attempt to format operator<(), as it is handled later.
+ if (Right.isNot(TT_OverloadedOperatorLParen))
+ return false;
}
if (Right.is(tok::ellipsis)) {
return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous &&
@@ -3424,7 +3538,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Right.is(TT_BlockComment))
return true;
// foo() -> const Bar * override/final
- if (Right.isOneOf(Keywords.kw_override, Keywords.kw_final) &&
+ if (Right.isOneOf(Keywords.kw_override, Keywords.kw_final,
+ tok::kw_noexcept) &&
!Right.is(TT_StartOfName)) {
return true;
}
@@ -3591,7 +3706,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return true;
if (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch,
tok::kw_case, TT_ForEachMacro, TT_ObjCForIn) ||
- Left.isIf(Line.Type != LT_PreprocessorDirective)) {
+ Left.isIf(Line.Type != LT_PreprocessorDirective) ||
+ Right.is(TT_ConditionLParen)) {
return Style.SpaceBeforeParensOptions.AfterControlStatements ||
spaceRequiredBeforeParens(Right);
}
@@ -3977,8 +4093,16 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return true;
}
} else if (Style.isVerilog()) {
+ // Add space between things in a primitive's state table unless in a
+ // transition like `(0?)`.
+ if ((Left.is(TT_VerilogTableItem) &&
+ !Right.isOneOf(tok::r_paren, tok::semi)) ||
+ (Right.is(TT_VerilogTableItem) && Left.isNot(tok::l_paren))) {
+ const FormatToken *Next = Right.getNextNonComment();
+ return !(Next && Next->is(tok::r_paren));
+ }
// Don't add space within a delay like `#0`.
- if (!Left.is(TT_BinaryOperator) &&
+ if (Left.isNot(TT_BinaryOperator) &&
Left.isOneOf(Keywords.kw_verilogHash, Keywords.kw_verilogHashHash)) {
return false;
}
@@ -3991,6 +4115,31 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Left.MatchingParen->endsSequence(tok::l_paren, tok::at)))) {
return true;
}
+ // Don't add embedded spaces in a number literal like `16'h1?ax` or an array
+ // literal like `'{}`.
+ if (Left.is(Keywords.kw_apostrophe) ||
+ (Left.is(TT_VerilogNumberBase) && Right.is(tok::numeric_constant))) {
+ return false;
+ }
+ // Add space between the type name and dimension like `logic [1:0]`.
+ if (Right.is(tok::l_square) &&
+ Left.isOneOf(TT_VerilogDimensionedTypeName, Keywords.kw_function)) {
+ return true;
+ }
+ // Don't add spaces between a casting type and the quote or repetition count
+ // and the brace.
+ if ((Right.is(Keywords.kw_apostrophe) ||
+ (Right.is(BK_BracedInit) && Right.is(tok::l_brace))) &&
+ !(Left.isOneOf(Keywords.kw_assign, Keywords.kw_unique) ||
+ Keywords.isVerilogWordOperator(Left)) &&
+ (Left.isOneOf(tok::r_square, tok::r_paren, tok::r_brace,
+ tok::numeric_constant) ||
+ Keywords.isWordLike(Left))) {
+ return false;
+ }
+ // Add space in attribute like `(* ASYNC_REG = "TRUE" *)`.
+ if (Left.endsSequence(tok::star, tok::l_paren) && Right.is(tok::identifier))
+ return true;
}
if (Left.is(TT_ImplicitStringLiteral))
return Right.hasWhitespaceBefore();
@@ -4032,6 +4181,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Style.BitFieldColonSpacing == FormatStyle::BFCS_After;
}
if (Right.is(tok::colon)) {
+ if (Right.is(TT_GotoLabelColon) ||
+ (!Style.isVerilog() &&
+ Line.First->isOneOf(tok::kw_default, tok::kw_case))) {
+ return Style.SpaceBeforeCaseColon;
+ }
if (Line.First->isOneOf(tok::kw_default, tok::kw_case))
return Style.SpaceBeforeCaseColon;
const FormatToken *Next = Right.getNextNonComment();
@@ -4049,6 +4203,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return false;
if (Right.is(TT_CSharpNamedArgumentColon))
return false;
+ if (Right.is(TT_GenericSelectionColon))
+ return false;
if (Right.is(TT_BitFieldColon)) {
return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both ||
Style.BitFieldColonSpacing == FormatStyle::BFCS_Before;
@@ -4157,7 +4313,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return false;
}
if (Right.is(tok::less) && Left.isNot(tok::l_paren) &&
- Line.startsWith(tok::hash)) {
+ Line.Type == LT_ImportStatement) {
return true;
}
if (Right.is(TT_TrailingUnaryOperator))
@@ -4294,6 +4450,11 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
Right.Next->is(tok::string_literal)) {
return true;
}
+ } else if (Style.isVerilog()) {
+ // Break after labels. In Verilog labels don't have the 'case' keyword, so
+ // it is hard to identify them in UnwrappedLineParser.
+ if (!Keywords.isVerilogBegin(Right) && Keywords.isVerilogEndOfLabel(Left))
+ return true;
} else if (Style.Language == FormatStyle::LK_Cpp ||
Style.Language == FormatStyle::LK_ObjC ||
Style.Language == FormatStyle::LK_Proto ||
@@ -4310,18 +4471,27 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
// }
if (Left.is(TT_DictLiteral) && Left.is(tok::l_brace))
return true;
- // Always break after a JSON array opener.
- // [
- // ]
- if (Left.is(TT_ArrayInitializerLSquare) && Left.is(tok::l_square) &&
- !Right.is(tok::r_square)) {
- return true;
+ // Always break after a JSON array opener based on BreakArrays.
+ if ((Left.is(TT_ArrayInitializerLSquare) && Left.is(tok::l_square) &&
+ Right.isNot(tok::r_square)) ||
+ Left.is(tok::comma)) {
+ if (Right.is(tok::l_brace))
+ return true;
+ // scan to the right if an we see an object or an array inside
+ // then break.
+ for (const auto *Tok = &Right; Tok; Tok = Tok->Next) {
+ if (Tok->isOneOf(tok::l_brace, tok::l_square))
+ return true;
+ if (Tok->isOneOf(tok::r_brace, tok::r_square))
+ break;
+ }
+ return Style.BreakArrays;
}
- // Always break after successive entries.
- // 1,
- // 2
- if (Left.is(tok::comma))
- return true;
+ }
+
+ if (Line.startsWith(tok::kw_asm) && Right.is(TT_InlineASMColon) &&
+ Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always) {
+ return true;
}
// If the last token before a '}', ']', or ')' is a comma or a trailing
@@ -4784,7 +4954,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
//
// instead, even if it is longer by one line.
//
- // Note that this allows allows the "{" to go over the column limit
+ // Note that this allows the "{" to go over the column limit
// when the column limit is just between ":" and "{", but that does
// not happen too often and alternative formattings in this case are
// not much better.
@@ -4881,6 +5051,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
!Right.MatchingParen) {
return false;
}
+ auto Next = Right.Next;
+ if (Next && Next->is(tok::r_paren))
+ Next = Next->Next;
+ if (Next && Next->is(tok::l_paren))
+ return false;
const FormatToken *Previous = Right.MatchingParen->Previous;
return !(Previous && (Previous->is(tok::kw_for) || Previous->isIf()));
}
@@ -4961,7 +5136,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
}
void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) const {
- llvm::errs() << "AnnotatedTokens(L=" << Line.Level << "):\n";
+ llvm::errs() << "AnnotatedTokens(L=" << Line.Level << ", P=" << Line.PPLevel
+ << ", T=" << Line.Type << ", C=" << Line.IsContinuation
+ << "):\n";
const FormatToken *Tok = Line.First;
while (Tok) {
llvm::errs() << " M=" << Tok->MustBreakBefore
diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h
index 1be64ed6d3b5..354511b6323a 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -31,18 +31,23 @@ enum LineType {
LT_PreprocessorDirective,
LT_VirtualFunctionDecl,
LT_ArrayOfStructInitializer,
+ LT_CommentAbovePPDirective,
};
class AnnotatedLine {
public:
AnnotatedLine(const UnwrappedLine &Line)
: First(Line.Tokens.front().Tok), Level(Line.Level),
+ PPLevel(Line.PPLevel),
MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex),
MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex),
InPPDirective(Line.InPPDirective),
+ InPragmaDirective(Line.InPragmaDirective),
+ InMacroBody(Line.InMacroBody),
MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
IsMultiVariableDeclStmt(false), Affected(false),
LeadingEmptyLinesAffected(false), ChildrenAffected(false),
+ ReturnTypeWrapped(false), IsContinuation(Line.IsContinuation),
FirstStartColumn(Line.FirstStartColumn) {
assert(!Line.Tokens.empty());
@@ -125,9 +130,12 @@ public:
LineType Type;
unsigned Level;
+ unsigned PPLevel;
size_t MatchingOpeningBlockLineIndex;
size_t MatchingClosingBlockLineIndex;
bool InPPDirective;
+ bool InPragmaDirective;
+ bool InMacroBody;
bool MustBeDeclaration;
bool MightBeFunctionDecl;
bool IsMultiVariableDeclStmt;
@@ -143,6 +151,13 @@ public:
/// \c True if one of this line's children intersects with an input range.
bool ChildrenAffected;
+ /// \c True if breaking after last attribute group in function return type.
+ bool ReturnTypeWrapped;
+
+ /// \c True if this line should be indented by ContinuationIndent in addition
+ /// to the normal indention level.
+ bool IsContinuation;
+
unsigned FirstStartColumn;
private:
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index abeb93d23776..8e1d907208c0 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -60,16 +60,23 @@ public:
// Update the indent level cache size so that we can rely on it
// having the right size in adjustToUnmodifiedline.
skipLine(Line, /*UnknownIndent=*/true);
- if (Line.InPPDirective) {
- unsigned IndentWidth =
+ if (Style.IndentPPDirectives != FormatStyle::PPDIS_None &&
+ (Line.InPPDirective ||
+ (Style.IndentPPDirectives == FormatStyle::PPDIS_BeforeHash &&
+ Line.Type == LT_CommentAbovePPDirective))) {
+ unsigned PPIndentWidth =
(Style.PPIndentWidth >= 0) ? Style.PPIndentWidth : Style.IndentWidth;
- Indent = Line.Level * IndentWidth + AdditionalIndent;
+ Indent = Line.InMacroBody
+ ? Line.PPLevel * PPIndentWidth +
+ (Line.Level - Line.PPLevel) * Style.IndentWidth
+ : Line.Level * PPIndentWidth;
+ Indent += AdditionalIndent;
} else {
Indent = getIndent(Line.Level);
}
if (static_cast<int>(Indent) + Offset >= 0)
Indent += Offset;
- if (Line.First->is(TT_CSharpGenericTypeConstraint))
+ if (Line.IsContinuation)
Indent = Line.Level * Style.IndentWidth + Style.ContinuationIndentWidth;
}
@@ -641,6 +648,7 @@ private:
unsigned Length = 0;
bool EndsWithComment = false;
bool InPPDirective = I[0]->InPPDirective;
+ bool InMacroBody = I[0]->InMacroBody;
const unsigned Level = I[0]->Level;
for (; NumStmts < 3; ++NumStmts) {
if (I + 1 + NumStmts == E)
@@ -648,6 +656,8 @@ private:
const AnnotatedLine *Line = I[1 + NumStmts];
if (Line->InPPDirective != InPPDirective)
break;
+ if (Line->InMacroBody != InMacroBody)
+ break;
if (Line->First->isOneOf(tok::kw_case, tok::kw_default, tok::r_brace))
break;
if (Line->First->isOneOf(tok::kw_if, tok::kw_for, tok::kw_switch,
@@ -709,16 +719,23 @@ private:
if (Tok && Tok->is(tok::colon))
return 0;
}
- if (Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, tok::kw_do,
- tok::kw_try, tok::kw___try, tok::kw_catch,
- tok::kw___finally, tok::kw_for, TT_ForEachMacro,
- tok::r_brace, Keywords.kw___except)) {
- if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never)
- return 0;
- if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Empty &&
- !I[1]->First->is(tok::r_brace)) {
+
+ auto IsCtrlStmt = [](const auto &Line) {
+ return Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while,
+ tok::kw_do, tok::kw_for, TT_ForEachMacro);
+ };
+
+ const bool IsSplitBlock =
+ Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never ||
+ (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Empty &&
+ I[1]->First->isNot(tok::r_brace));
+
+ if (IsCtrlStmt(Line) ||
+ Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
+ tok::kw___finally, tok::r_brace,
+ Keywords.kw___except)) {
+ if (IsSplitBlock)
return 0;
- }
// Don't merge when we can't except the case when
// the control statement block is empty
if (!Style.AllowShortIfStatementsOnASingleLine &&
@@ -761,6 +778,11 @@ private:
}
if (Line.Last->is(tok::l_brace)) {
+ if (IsSplitBlock && Line.First == Line.Last &&
+ I > AnnotatedLines.begin() &&
+ (I[-1]->endsWith(tok::kw_else) || IsCtrlStmt(*I[-1]))) {
+ return 0;
+ }
FormatToken *Tok = I[1]->First;
auto ShouldMerge = [Tok]() {
if (Tok->isNot(tok::r_brace) || Tok->MustBreakBefore)
@@ -1297,7 +1319,7 @@ unsigned UnwrappedLineFormatter::format(
// We continue formatting unchanged lines to adjust their indent, e.g. if a
// scope was added. However, we need to carefully stop doing this when we
- // exit the scope of affected lines to prevent indenting a the entire
+ // exit the scope of affected lines to prevent indenting the entire
// remaining file if it currently missing a closing brace.
bool PreviousRBrace =
PreviousLine && PreviousLine->startsWith(tok::r_brace);
diff --git a/clang/lib/Format/UnwrappedLineFormatter.h b/clang/lib/Format/UnwrappedLineFormatter.h
index 3e33de07fa12..ee6d31de8c42 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.h
+++ b/clang/lib/Format/UnwrappedLineFormatter.h
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// Implements a combinartorial exploration of all the different
+/// Implements a combinatorial exploration of all the different
/// linebreaks unwrapped lines can be formatted in.
///
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 83b4f1e7991f..3e58b6f90559 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -41,13 +41,7 @@ public:
// Returns the token that would be returned by the next call to
// getNextToken().
- virtual FormatToken *peekNextToken() = 0;
-
- // Returns the token that would be returned after the next N calls to
- // getNextToken(). N needs to be greater than zero, and small enough that
- // there are still tokens. Check for tok::eof with N-1 before calling it with
- // N.
- virtual FormatToken *peekNextToken(int N) = 0;
+ virtual FormatToken *peekNextToken(bool SkipComment = false) = 0;
// Returns whether we are at the end of the file.
// This can be different from whether getNextToken() returned an eof token
@@ -64,6 +58,39 @@ public:
namespace {
+void printLine(llvm::raw_ostream &OS, const UnwrappedLine &Line,
+ StringRef Prefix = "", bool PrintText = false) {
+ OS << Prefix << "Line(" << Line.Level << ", FSC=" << Line.FirstStartColumn
+ << ")" << (Line.InPPDirective ? " MACRO" : "") << ": ";
+ bool NewLine = false;
+ for (std::list<UnwrappedLineNode>::const_iterator I = Line.Tokens.begin(),
+ E = Line.Tokens.end();
+ I != E; ++I) {
+ if (NewLine) {
+ OS << Prefix;
+ NewLine = false;
+ }
+ OS << I->Tok->Tok.getName() << "["
+ << "T=" << (unsigned)I->Tok->getType()
+ << ", OC=" << I->Tok->OriginalColumn << ", \"" << I->Tok->TokenText
+ << "\"] ";
+ for (SmallVectorImpl<UnwrappedLine>::const_iterator
+ CI = I->Children.begin(),
+ CE = I->Children.end();
+ CI != CE; ++CI) {
+ OS << "\n";
+ printLine(OS, *CI, (Prefix + " ").str());
+ NewLine = true;
+ }
+ }
+ if (!NewLine)
+ OS << "\n";
+}
+
+LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line) {
+ printLine(llvm::dbgs(), Line);
+}
+
class ScopedDeclarationState {
public:
ScopedDeclarationState(UnwrappedLine &Line, llvm::BitVector &Stack,
@@ -116,12 +143,14 @@ public:
TokenSource = this;
Line.Level = 0;
Line.InPPDirective = true;
+ // InMacroBody gets set after the `#define x` part.
}
~ScopedMacroState() override {
TokenSource = PreviousTokenSource;
ResetToken = Token;
Line.InPPDirective = false;
+ Line.InMacroBody = false;
Line.Level = PreviousLineLevel;
}
@@ -140,17 +169,10 @@ public:
return PreviousTokenSource->getPreviousToken();
}
- FormatToken *peekNextToken() override {
+ FormatToken *peekNextToken(bool SkipComment) override {
if (eof())
return &FakeEOF;
- return PreviousTokenSource->peekNextToken();
- }
-
- FormatToken *peekNextToken(int N) override {
- assert(N > 0);
- if (eof())
- return &FakeEOF;
- return PreviousTokenSource->peekNextToken(N);
+ return PreviousTokenSource->peekNextToken(SkipComment);
}
bool isEOF() override { return PreviousTokenSource->isEOF(); }
@@ -195,7 +217,9 @@ public:
PreBlockLine = std::move(Parser.Line);
Parser.Line = std::make_unique<UnwrappedLine>();
Parser.Line->Level = PreBlockLine->Level;
+ Parser.Line->PPLevel = PreBlockLine->PPLevel;
Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
+ Parser.Line->InMacroBody = PreBlockLine->InMacroBody;
}
~ScopedLineState() {
@@ -245,7 +269,7 @@ public:
: Tokens(Tokens), Position(-1) {}
FormatToken *getNextToken() override {
- if (Position >= 0 && Tokens[Position]->is(tok::eof)) {
+ if (Position >= 0 && isEOF()) {
LLVM_DEBUG({
llvm::dbgs() << "Next ";
dbgToken(Position);
@@ -264,8 +288,11 @@ public:
return Position > 0 ? Tokens[Position - 1] : nullptr;
}
- FormatToken *peekNextToken() override {
+ FormatToken *peekNextToken(bool SkipComment) override {
int Next = Position + 1;
+ if (SkipComment)
+ while (Tokens[Next]->is(tok::comment))
+ ++Next;
LLVM_DEBUG({
llvm::dbgs() << "Peeking ";
dbgToken(Next);
@@ -273,16 +300,6 @@ public:
return Tokens[Next];
}
- FormatToken *peekNextToken(int N) override {
- assert(N > 0);
- int Next = Position + N;
- LLVM_DEBUG({
- llvm::dbgs() << "Peeking (+" << (N - 1) << ") ";
- dbgToken(Next);
- });
- return Tokens[Next];
- }
-
bool isEOF() override { return Tokens[Position]->is(tok::eof); }
unsigned getPosition() override {
@@ -573,12 +590,16 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace,
break;
}
// Else, if it is 'default:', fall through to the case handling.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case tok::kw_case:
- if (Style.isJavaScript() && Line->MustBeDeclaration) {
- // A 'case: string' style field declaration.
- parseStructuralElement();
+ if (Style.isProto() || Style.isVerilog() ||
+ (Style.isJavaScript() && Line->MustBeDeclaration)) {
+ // Proto: there are no switch/case statements
+ // Verilog: Case labels don't have this word. We handle case
+ // labels including default in TokenAnnotator.
+ // JavaScript: A 'case: string' style field declaration.
+ ParseDefault();
break;
}
if (!SwitchLabelEncountered &&
@@ -597,7 +618,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace,
}
if (handleCppAttributes())
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
ParseDefault();
break;
@@ -733,7 +754,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
case tok::identifier:
if (!Tok->is(TT_StatementMacro))
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::at:
case tok::semi:
case tok::kw_if:
@@ -812,9 +833,18 @@ bool UnwrappedLineParser::mightFitOnOneLine(
auto Length = LastToken->TotalLength;
if (OpeningBrace) {
assert(OpeningBrace != Tokens.front().Tok);
+ if (auto Prev = OpeningBrace->Previous;
+ Prev && Prev->TotalLength + ColumnLimit == OpeningBrace->TotalLength) {
+ Length -= ColumnLimit;
+ }
Length -= OpeningBrace->TokenText.size() + 1;
}
+ if (const auto *FirstToken = Line.First; FirstToken->is(tok::r_brace)) {
+ assert(!OpeningBrace || OpeningBrace->is(TT_ControlStatementLBrace));
+ Length -= FirstToken->TokenText.size() + 1;
+ }
+
Index = 0;
for (auto &Token : Tokens) {
const auto &SavedToken = SavedTokens[Index++];
@@ -823,6 +853,9 @@ bool UnwrappedLineParser::mightFitOnOneLine(
delete SavedToken.Tok;
}
+ // If these change PPLevel needs to be used for get correct indentation.
+ assert(!Line.InMacroBody);
+ assert(!Line.InPPDirective);
return Line.Level * Style.IndentWidth + Length <= ColumnLimit;
}
@@ -839,8 +872,13 @@ FormatToken *UnwrappedLineParser::parseBlock(
}
};
+ // Whether this is a Verilog-specific block that has a special header like a
+ // module.
+ const bool VerilogHierarchy =
+ Style.isVerilog() && Keywords.isVerilogHierarchy(*FormatTok);
assert((FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) ||
- (Style.isVerilog() && Keywords.isVerilogBegin(*FormatTok))) &&
+ (Style.isVerilog() &&
+ (Keywords.isVerilogBegin(*FormatTok) || VerilogHierarchy))) &&
"'{' or macro block token expected");
FormatToken *Tok = FormatTok;
const bool FollowedByComment = Tokens->peekNextToken()->is(tok::comment);
@@ -850,14 +888,20 @@ FormatToken *UnwrappedLineParser::parseBlock(
// For Whitesmiths mode, jump to the next level prior to skipping over the
// braces.
- if (AddLevels > 0 && Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths)
+ if (!VerilogHierarchy && AddLevels > 0 &&
+ Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) {
++Line->Level;
+ }
size_t PPStartHash = computePPHash();
const unsigned InitialLevel = Line->Level;
- nextToken(/*LevelDifference=*/AddLevels);
- HandleVerilogBlockLabel();
+ if (VerilogHierarchy) {
+ AddLevels += parseVerilogHierarchyHeader();
+ } else {
+ nextToken(/*LevelDifference=*/AddLevels);
+ HandleVerilogBlockLabel();
+ }
// Bail out if there are too many levels. Otherwise, the stack might overflow.
if (Line->Level > 300)
@@ -899,6 +943,9 @@ FormatToken *UnwrappedLineParser::parseBlock(
return IfLBrace;
}
+ const bool IsFunctionRBrace =
+ FormatTok->is(tok::r_brace) && Tok->is(TT_FunctionLBrace);
+
auto RemoveBraces = [=]() mutable {
if (!SimpleBlock)
return false;
@@ -938,11 +985,24 @@ FormatToken *UnwrappedLineParser::parseBlock(
// Munch the closing brace.
nextToken(/*LevelDifference=*/-AddLevels);
+
+ // When this is a function block and there is an unnecessary semicolon
+ // afterwards then mark it as optional (so the RemoveSemi pass can get rid of
+ // it later).
+ if (Style.RemoveSemicolon && IsFunctionRBrace) {
+ while (FormatTok->is(tok::semi)) {
+ FormatTok->Optional = true;
+ nextToken();
+ }
+ }
+
HandleVerilogBlockLabel();
if (MacroBlock && FormatTok->is(tok::l_paren))
parseParens();
+ Line->Level = InitialLevel;
+
if (FormatTok->is(tok::kw_noexcept)) {
// A noexcept in a requires expression.
nextToken();
@@ -958,8 +1018,6 @@ FormatToken *UnwrappedLineParser::parseBlock(
if (MunchSemi && FormatTok->is(tok::semi))
nextToken();
- Line->Level = InitialLevel;
-
if (PPStartHash == PPEndHash) {
Line->MatchingOpeningBlockLineIndex = OpeningLineIndex;
if (OpeningLineIndex != UnwrappedLine::kInvalidIndex) {
@@ -1073,16 +1131,17 @@ void UnwrappedLineParser::parsePPDirective() {
parsePPIf(/*IfDef=*/true);
break;
case tok::pp_else:
- parsePPElse();
- break;
case tok::pp_elifdef:
case tok::pp_elifndef:
case tok::pp_elif:
- parsePPElIf();
+ parsePPElse();
break;
case tok::pp_endif:
parsePPEndIf();
break;
+ case tok::pp_pragma:
+ parsePPPragma();
+ break;
default:
parsePPUnknown();
break;
@@ -1109,7 +1168,7 @@ void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) {
PPLevelBranchIndex.push_back(0);
PPLevelBranchCount.push_back(0);
}
- PPChainBranchIndex.push(0);
+ PPChainBranchIndex.push(Unreachable ? -1 : 0);
bool Skip = PPLevelBranchIndex[PPBranchLevel] > 0;
conditionalCompilationCondition(Unreachable || Skip);
}
@@ -1175,15 +1234,16 @@ void UnwrappedLineParser::parsePPElse() {
// If a potential include guard has an #else, it's not an include guard.
if (IncludeGuard == IG_Defined && PPBranchLevel == 0)
IncludeGuard = IG_Rejected;
+ // Don't crash when there is an #else without an #if.
+ assert(PPBranchLevel >= -1);
+ if (PPBranchLevel == -1)
+ conditionalCompilationStart(/*Unreachable=*/true);
conditionalCompilationAlternative();
- if (PPBranchLevel > -1)
- --PPBranchLevel;
+ --PPBranchLevel;
parsePPUnknown();
++PPBranchLevel;
}
-void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
-
void UnwrappedLineParser::parsePPEndIf() {
conditionalCompilationEnd();
parsePPUnknown();
@@ -1234,6 +1294,10 @@ void UnwrappedLineParser::parsePPDefine() {
addUnwrappedLine();
++Line->Level;
+ Line->PPLevel = PPBranchLevel + (IncludeGuard == IG_Defined ? 0 : 1);
+ assert((int)Line->PPLevel >= 0);
+ Line->InMacroBody = true;
+
// Errors during a preprocessor directive can only affect the layout of the
// preprocessor directive, and thus we ignore them. An alternative approach
// would be to use the same approach we use on the file level (no
@@ -1242,6 +1306,11 @@ void UnwrappedLineParser::parsePPDefine() {
parseFile();
}
+void UnwrappedLineParser::parsePPPragma() {
+ Line->InPragmaDirective = true;
+ parsePPUnknown();
+}
+
void UnwrappedLineParser::parsePPUnknown() {
do {
nextToken();
@@ -1369,7 +1438,15 @@ static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next,
return Tok->Previous && Tok->Previous->isOneOf(tok::l_paren, tok::comma);
}
-void UnwrappedLineParser::parseModuleImport() {
+bool UnwrappedLineParser::parseModuleImport() {
+ assert(FormatTok->is(Keywords.kw_import) && "'import' expected");
+
+ if (auto Token = Tokens->peekNextToken(/*SkipComment=*/true);
+ !Token->Tok.getIdentifierInfo() &&
+ !Token->isOneOf(tok::colon, tok::less, tok::string_literal)) {
+ return false;
+ }
+
nextToken();
while (!eof()) {
if (FormatTok->is(tok::colon)) {
@@ -1396,6 +1473,7 @@ void UnwrappedLineParser::parseModuleImport() {
}
addUnwrappedLine();
+ return true;
}
// readTokenWithJavaScriptASI reads the next token and terminates the current
@@ -1457,13 +1535,30 @@ void UnwrappedLineParser::parseStructuralElement(
addUnwrappedLine();
return;
}
+
+ if (Style.isVerilog()) {
+ // Skip things that can exist before keywords like 'if' and 'case'.
+ while (true) {
+ if (FormatTok->isOneOf(Keywords.kw_priority, Keywords.kw_unique,
+ Keywords.kw_unique0)) {
+ nextToken();
+ } else if (FormatTok->is(tok::l_paren) &&
+ Tokens->peekNextToken()->is(tok::star)) {
+ parseParens();
+ } else {
+ break;
+ }
+ }
+ }
+
+ // Tokens that only make sense at the beginning of a line.
switch (FormatTok->Tok.getKind()) {
case tok::kw_asm:
nextToken();
if (FormatTok->is(tok::l_brace)) {
FormatTok->setFinalizedType(TT_InlineASMBrace);
nextToken();
- while (FormatTok && FormatTok->isNot(tok::eof)) {
+ while (FormatTok && !eof()) {
if (FormatTok->is(tok::r_brace)) {
FormatTok->setFinalizedType(TT_InlineASMBrace);
nextToken();
@@ -1523,6 +1618,9 @@ void UnwrappedLineParser::parseStructuralElement(
parseSwitch();
return;
case tok::kw_default:
+ // In Verilog default along with other labels are handled in the next loop.
+ if (Style.isVerilog())
+ break;
if (Style.isJavaScript() && Line->MustBeDeclaration) {
// 'default: string' field declaration.
break;
@@ -1535,6 +1633,16 @@ void UnwrappedLineParser::parseStructuralElement(
// e.g. "default void f() {}" in a Java interface.
break;
case tok::kw_case:
+ // Proto: there are no switch/case statements.
+ if (Style.isProto()) {
+ nextToken();
+ return;
+ }
+ if (Style.isVerilog()) {
+ parseBlock();
+ addUnwrappedLine();
+ return;
+ }
if (Style.isJavaScript() && Line->MustBeDeclaration) {
// 'case: string' field declaration.
nextToken();
@@ -1552,7 +1660,14 @@ void UnwrappedLineParser::parseStructuralElement(
return;
case tok::kw_extern:
nextToken();
- if (FormatTok->is(tok::string_literal)) {
+ if (Style.isVerilog()) {
+ // In Verilog and extern module declaration looks like a start of module.
+ // But there is no body and endmodule. So we handle it separately.
+ if (Keywords.isVerilogHierarchy(*FormatTok)) {
+ parseVerilogHierarchyHeader();
+ return;
+ }
+ } else if (FormatTok->is(tok::string_literal)) {
nextToken();
if (FormatTok->is(tok::l_brace)) {
if (Style.BraceWrapping.AfterExternBlock)
@@ -1577,10 +1692,16 @@ void UnwrappedLineParser::parseStructuralElement(
parseJavaScriptEs6ImportExport();
return;
}
- if (!Style.isCpp())
- break;
- // Handle C++ "(inline|export) namespace".
- LLVM_FALLTHROUGH;
+ if (Style.isCpp()) {
+ nextToken();
+ if (FormatTok->is(tok::kw_namespace)) {
+ parseNamespace();
+ return;
+ }
+ if (FormatTok->is(Keywords.kw_import) && parseModuleImport())
+ return;
+ }
+ break;
case tok::kw_inline:
nextToken();
if (FormatTok->is(tok::kw_namespace)) {
@@ -1615,10 +1736,8 @@ void UnwrappedLineParser::parseStructuralElement(
addUnwrappedLine();
return;
}
- if (Style.isCpp()) {
- parseModuleImport();
+ if (Style.isCpp() && parseModuleImport())
return;
- }
}
if (Style.isCpp() &&
FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals,
@@ -1712,9 +1831,6 @@ void UnwrappedLineParser::parseStructuralElement(
break;
}
break;
- case tok::kw_concept:
- parseConcept();
- return;
case tok::kw_requires: {
if (Style.isCpp()) {
bool ParsedClause = parseRequires();
@@ -1751,9 +1867,15 @@ void UnwrappedLineParser::parseStructuralElement(
parseEnum();
}
break;
+ case tok::kw_class:
+ if (Style.isVerilog()) {
+ parseBlock();
+ addUnwrappedLine();
+ return;
+ }
+ [[fallthrough]];
case tok::kw_struct:
case tok::kw_union:
- case tok::kw_class:
if (parseStructLike())
return;
break;
@@ -1782,9 +1904,11 @@ void UnwrappedLineParser::parseStructuralElement(
parseParens();
// Break the unwrapped line if a K&R C function definition has a parameter
// declaration.
- if (!IsTopLevel || !Style.isCpp() || !Previous || FormatTok->is(tok::eof))
+ if (!IsTopLevel || !Style.isCpp() || !Previous || eof())
break;
- if (isC78ParameterDecl(FormatTok, Tokens->peekNextToken(), Previous)) {
+ if (isC78ParameterDecl(FormatTok,
+ Tokens->peekNextToken(/*SkipComment=*/true),
+ Previous)) {
addUnwrappedLine();
return;
}
@@ -1825,8 +1949,7 @@ void UnwrappedLineParser::parseStructuralElement(
} else if (Style.BraceWrapping.AfterFunction) {
addUnwrappedLine();
}
- if (!Line->InPPDirective)
- FormatTok->setFinalizedType(TT_FunctionLBrace);
+ FormatTok->setFinalizedType(TT_FunctionLBrace);
parseBlock();
addUnwrappedLine();
return;
@@ -1888,6 +2011,19 @@ void UnwrappedLineParser::parseStructuralElement(
return;
}
+ if (Style.isVerilog()) {
+ if (FormatTok->is(Keywords.kw_table)) {
+ parseVerilogTable();
+ return;
+ }
+ if (Keywords.isVerilogBegin(*FormatTok) ||
+ Keywords.isVerilogHierarchy(*FormatTok)) {
+ parseBlock();
+ addUnwrappedLine();
+ return;
+ }
+ }
+
if (FormatTok->is(Keywords.kw_interface)) {
if (parseStructLike())
return;
@@ -1919,7 +2055,9 @@ void UnwrappedLineParser::parseStructuralElement(
return I != E && (++I == E);
};
if (OneTokenSoFar()) {
- if (FormatTok->is(tok::colon) && !Line->MustBeDeclaration) {
+ // In Verilog labels can be any expression, so we don't do them here.
+ if (!Style.isVerilog() && FormatTok->is(tok::colon) &&
+ !Line->MustBeDeclaration) {
Line->Tokens.begin()->Tok->MustBreakBefore = true;
parseLabel(!Style.IndentGotoLabels);
if (HasLabel)
@@ -1939,7 +2077,8 @@ void UnwrappedLineParser::parseStructuralElement(
if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) &&
tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) {
- PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro);
+ if (PreviousToken->isNot(TT_UntouchableMacroFunc))
+ PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro);
addUnwrappedLine();
return;
}
@@ -1976,6 +2115,17 @@ void UnwrappedLineParser::parseStructuralElement(
parseNew();
break;
case tok::kw_case:
+ // Proto: there are no switch/case statements.
+ if (Style.isProto()) {
+ nextToken();
+ return;
+ }
+ // In Verilog switch is called case.
+ if (Style.isVerilog()) {
+ parseBlock();
+ addUnwrappedLine();
+ return;
+ }
if (Style.isJavaScript() && Line->MustBeDeclaration) {
// 'case: string' field declaration.
nextToken();
@@ -1983,6 +2133,30 @@ void UnwrappedLineParser::parseStructuralElement(
}
parseCaseLabel();
break;
+ case tok::kw_default:
+ nextToken();
+ if (Style.isVerilog()) {
+ if (FormatTok->is(tok::colon)) {
+ // The label will be handled in the next iteration.
+ break;
+ }
+ if (FormatTok->is(Keywords.kw_clocking)) {
+ // A default clocking block.
+ parseBlock();
+ addUnwrappedLine();
+ return;
+ }
+ parseVerilogCaseLabel();
+ return;
+ }
+ break;
+ case tok::colon:
+ nextToken();
+ if (Style.isVerilog()) {
+ parseVerilogCaseLabel();
+ return;
+ }
+ break;
default:
nextToken();
break;
@@ -2108,26 +2282,29 @@ bool UnwrappedLineParser::tryToParseLambda() {
case tok::l_square:
parseSquare();
break;
- case tok::kw_class:
- case tok::kw_template:
- case tok::kw_typename:
+ case tok::less:
assert(FormatTok->Previous);
- if (FormatTok->Previous->is(tok::less))
+ if (FormatTok->Previous->is(tok::r_square))
InTemplateParameterList = true;
nextToken();
break;
+ case tok::kw_auto:
+ case tok::kw_class:
+ case tok::kw_template:
+ case tok::kw_typename:
case tok::amp:
case tok::star:
case tok::kw_const:
case tok::kw_constexpr:
+ case tok::kw_consteval:
case tok::comma:
- case tok::less:
case tok::greater:
case tok::identifier:
case tok::numeric_constant:
case tok::coloncolon:
case tok::kw_mutable:
case tok::kw_noexcept:
+ case tok::kw_static:
nextToken();
break;
// Specialization of a template with an integer parameter can contain
@@ -2201,7 +2378,7 @@ bool UnwrappedLineParser::tryToParseLambdaIntroducer() {
if (FormatTok->is(tok::l_square))
return false;
if (FormatTok->is(tok::r_square)) {
- const FormatToken *Next = Tokens->peekNextToken();
+ const FormatToken *Next = Tokens->peekNextToken(/*SkipComment=*/true);
if (Next->is(tok::greater))
return false;
}
@@ -2432,7 +2609,7 @@ void UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
case tok::ampamp:
if (AmpAmpTokenType != TT_Unknown)
FormatTok->setFinalizedType(AmpAmpTokenType);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
nextToken();
break;
@@ -2502,8 +2679,10 @@ void UnwrappedLineParser::parseUnbracedBody(bool CheckEOF) {
FormatToken *Tok = nullptr;
if (Style.InsertBraces && !Line->InPPDirective && !Line->Tokens.empty() &&
- PreprocessorDirectives.empty()) {
- Tok = getLastNonComment(*Line);
+ PreprocessorDirectives.empty() && FormatTok->isNot(tok::semi)) {
+ Tok = Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Never
+ ? getLastNonComment(*Line)
+ : Line->Tokens.back().Tok;
assert(Tok);
if (Tok->BraceCount < 0) {
assert(Tok->BraceCount == -1);
@@ -2530,7 +2709,7 @@ void UnwrappedLineParser::parseUnbracedBody(bool CheckEOF) {
++Tok->BraceCount;
}
- if (CheckEOF && FormatTok->is(tok::eof))
+ if (CheckEOF && eof())
addUnwrappedLine();
--Line->Level;
@@ -2572,6 +2751,14 @@ bool UnwrappedLineParser::handleCppAttributes() {
return false;
}
+/// Returns whether \c Tok begins a block.
+bool UnwrappedLineParser::isBlockBegin(const FormatToken &Tok) const {
+ // FIXME: rename the function or make
+ // Tok.isOneOf(tok::l_brace, TT_MacroBlockBegin) work.
+ return Style.isVerilog() ? Keywords.isVerilogBegin(Tok)
+ : Tok.is(tok::l_brace);
+}
+
FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind,
bool KeepBraces) {
assert(FormatTok->is(tok::kw_if) && "'if' expected");
@@ -2597,7 +2784,7 @@ FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind,
FormatToken *IfLeftBrace = nullptr;
IfStmtKind IfBlockKind = IfStmtKind::NotIf;
- if (Keywords.isBlockBegin(*FormatTok, Style)) {
+ if (isBlockBegin(*FormatTok)) {
FormatTok->setFinalizedType(TT_ControlStatementLBrace);
IfLeftBrace = FormatTok;
CompoundStatementIndenter Indenter(this, Style, Line->Level);
@@ -2630,7 +2817,7 @@ FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind,
}
nextToken();
handleAttributes();
- if (Keywords.isBlockBegin(*FormatTok, Style)) {
+ if (isBlockBegin(*FormatTok)) {
const bool FollowedByIf = Tokens->peekNextToken()->is(tok::kw_if);
FormatTok->setFinalizedType(TT_ElseLBrace);
ElseLeftBrace = FormatTok;
@@ -2862,6 +3049,11 @@ void UnwrappedLineParser::parseNew() {
if (Style.isCSharp()) {
do {
+ // Handle constructor invocation, e.g. `new(field: value)`.
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
+
+ // Handle array initialization syntax, e.g. `new[] {10, 20, 30}`.
if (FormatTok->is(tok::l_brace))
parseBracedList();
@@ -2897,7 +3089,7 @@ void UnwrappedLineParser::parseNew() {
void UnwrappedLineParser::parseLoopBody(bool KeepBraces, bool WrapRightBrace) {
keepAncestorBraces();
- if (Keywords.isBlockBegin(*FormatTok, Style)) {
+ if (isBlockBegin(*FormatTok)) {
if (!KeepBraces)
FormatTok->setFinalizedType(TT_ControlStatementLBrace);
FormatToken *LeftBrace = FormatTok;
@@ -3102,26 +3294,6 @@ void UnwrappedLineParser::parseAccessSpecifier() {
}
}
-/// \brief Parses a concept definition.
-/// \pre The current token has to be the concept keyword.
-///
-/// Returns if either the concept has been completely parsed, or if it detects
-/// that the concept definition is incorrect.
-void UnwrappedLineParser::parseConcept() {
- assert(FormatTok->is(tok::kw_concept) && "'concept' expected");
- nextToken();
- if (!FormatTok->is(tok::identifier))
- return;
- nextToken();
- if (!FormatTok->is(tok::equal))
- return;
- nextToken();
- parseConstraintExpression();
- if (FormatTok->is(tok::semi))
- nextToken();
- addUnwrappedLine();
-}
-
/// \brief Parses a requires, decides if it is a clause or an expression.
/// \pre The current token has to be the requires keyword.
/// \returns true if it parsed a clause.
@@ -3204,37 +3376,41 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
// So we want basically to check for TYPE NAME, but TYPE can contain all kinds
// of stuff: typename, const, *, &, &&, ::, identifiers.
- int NextTokenOffset = 1;
- auto NextToken = Tokens->peekNextToken(NextTokenOffset);
- auto PeekNext = [&NextTokenOffset, &NextToken, this] {
- ++NextTokenOffset;
- NextToken = Tokens->peekNextToken(NextTokenOffset);
+ unsigned StoredPosition = Tokens->getPosition();
+ FormatToken *NextToken = Tokens->getNextToken();
+ int Lookahead = 0;
+ auto PeekNext = [&Lookahead, &NextToken, this] {
+ ++Lookahead;
+ NextToken = Tokens->getNextToken();
};
bool FoundType = false;
bool LastWasColonColon = false;
int OpenAngles = 0;
- for (; NextTokenOffset < 50; PeekNext()) {
+ for (; Lookahead < 50; PeekNext()) {
switch (NextToken->Tok.getKind()) {
case tok::kw_volatile:
case tok::kw_const:
case tok::comma:
+ FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresExpression(RequiresToken);
return false;
case tok::r_paren:
case tok::pipepipe:
+ FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresClause(RequiresToken);
return true;
case tok::eof:
// Break out of the loop.
- NextTokenOffset = 50;
+ Lookahead = 50;
break;
case tok::coloncolon:
LastWasColonColon = true;
break;
case tok::identifier:
if (FoundType && !LastWasColonColon && OpenAngles == 0) {
+ FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresExpression(RequiresToken);
return false;
}
@@ -3249,14 +3425,15 @@ bool clang::format::UnwrappedLineParser::parseRequires() {
break;
default:
if (NextToken->isSimpleTypeSpecifier()) {
+ FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresExpression(RequiresToken);
return false;
}
break;
}
}
-
// This seems to be a complicated expression, just assume it's a clause.
+ FormatTok = Tokens->setPosition(StoredPosition);
parseRequiresClause(RequiresToken);
return true;
}
@@ -3283,6 +3460,8 @@ void UnwrappedLineParser::parseRequiresClause(FormatToken *RequiresToken) {
? TT_RequiresClauseInARequiresExpression
: TT_RequiresClause);
+ // NOTE: parseConstraintExpression is only ever called from this function.
+ // It could be inlined into here.
parseConstraintExpression();
if (!InRequiresExpression)
@@ -3316,9 +3495,8 @@ void UnwrappedLineParser::parseRequiresExpression(FormatToken *RequiresToken) {
/// \brief Parses a constraint expression.
///
-/// This is either the definition of a concept, or the body of a requires
-/// clause. It returns, when the parsing is complete, or the expression is
-/// incorrect.
+/// This is the body of a requires clause. It returns, when the parsing is
+/// complete, or the expression is incorrect.
void UnwrappedLineParser::parseConstraintExpression() {
// The special handling for lambdas is needed since tryToParseLambda() eats a
// token and if a requires expression is the last part of a requires clause
@@ -3385,7 +3563,6 @@ void UnwrappedLineParser::parseConstraintExpression() {
case tok::minus:
case tok::star:
case tok::slash:
- case tok::kw_decltype:
LambdaNextTimeAllowed = true;
// Just eat them.
nextToken();
@@ -3417,9 +3594,9 @@ void UnwrappedLineParser::parseConstraintExpression() {
// concept C = bool(...);
// and bool is the only type, all other types as cast must be inside a
// cast to bool an thus are handled by the other cases.
- nextToken();
- if (FormatTok->isNot(tok::l_paren))
+ if (Tokens->peekNextToken()->isNot(tok::l_paren))
return;
+ nextToken();
parseParens();
break;
@@ -3438,7 +3615,8 @@ void UnwrappedLineParser::parseConstraintExpression() {
switch (FormatTok->Previous->Tok.getKind()) {
case tok::coloncolon: // Nested identifier.
case tok::ampamp: // Start of a function or variable for the
- case tok::pipepipe: // constraint expression.
+ case tok::pipepipe: // constraint expression. (binary)
+ case tok::exclaim: // The same as above, but unary.
case tok::kw_requires: // Initial identifier of a requires clause.
case tok::equal: // Initial identifier of a concept declaration.
break;
@@ -3639,7 +3817,7 @@ void UnwrappedLineParser::parseJavaEnumBody() {
++Line->Level;
// Parse the enum constants.
- while (FormatTok->isNot(tok::eof)) {
+ while (!eof()) {
if (FormatTok->is(tok::l_brace)) {
// Parse the constant's class body.
parseBlock(/*MustBeDeclaration=*/true, /*AddLevels=*/1u,
@@ -3989,21 +4167,176 @@ void UnwrappedLineParser::parseStatementMacro() {
addUnwrappedLine();
}
-LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
- StringRef Prefix = "") {
- llvm::dbgs() << Prefix << "Line(" << Line.Level
- << ", FSC=" << Line.FirstStartColumn << ")"
- << (Line.InPPDirective ? " MACRO" : "") << ": ";
- for (const auto &Node : Line.Tokens) {
- llvm::dbgs() << Node.Tok->Tok.getName() << "["
- << "T=" << static_cast<unsigned>(Node.Tok->getType())
- << ", OC=" << Node.Tok->OriginalColumn << "] ";
- }
- for (const auto &Node : Line.Tokens)
- for (const auto &ChildNode : Node.Children)
- printDebugInfo(ChildNode, "\nChild: ");
-
- llvm::dbgs() << "\n";
+void UnwrappedLineParser::parseVerilogHierarchyIdentifier() {
+ // consume things like a::`b.c[d:e] or a::*
+ while (true) {
+ if (FormatTok->isOneOf(tok::star, tok::period, tok::periodstar,
+ tok::coloncolon, tok::hash) ||
+ Keywords.isVerilogIdentifier(*FormatTok)) {
+ nextToken();
+ } else if (FormatTok->is(tok::l_square)) {
+ parseSquare();
+ } else {
+ break;
+ }
+ }
+}
+
+void UnwrappedLineParser::parseVerilogSensitivityList() {
+ if (!FormatTok->is(tok::at))
+ return;
+ nextToken();
+ // A block event expression has 2 at signs.
+ if (FormatTok->is(tok::at))
+ nextToken();
+ switch (FormatTok->Tok.getKind()) {
+ case tok::star:
+ nextToken();
+ break;
+ case tok::l_paren:
+ parseParens();
+ break;
+ default:
+ parseVerilogHierarchyIdentifier();
+ break;
+ }
+}
+
+unsigned UnwrappedLineParser::parseVerilogHierarchyHeader() {
+ unsigned AddLevels = 0;
+
+ if (FormatTok->is(Keywords.kw_clocking)) {
+ nextToken();
+ if (Keywords.isVerilogIdentifier(*FormatTok))
+ nextToken();
+ parseVerilogSensitivityList();
+ if (FormatTok->is(tok::semi))
+ nextToken();
+ } else if (FormatTok->isOneOf(tok::kw_case, Keywords.kw_casex,
+ Keywords.kw_casez, Keywords.kw_randcase,
+ Keywords.kw_randsequence)) {
+ if (Style.IndentCaseLabels)
+ AddLevels++;
+ nextToken();
+ if (FormatTok->is(tok::l_paren)) {
+ FormatTok->setFinalizedType(TT_ConditionLParen);
+ parseParens();
+ }
+ if (FormatTok->isOneOf(Keywords.kw_inside, Keywords.kw_matches))
+ nextToken();
+ // The case header has no semicolon.
+ } else {
+ // "module" etc.
+ nextToken();
+ // all the words like the name of the module and specifiers like
+ // "automatic" and the width of function return type
+ while (true) {
+ if (FormatTok->is(tok::l_square)) {
+ auto Prev = FormatTok->getPreviousNonComment();
+ if (Prev && Keywords.isVerilogIdentifier(*Prev))
+ Prev->setFinalizedType(TT_VerilogDimensionedTypeName);
+ parseSquare();
+ } else if (Keywords.isVerilogIdentifier(*FormatTok) ||
+ FormatTok->isOneOf(Keywords.kw_automatic, tok::kw_static)) {
+ nextToken();
+ } else {
+ break;
+ }
+ }
+
+ auto NewLine = [this]() {
+ addUnwrappedLine();
+ Line->IsContinuation = true;
+ };
+
+ // package imports
+ while (FormatTok->is(Keywords.kw_import)) {
+ NewLine();
+ nextToken();
+ parseVerilogHierarchyIdentifier();
+ if (FormatTok->is(tok::semi))
+ nextToken();
+ }
+
+ // parameters and ports
+ if (FormatTok->is(Keywords.kw_verilogHash)) {
+ NewLine();
+ nextToken();
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
+ }
+ if (FormatTok->is(tok::l_paren)) {
+ NewLine();
+ parseParens();
+ }
+
+ // extends and implements
+ if (FormatTok->is(Keywords.kw_extends)) {
+ NewLine();
+ nextToken();
+ parseVerilogHierarchyIdentifier();
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
+ }
+ if (FormatTok->is(Keywords.kw_implements)) {
+ NewLine();
+ do {
+ nextToken();
+ parseVerilogHierarchyIdentifier();
+ } while (FormatTok->is(tok::comma));
+ }
+
+ // Coverage event for cover groups.
+ if (FormatTok->is(tok::at)) {
+ NewLine();
+ parseVerilogSensitivityList();
+ }
+
+ if (FormatTok->is(tok::semi))
+ nextToken(/*LevelDifference=*/1);
+ addUnwrappedLine();
+ }
+
+ return AddLevels;
+}
+
+void UnwrappedLineParser::parseVerilogTable() {
+ assert(FormatTok->is(Keywords.kw_table));
+ nextToken(/*LevelDifference=*/1);
+ addUnwrappedLine();
+
+ auto InitialLevel = Line->Level++;
+ while (!eof() && !Keywords.isVerilogEnd(*FormatTok)) {
+ FormatToken *Tok = FormatTok;
+ nextToken();
+ if (Tok->is(tok::semi))
+ addUnwrappedLine();
+ else if (Tok->isOneOf(tok::star, tok::colon, tok::question, tok::minus))
+ Tok->setFinalizedType(TT_VerilogTableItem);
+ }
+ Line->Level = InitialLevel;
+ nextToken(/*LevelDifference=*/-1);
+ addUnwrappedLine();
+}
+
+void UnwrappedLineParser::parseVerilogCaseLabel() {
+ // The label will get unindented in AnnotatingParser. If there are no leading
+ // spaces, indent the rest here so that things inside the block will be
+ // indented relative to things outside. We don't use parseLabel because we
+ // don't know whether this colon is a label or a ternary expression at this
+ // point.
+ auto OrigLevel = Line->Level;
+ auto FirstLine = CurrentLines->size();
+ if (Line->Level == 0 || (Line->InPPDirective && Line->Level <= 1))
+ ++Line->Level;
+ else if (!Style.IndentCaseBlocks && Keywords.isVerilogBegin(*FormatTok))
+ --Line->Level;
+ parseStructuralElement();
+ // Restore the indentation in both the new line and the line that has the
+ // label.
+ if (CurrentLines->size() > FirstLine)
+ (*CurrentLines)[FirstLine].Level = OrigLevel;
+ Line->Level = OrigLevel;
}
void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) {
@@ -4026,6 +4359,7 @@ void UnwrappedLineParser::addUnwrappedLine(LineLevel AdjustLevel) {
Line->Tokens.clear();
Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
Line->FirstStartColumn = 0;
+ Line->IsContinuation = false;
if (ClosesWhitesmithsBlock && AdjustLevel == LineLevel::Remove)
--Line->Level;
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index 3394bfab8b8e..f043e567eb73 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -44,11 +44,23 @@ struct UnwrappedLine {
/// The indent level of the \c UnwrappedLine.
unsigned Level;
+ /// The \c PPBranchLevel (adjusted for header guards) if this line is a
+ /// \c InMacroBody line, and 0 otherwise.
+ unsigned PPLevel;
+
/// Whether this \c UnwrappedLine is part of a preprocessor directive.
bool InPPDirective;
+ /// Whether this \c UnwrappedLine is part of a pramga directive.
+ bool InPragmaDirective;
+ /// Whether it is part of a macro body.
+ bool InMacroBody;
bool MustBeDeclaration;
+ /// \c True if this line should be indented by ContinuationIndent in
+ /// addition to the normal indention level.
+ bool IsContinuation = false;
+
/// If this \c UnwrappedLine closes a block in a sequence of lines,
/// \c MatchingOpeningBlockLineIndex stores the index of the corresponding
/// opening line. Otherwise, \c MatchingOpeningBlockLineIndex must be
@@ -111,9 +123,9 @@ private:
void parsePPDirective();
void parsePPDefine();
void parsePPIf(bool IfDef);
- void parsePPElIf();
void parsePPElse();
void parsePPEndIf();
+ void parsePPPragma();
void parsePPUnknown();
void readTokenWithJavaScriptASI();
void parseStructuralElement(bool IsTopLevel = false,
@@ -131,6 +143,7 @@ private:
void parseUnbracedBody(bool CheckEOF = false);
void handleAttributes();
bool handleCppAttributes();
+ bool isBlockBegin(const FormatToken &Tok) const;
FormatToken *parseIfThenElse(IfStmtKind *IfKind, bool KeepBraces = false);
void parseTryCatch();
void parseLoopBody(bool KeepBraces, bool WrapRightBrace);
@@ -140,12 +153,11 @@ private:
void parseCaseLabel();
void parseSwitch();
void parseNamespace();
- void parseModuleImport();
+ bool parseModuleImport();
void parseNew();
void parseAccessSpecifier();
bool parseEnum();
bool parseStructLike();
- void parseConcept();
bool parseRequires();
void parseRequiresClause(FormatToken *RequiresToken);
void parseRequiresExpression(FormatToken *RequiresToken);
@@ -174,6 +186,13 @@ private:
bool tryToParsePropertyAccessor();
void tryToParseJSFunction();
bool tryToParseSimpleAttribute();
+ void parseVerilogHierarchyIdentifier();
+ void parseVerilogSensitivityList();
+ // Returns the number of levels of indentation in addition to the normal 1
+ // level for a block, used for indenting case labels.
+ unsigned parseVerilogHierarchyHeader();
+ void parseVerilogTable();
+ void parseVerilogCaseLabel();
// Used by addUnwrappedLine to denote whether to keep or remove a level
// when resetting the line state.
@@ -197,7 +216,7 @@ private:
//
// NextTok specifies the next token. A null pointer NextTok is supported, and
// signifies either the absence of a next token, or that the next token
- // shouldn't be taken into accunt for the analysis.
+ // shouldn't be taken into account for the analysis.
void distributeComments(const SmallVectorImpl<FormatToken *> &Comments,
const FormatToken *NextTok);
@@ -342,7 +361,8 @@ struct UnwrappedLineNode {
};
inline UnwrappedLine::UnwrappedLine()
- : Level(0), InPPDirective(false), MustBeDeclaration(false),
+ : Level(0), PPLevel(0), InPPDirective(false), InPragmaDirective(false),
+ InMacroBody(false), MustBeDeclaration(false),
MatchingOpeningBlockLineIndex(kInvalidIndex) {}
} // end namespace format
diff --git a/clang/lib/Format/UsingDeclarationsSorter.cpp b/clang/lib/Format/UsingDeclarationsSorter.cpp
index bf5307260c0b..2f4b1e0e4627 100644
--- a/clang/lib/Format/UsingDeclarationsSorter.cpp
+++ b/clang/lib/Format/UsingDeclarationsSorter.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "UsingDeclarationsSorter.h"
+#include "clang/Format/Format.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Regex.h"
@@ -32,7 +33,7 @@ namespace {
// individual names is that all non-namespace names come before all namespace
// names, and within those groups, names are in case-insensitive lexicographic
// order.
-int compareLabels(StringRef A, StringRef B) {
+int compareLabelsLexicographicNumeric(StringRef A, StringRef B) {
SmallVector<StringRef, 2> NamesA;
A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
SmallVector<StringRef, 2> NamesB;
@@ -64,16 +65,38 @@ int compareLabels(StringRef A, StringRef B) {
return 0;
}
+int compareLabelsLexicographic(StringRef A, StringRef B) {
+ SmallVector<StringRef, 2> NamesA;
+ A.split(NamesA, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ SmallVector<StringRef, 2> NamesB;
+ B.split(NamesB, "::", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ size_t SizeA = NamesA.size();
+ size_t SizeB = NamesB.size();
+ for (size_t I = 0, E = std::min(SizeA, SizeB); I < E; ++I) {
+ // Two namespaces names within a group compare case-insensitively.
+ int C = NamesA[I].compare_insensitive(NamesB[I]);
+ if (C != 0)
+ return C;
+ }
+ if (SizeA < SizeB)
+ return -1;
+ return SizeA == SizeB ? 0 : 1;
+}
+
+int compareLabels(
+ StringRef A, StringRef B,
+ FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
+ if (SortUsingDeclarations == FormatStyle::SUD_LexicographicNumeric)
+ return compareLabelsLexicographicNumeric(A, B);
+ return compareLabelsLexicographic(A, B);
+}
+
struct UsingDeclaration {
const AnnotatedLine *Line;
std::string Label;
UsingDeclaration(const AnnotatedLine *Line, const std::string &Label)
: Line(Line), Label(Label) {}
-
- bool operator<(const UsingDeclaration &Other) const {
- return compareLabels(Label, Other.Label) < 0;
- }
};
/// Computes the label of a using declaration starting at tthe using token
@@ -113,7 +136,8 @@ std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) {
void endUsingDeclarationBlock(
SmallVectorImpl<UsingDeclaration> *UsingDeclarations,
- const SourceManager &SourceMgr, tooling::Replacements *Fixes) {
+ const SourceManager &SourceMgr, tooling::Replacements *Fixes,
+ FormatStyle::SortUsingDeclarationsOptions SortUsingDeclarations) {
bool BlockAffected = false;
for (const UsingDeclaration &Declaration : *UsingDeclarations) {
if (Declaration.Line->Affected) {
@@ -127,7 +151,11 @@ void endUsingDeclarationBlock(
}
SmallVector<UsingDeclaration, 4> SortedUsingDeclarations(
UsingDeclarations->begin(), UsingDeclarations->end());
- llvm::stable_sort(SortedUsingDeclarations);
+ auto Comp = [SortUsingDeclarations](const UsingDeclaration &Lhs,
+ const UsingDeclaration &Rhs) -> bool {
+ return compareLabels(Lhs.Label, Rhs.Label, SortUsingDeclarations) < 0;
+ };
+ llvm::stable_sort(SortedUsingDeclarations, Comp);
SortedUsingDeclarations.erase(
std::unique(SortedUsingDeclarations.begin(),
SortedUsingDeclarations.end(),
@@ -192,21 +220,26 @@ std::pair<tooling::Replacements, unsigned> UsingDeclarationsSorter::analyze(
const auto *FirstTok = Line->First;
if (Line->InPPDirective || !Line->startsWith(tok::kw_using) ||
FirstTok->Finalized) {
- endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
+ Style.SortUsingDeclarations);
continue;
}
- if (FirstTok->NewlinesBefore > 1)
- endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ if (FirstTok->NewlinesBefore > 1) {
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
+ Style.SortUsingDeclarations);
+ }
const auto *UsingTok =
FirstTok->is(tok::comment) ? FirstTok->getNextNonComment() : FirstTok;
std::string Label = computeUsingDeclarationLabel(UsingTok);
if (Label.empty()) {
- endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
+ Style.SortUsingDeclarations);
continue;
}
UsingDeclarations.push_back(UsingDeclaration(Line, Label));
}
- endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
+ endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes,
+ Style.SortUsingDeclarations);
return {Fixes, 0};
}
diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp
index 6ec788ad23c6..9951906b6af0 100644
--- a/clang/lib/Format/WhitespaceManager.cpp
+++ b/clang/lib/Format/WhitespaceManager.cpp
@@ -522,6 +522,13 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
? Changes[StartAt].indentAndNestingLevel()
: std::tuple<unsigned, unsigned, unsigned>();
+ // Keep track if the first token has a non-zero indent and nesting level.
+ // This can happen when aligning the contents of "#else" preprocessor blocks,
+ // which is done separately.
+ bool HasInitialIndentAndNesting =
+ StartAt == 0 &&
+ IndentAndNestingLevel > std::tuple<unsigned, unsigned, unsigned>();
+
// Keep track of the number of commas before the matching tokens, we will only
// align a sequence of matching tokens if they are preceded by the same number
// of commas.
@@ -556,8 +563,19 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
unsigned i = StartAt;
for (unsigned e = Changes.size(); i != e; ++i) {
- if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
- break;
+ if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) {
+ if (!HasInitialIndentAndNesting)
+ break;
+ // The contents of preprocessor blocks are aligned separately.
+ // If the initial preprocessor block is indented or nested (e.g. it's in
+ // a function), do not align and exit after finishing this scope block.
+ // Instead, align, and then lower the baseline indent and nesting level
+ // in order to continue aligning subsequent blocks.
+ EndOfSequence = i;
+ AlignCurrentSequence();
+ IndentAndNestingLevel =
+ Changes[i].indentAndNestingLevel(); // new baseline
+ }
if (Changes[i].NewlinesBefore != 0) {
CommasBeforeMatch = 0;
@@ -591,7 +609,8 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
++CommasBeforeMatch;
} else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
// Call AlignTokens recursively, skipping over this scope block.
- unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS);
+ unsigned StoppedAt =
+ AlignTokens(Style, Matches, Changes, i, ACS, RightJustify);
i = StoppedAt - 1;
continue;
}
@@ -852,9 +871,7 @@ void WhitespaceManager::alignConsecutiveDeclarations() {
AlignTokens(
Style,
[](Change const &C) {
- // tok::kw_operator is necessary for aligning operator overload
- // definitions.
- if (C.Tok->isOneOf(TT_FunctionDeclarationName, tok::kw_operator))
+ if (C.Tok->is(TT_FunctionDeclarationName))
return true;
if (C.Tok->isNot(TT_StartOfName))
return false;
@@ -927,6 +944,10 @@ void WhitespaceManager::alignTrailingComments() {
unsigned StartOfSequence = 0;
bool BreakBeforeNext = false;
unsigned Newlines = 0;
+ unsigned int NewLineThreshold = 1;
+ if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Always)
+ NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1;
+
for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
if (Changes[i].StartOfBlockComment)
continue;
@@ -934,6 +955,21 @@ void WhitespaceManager::alignTrailingComments() {
if (!Changes[i].IsTrailingComment)
continue;
+ if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Leave) {
+ auto OriginalSpaces =
+ Changes[i].OriginalWhitespaceRange.getEnd().getRawEncoding() -
+ Changes[i].OriginalWhitespaceRange.getBegin().getRawEncoding() -
+ Changes[i].Tok->NewlinesBefore;
+ unsigned RestoredLineLength = Changes[i].StartOfTokenColumn +
+ Changes[i].TokenLength + OriginalSpaces;
+ // If leaving comments makes the line exceed the column limit, give up to
+ // leave the comments.
+ if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit != 0)
+ break;
+ Changes[i].Spaces = OriginalSpaces;
+ continue;
+ }
+
unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
unsigned ChangeMaxColumn;
@@ -957,7 +993,7 @@ void WhitespaceManager::alignTrailingComments() {
Changes[i - 1].Tok->is(tok::r_brace) &&
Changes[i - 1].StartOfTokenColumn == 0;
bool WasAlignedWithStartOfNextLine = false;
- if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
+ if (Changes[i].NewlinesBefore >= 1) { // A comment on its own line.
unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
Changes[i].OriginalWhitespaceRange.getEnd());
for (unsigned j = i + 1; j != e; ++j) {
@@ -974,12 +1010,13 @@ void WhitespaceManager::alignTrailingComments() {
break;
}
}
- if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
+ if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never ||
+ FollowsRBraceInColumn0) {
alignTrailingComments(StartOfSequence, i, MinColumn);
MinColumn = ChangeMinColumn;
MaxColumn = ChangeMinColumn;
StartOfSequence = i;
- } else if (BreakBeforeNext || Newlines > 1 ||
+ } else if (BreakBeforeNext || Newlines > NewLineThreshold ||
(ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
// Break the comment sequence if the previous line did not end
// in a trailing comment.
@@ -1014,7 +1051,7 @@ void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
Changes[i].StartOfBlockComment->StartOfTokenColumn -
Changes[i].StartOfTokenColumn;
}
- if (Shift < 0)
+ if (Shift <= 0)
continue;
Changes[i].Spaces += Shift;
if (i + 1 != Changes.size())
diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h
index 2be62338bc9a..2ccf8c08302a 100644
--- a/clang/lib/Format/WhitespaceManager.h
+++ b/clang/lib/Format/WhitespaceManager.h
@@ -199,7 +199,7 @@ private:
SmallVector<unsigned> CellCounts;
unsigned InitialSpaces = 0;
- // Determine if every row in the the array
+ // Determine if every row in the array
// has the same number of columns.
bool isRectangular() const {
if (CellCounts.empty())
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 5a157d665a9d..3b4f25182ac9 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -66,8 +66,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
@@ -87,6 +85,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
@@ -98,6 +97,7 @@
#include <cstdlib>
#include <memory>
#include <mutex>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -524,6 +524,7 @@ class ASTInfoCollector : public ASTReaderListener {
IntrusiveRefCntPtr<TargetInfo> &Target;
unsigned &Counter;
bool InitializedLanguage = false;
+ bool InitializedHeaderSearchPaths = false;
public:
ASTInfoCollector(Preprocessor &PP, ASTContext *Context,
@@ -550,7 +551,34 @@ public:
bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
StringRef SpecificModuleCachePath,
bool Complain) override {
+ // Preserve previously set header search paths.
+ llvm::SaveAndRestore X(this->HSOpts.UserEntries);
+ llvm::SaveAndRestore Y(this->HSOpts.SystemHeaderPrefixes);
+ llvm::SaveAndRestore Z(this->HSOpts.VFSOverlayFiles);
+
this->HSOpts = HSOpts;
+
+ return false;
+ }
+
+ bool ReadHeaderSearchPaths(const HeaderSearchOptions &HSOpts,
+ bool Complain) override {
+ if (InitializedHeaderSearchPaths)
+ return false;
+
+ this->HSOpts.UserEntries = HSOpts.UserEntries;
+ this->HSOpts.SystemHeaderPrefixes = HSOpts.SystemHeaderPrefixes;
+ this->HSOpts.VFSOverlayFiles = HSOpts.VFSOverlayFiles;
+
+ // Initialize the FileManager. We can't do this in update(), since that
+ // performs the initialization too late (once both target and language
+ // options are read).
+ PP.getFileManager().setVirtualFileSystem(createVFSFromOverlayFiles(
+ HSOpts.VFSOverlayFiles, PP.getDiagnostics(),
+ PP.getFileManager().getVirtualFileSystemPtr()));
+
+ InitializedHeaderSearchPaths = true;
+
return false;
}
@@ -705,10 +733,10 @@ void FilterAndStoreDiagnosticConsumer::HandleDiagnostic(
}
if (StandaloneDiags) {
- llvm::Optional<StoredDiagnostic> StoredDiag = None;
+ std::optional<StoredDiagnostic> StoredDiag;
if (!ResultDiag) {
StoredDiag.emplace(Level, Info);
- ResultDiag = StoredDiag.getPointer();
+ ResultDiag = &*StoredDiag;
}
StandaloneDiags->push_back(
makeStandaloneDiagnostic(*LangOpts, *ResultDiag));
@@ -1349,7 +1377,7 @@ ASTUnit::getMainBufferWithPrecompiledPreamble(
SmallVector<StoredDiagnostic, 4> NewPreambleDiags;
ASTUnitPreambleCallbacks Callbacks;
{
- llvm::Optional<CaptureDroppedDiagnostics> Capture;
+ std::optional<CaptureDroppedDiagnostics> Capture;
if (CaptureDiagnostics != CaptureDiagsKind::None)
Capture.emplace(CaptureDiagnostics, *Diagnostics, &NewPreambleDiags,
&NewPreambleDiagsStandalone);
@@ -1715,8 +1743,8 @@ 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,
+ bool RetainExcludedConditionalBlocks, std::optional<StringRef> ModuleFormat,
+ std::unique_ptr<ASTUnit> *ErrAST,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
@@ -1732,8 +1760,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
CIOpts.VFS = VFS;
CIOpts.Diags = Diags;
CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
- CI = createInvocation(llvm::makeArrayRef(ArgBegin, ArgEnd),
- std::move(CIOpts));
+ CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts));
if (!CI)
return nullptr;
}
@@ -2214,10 +2241,10 @@ void ASTUnit::CodeComplete(
Clang->setCodeCompletionConsumer(AugmentedConsumer);
auto getUniqueID =
- [&FileMgr](StringRef Filename) -> Optional<llvm::sys::fs::UniqueID> {
+ [&FileMgr](StringRef Filename) -> std::optional<llvm::sys::fs::UniqueID> {
if (auto Status = FileMgr.getVirtualFileSystem().status(Filename))
return Status->getUniqueID();
- return None;
+ return std::nullopt;
};
auto hasSameUniqueID = [getUniqueID](StringRef LHS, StringRef RHS) {
diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp
index 380eba4562b4..c1a9f25a8798 100644
--- a/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -27,15 +27,15 @@
using namespace clang;
namespace {
-class ChainedIncludesSourceImpl : public ExternalSemaSource {
+class ChainedIncludesSource : public ExternalSemaSource {
public:
- ChainedIncludesSourceImpl(std::vector<std::unique_ptr<CompilerInstance>> CIs)
+ ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs)
: CIs(std::move(CIs)) {}
protected:
- //===----------------------------------------------------------------------===//
+ //===--------------------------------------------------------------------===//
// ExternalASTSource interface.
- //===----------------------------------------------------------------------===//
+ //===--------------------------------------------------------------------===//
/// Return the amount of memory used by memory buffers, breaking down
/// by heap-backed versus mmap'ed memory.
@@ -51,30 +51,7 @@ protected:
private:
std::vector<std::unique_ptr<CompilerInstance>> CIs;
};
-
-/// Members of ChainedIncludesSource, factored out so we can initialize
-/// them before we initialize the ExternalSemaSource base class.
-struct ChainedIncludesSourceMembers {
- ChainedIncludesSourceMembers(
- std::vector<std::unique_ptr<CompilerInstance>> CIs,
- IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
- : Impl(std::move(CIs)), FinalReader(std::move(FinalReader)) {}
- ChainedIncludesSourceImpl Impl;
- IntrusiveRefCntPtr<ExternalSemaSource> FinalReader;
-};
-
-/// Use MultiplexExternalSemaSource to dispatch all ExternalSemaSource
-/// calls to the final reader.
-class ChainedIncludesSource
- : private ChainedIncludesSourceMembers,
- public MultiplexExternalSemaSource {
-public:
- ChainedIncludesSource(std::vector<std::unique_ptr<CompilerInstance>> CIs,
- IntrusiveRefCntPtr<ExternalSemaSource> FinalReader)
- : ChainedIncludesSourceMembers(std::move(CIs), std::move(FinalReader)),
- MultiplexExternalSemaSource(Impl, *this->FinalReader) {}
-};
-}
+} // end anonymous namespace
static ASTReader *
createASTReader(CompilerInstance &CI, StringRef pchFile,
@@ -214,6 +191,8 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
if (!Reader)
return nullptr;
- return IntrusiveRefCntPtr<ChainedIncludesSource>(
- new ChainedIncludesSource(std::move(CIs), Reader));
+ auto ChainedSrc =
+ llvm::makeIntrusiveRefCnt<ChainedIncludesSource>(std::move(CIs));
+ return llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>(
+ ChainedSrc.get(), Reader.get());
}
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 2cd7efd862ec..ecc1c4cf51c1 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangStandard.h"
#include "clang/Basic/SourceManager.h"
@@ -25,6 +26,7 @@
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/LogDiagnosticPrinter.h"
+#include "clang/Frontend/SARIFDiagnosticPrinter.h"
#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
@@ -39,6 +41,7 @@
#include "clang/Serialization/InMemoryModuleCache.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Errc.h"
@@ -52,6 +55,7 @@
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
#include <time.h>
#include <utility>
@@ -115,9 +119,9 @@ bool CompilerInstance::createTarget() {
auto TO = std::make_shared<TargetOptions>();
TO->Triple = llvm::Triple::normalize(getFrontendOpts().AuxTriple);
if (getFrontendOpts().AuxTargetCPU)
- TO->CPU = getFrontendOpts().AuxTargetCPU.value();
+ TO->CPU = *getFrontendOpts().AuxTargetCPU;
if (getFrontendOpts().AuxTargetFeatures)
- TO->FeaturesAsWritten = getFrontendOpts().AuxTargetFeatures.value();
+ TO->FeaturesAsWritten = *getFrontendOpts().AuxTargetFeatures;
TO->HostTriple = getTarget().getTriple().str();
setAuxTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), TO));
}
@@ -249,7 +253,8 @@ static void collectIncludePCH(CompilerInstance &CI,
// used here since we're not interested in validating the PCH at this time,
// but only to check whether this is a file containing an AST.
if (!ASTReader::readASTFileControlBlock(
- Dir->path(), FileMgr, CI.getPCHContainerReader(),
+ Dir->path(), FileMgr, CI.getModuleCache(),
+ CI.getPCHContainerReader(),
/*FindModuleFileExtensions=*/false, Validator,
/*ValidateDiagnosticOptions=*/false))
MDC->addFile(Dir->path());
@@ -346,6 +351,8 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
// implementing -verify.
if (Client) {
Diags->setClient(Client, ShouldOwnClient);
+ } else if (Opts->getFormat() == DiagnosticOptions::SARIF) {
+ Diags->setClient(new SARIFDiagnosticPrinter(llvm::errs(), Opts));
} else
Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
@@ -419,7 +426,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.
- auto ToFile = FileMgr.getFile(RF.second);
+ OptionalFileEntryRef ToFile = FileMgr.getOptionalFileRef(RF.second);
if (!ToFile) {
Diags.Report(diag::err_fe_remap_missing_to_file) << RF.first << RF.second;
continue;
@@ -427,7 +434,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;
@@ -777,12 +784,7 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
continue;
}
- // If '-working-directory' was passed, the output filename should be
- // relative to that.
- SmallString<128> NewOutFile(OF.Filename);
- FileMgr->FixupRelativePath(NewOutFile);
-
- llvm::Error E = OF.File->keep(NewOutFile);
+ llvm::Error E = OF.File->keep(OF.Filename);
if (!E)
continue;
@@ -803,7 +805,7 @@ std::unique_ptr<raw_pwrite_stream> CompilerInstance::createDefaultOutputFile(
bool Binary, StringRef InFile, StringRef Extension, bool RemoveFileOnSignal,
bool CreateMissingDirectories, bool ForceUseTemporary) {
StringRef OutputPath = getFrontendOpts().OutputFile;
- Optional<SmallString<128>> PathStorage;
+ std::optional<SmallString<128>> PathStorage;
if (OutputPath.empty()) {
if (InFile == "-" || Extension.empty()) {
OutputPath = "-";
@@ -845,8 +847,17 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary,
assert((!CreateMissingDirectories || UseTemporary) &&
"CreateMissingDirectories is only allowed when using temporary files");
+ // If '-working-directory' was passed, the output filename should be
+ // relative to that.
+ std::optional<SmallString<128>> AbsPath;
+ if (OutputPath != "-" && !llvm::sys::path::is_absolute(OutputPath)) {
+ AbsPath.emplace(OutputPath);
+ FileMgr->FixupRelativePath(*AbsPath);
+ OutputPath = *AbsPath;
+ }
+
std::unique_ptr<llvm::raw_fd_ostream> OS;
- Optional<StringRef> OSFile;
+ std::optional<StringRef> OSFile;
if (UseTemporary) {
if (OutputPath == "-")
@@ -868,7 +879,7 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary,
}
}
- Optional<llvm::sys::fs::TempFile> Temp;
+ std::optional<llvm::sys::fs::TempFile> Temp;
if (UseTemporary) {
// Create a temporary file.
// Insert -%%%%%%%% before the extension (if any), and because some tools
@@ -1015,9 +1026,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
// Validate/process some options.
if (getHeaderSearchOpts().Verbose)
- OS << "clang -cc1 version " CLANG_VERSION_STRING
- << " based upon " << BACKEND_PACKAGE_STRING
- << " default target " << llvm::sys::getDefaultTargetTriple() << "\n";
+ OS << "clang -cc1 version " CLANG_VERSION_STRING << " based upon LLVM "
+ << LLVM_VERSION_STRING << " default target "
+ << llvm::sys::getDefaultTargetTriple() << "\n";
if (getCodeGenOpts().TimePasses)
createFrontendTimer();
@@ -1150,8 +1161,7 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
// For any options that aren't intended to affect how a module is built,
// reset them to their default values.
- Invocation->getLangOpts()->resetNonModularOptions();
- PPOpts.resetNonModularOptions();
+ Invocation->resetNonModularOptions();
// Remove any macro definitions that are explicitly ignored by the module.
// They aren't supposed to affect how the module is built anyway.
@@ -1213,11 +1223,16 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
ImportingInstance.getDiagnosticClient()),
/*ShouldOwnClient=*/true);
- // Note that this module is part of the module build stack, so that we
- // can detect cycles in the module graph.
- Instance.setFileManager(&ImportingInstance.getFileManager());
+ if (FrontendOpts.ModulesShareFileManager) {
+ Instance.setFileManager(&ImportingInstance.getFileManager());
+ } else {
+ Instance.createFileManager(&ImportingInstance.getVirtualFileSystem());
+ }
Instance.createSourceManager(Instance.getFileManager());
SourceManager &SourceMgr = Instance.getSourceManager();
+
+ // Note that this module is part of the module build stack, so that we
+ // can detect cycles in the module graph.
SourceMgr.setModuleBuildStack(
ImportingInstance.getSourceManager().getModuleBuildStack());
SourceMgr.pushModuleBuildStack(ModuleName,
@@ -1266,19 +1281,17 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
Instance.getFrontendOpts().AllowPCMWithCompilerErrors;
}
-static const FileEntry *getPublicModuleMap(const FileEntry *File,
- FileManager &FileMgr) {
- StringRef Filename = llvm::sys::path::filename(File->getName());
- SmallString<128> PublicFilename(File->getDir()->getName());
+static OptionalFileEntryRef getPublicModuleMap(FileEntryRef File,
+ FileManager &FileMgr) {
+ StringRef Filename = llvm::sys::path::filename(File.getName());
+ SmallString<128> PublicFilename(File.getDir().getName());
if (Filename == "module_private.map")
llvm::sys::path::append(PublicFilename, "module.map");
else if (Filename == "module.private.modulemap")
llvm::sys::path::append(PublicFilename, "module.modulemap");
else
- return nullptr;
- if (auto FE = FileMgr.getFile(PublicFilename))
- return *FE;
- return nullptr;
+ return std::nullopt;
+ return FileMgr.getOptionalFileRef(PublicFilename);
}
/// Compile a module file for the given module in a separate compiler instance,
@@ -1294,21 +1307,22 @@ static bool compileModule(CompilerInstance &ImportingInstance,
ModuleMap &ModMap
= ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
bool Result;
- if (const FileEntry *ModuleMapFile =
+ if (OptionalFileEntryRef ModuleMapFile =
ModMap.getContainingModuleMapFile(Module)) {
// Canonicalize compilation to start with the public module map. This is
// vital for submodules declarations in the private module maps to be
// correctly parsed when depending on a top level module in the public one.
- if (const FileEntry *PublicMMFile = getPublicModuleMap(
- ModuleMapFile, ImportingInstance.getFileManager()))
+ if (OptionalFileEntryRef PublicMMFile = getPublicModuleMap(
+ *ModuleMapFile, ImportingInstance.getFileManager()))
ModuleMapFile = PublicMMFile;
+ StringRef ModuleMapFilePath = ModuleMapFile->getNameAsRequested();
+
// Use the module map where this module resides.
Result = compileModuleImpl(
ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
- FrontendInputFile(ModuleMapFile->getName(), IK, +Module->IsSystem),
- ModMap.getModuleMapFileForUniquing(Module)->getName(),
- ModuleFileName);
+ FrontendInputFile(ModuleMapFilePath, IK, +Module->IsSystem),
+ ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName);
} else {
// FIXME: We only need to fake up an input file here as a way of
// transporting the module's directory to the module map parser. We should
@@ -1330,7 +1344,7 @@ static bool compileModule(CompilerInstance &ImportingInstance,
[&](CompilerInstance &Instance) {
std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
- ModuleMapFile = Instance.getFileManager().getVirtualFile(
+ const FileEntry *ModuleMapFile = Instance.getFileManager().getVirtualFile(
FakeModuleMapFile, InferredModuleMapContent.size(), 0);
Instance.getSourceManager().overrideFileContents(
ModuleMapFile, std::move(ModuleMapBuffer));
@@ -1432,7 +1446,7 @@ static bool compileModuleAndReadASTBehindLock(
<< Module->Name << Locked.getErrorMessage();
// Clear out any potential leftover.
Locked.unsafeRemoveLockFile();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case llvm::LockFileManager::LFS_Owned:
// We're responsible for building the module ourselves.
return compileModuleAndReadASTImpl(ImportingInstance, ImportLoc,
@@ -1870,7 +1884,7 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST(
diag::warn_module_config_mismatch)
<< ModuleFilename;
// Fall through to error out.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ASTReader::VersionMismatch:
case ASTReader::HadErrors:
ModuleLoader::HadFatalFailure = true;
@@ -2005,8 +2019,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// match Foo_Private and emit a warning asking for the user to write
// @import Foo_Private instead. FIXME: remove this when existing clients
// migrate off of Foo.Private syntax.
- if (!Sub && PP->getLangOpts().ImplicitModules && Name == "Private" &&
- Module == Module->getTopLevelModule()) {
+ if (!Sub && Name == "Private" && Module == Module->getTopLevelModule()) {
SmallString<128> PrivateModule(Module->Name);
PrivateModule.append("_Private");
@@ -2020,6 +2033,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
Sub = loadModule(ImportLoc, PrivPath, Visibility, IsInclusionDirective);
if (Sub) {
MapPrivateSubModToTopLevel = true;
+ PP->markClangModuleAsAffecting(Module);
if (!getDiagnostics().isIgnored(
diag::warn_no_priv_submodule_use_toplevel, ImportLoc)) {
getDiagnostics().Report(Path[I].second,
@@ -2091,7 +2105,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
<< Module->getFullModuleName()
<< SourceRange(Path.front().second, Path.back().second);
- return ModuleLoadResult::MissingExpected;
+ return ModuleLoadResult(Module, ModuleLoadResult::MissingExpected);
}
// Check whether this module is available.
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 2dd96e68bb92..0bb9c8c83c63 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -52,8 +52,6 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -94,8 +92,11 @@
#include <cassert>
#include <cstddef>
#include <cstring>
+#include <ctime>
#include <fstream>
+#include <limits>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <type_traits>
@@ -113,8 +114,8 @@ using namespace llvm::opt;
// Parse misexpect tolerance argument value.
// Valid option values are integers in the range [0, 100)
-inline Expected<Optional<uint64_t>> parseToleranceOption(StringRef Arg) {
- int64_t Val;
+static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) {
+ uint32_t Val;
if (Arg.getAsInteger(10, Val))
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Not an integer: %s", Arg.data());
@@ -168,21 +169,22 @@ CompilerInvocationRefBase::~CompilerInvocationRefBase() = default;
#include "clang/Driver/Options.inc"
#undef SIMPLE_ENUM_VALUE_TABLE
-static llvm::Optional<bool> normalizeSimpleFlag(OptSpecifier Opt,
- unsigned TableIndex,
- const ArgList &Args,
- DiagnosticsEngine &Diags) {
+static std::optional<bool> normalizeSimpleFlag(OptSpecifier Opt,
+ unsigned TableIndex,
+ const ArgList &Args,
+ DiagnosticsEngine &Diags) {
if (Args.hasArg(Opt))
return true;
- return None;
+ return std::nullopt;
}
-static Optional<bool> normalizeSimpleNegativeFlag(OptSpecifier Opt, unsigned,
- const ArgList &Args,
- DiagnosticsEngine &) {
+static std::optional<bool> normalizeSimpleNegativeFlag(OptSpecifier Opt,
+ unsigned,
+ const ArgList &Args,
+ DiagnosticsEngine &) {
if (Args.hasArg(Opt))
return false;
- return None;
+ return std::nullopt;
}
/// The tblgen-erated code passes in a fifth parameter of an arbitrary type, but
@@ -197,18 +199,17 @@ static void denormalizeSimpleFlag(SmallVectorImpl<const char *> &Args,
}
template <typename T> static constexpr bool is_uint64_t_convertible() {
- return !std::is_same<T, uint64_t>::value &&
- llvm::is_integral_or_enum<T>::value;
+ return !std::is_same_v<T, uint64_t> && llvm::is_integral_or_enum<T>::value;
}
template <typename T,
std::enable_if_t<!is_uint64_t_convertible<T>(), bool> = false>
static auto makeFlagToValueNormalizer(T Value) {
return [Value](OptSpecifier Opt, unsigned, const ArgList &Args,
- DiagnosticsEngine &) -> Optional<T> {
+ DiagnosticsEngine &) -> std::optional<T> {
if (Args.hasArg(Opt))
return Value;
- return None;
+ return std::nullopt;
};
}
@@ -220,13 +221,13 @@ static auto makeFlagToValueNormalizer(T Value) {
static auto makeBooleanOptionNormalizer(bool Value, bool OtherValue,
OptSpecifier OtherOpt) {
- return [Value, OtherValue, OtherOpt](OptSpecifier Opt, unsigned,
- const ArgList &Args,
- DiagnosticsEngine &) -> Optional<bool> {
+ return [Value, OtherValue,
+ OtherOpt](OptSpecifier Opt, unsigned, const ArgList &Args,
+ DiagnosticsEngine &) -> std::optional<bool> {
if (const Arg *A = Args.getLastArg(Opt, OtherOpt)) {
return A->getOption().matches(Opt) ? Value : OtherValue;
}
- return None;
+ return std::nullopt;
};
}
@@ -269,34 +270,34 @@ denormalizeString(SmallVectorImpl<const char *> &Args, const char *Spelling,
denormalizeStringImpl(Args, Spelling, SA, OptClass, TableIndex, Twine(Value));
}
-static Optional<SimpleEnumValue>
+static std::optional<SimpleEnumValue>
findValueTableByName(const SimpleEnumValueTable &Table, StringRef Name) {
for (int I = 0, E = Table.Size; I != E; ++I)
if (Name == Table.Table[I].Name)
return Table.Table[I];
- return None;
+ return std::nullopt;
}
-static Optional<SimpleEnumValue>
+static std::optional<SimpleEnumValue>
findValueTableByValue(const SimpleEnumValueTable &Table, unsigned Value) {
for (int I = 0, E = Table.Size; I != E; ++I)
if (Value == Table.Table[I].Value)
return Table.Table[I];
- return None;
+ return std::nullopt;
}
-static llvm::Optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
- unsigned TableIndex,
- const ArgList &Args,
- DiagnosticsEngine &Diags) {
+static std::optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
+ unsigned TableIndex,
+ const ArgList &Args,
+ DiagnosticsEngine &Diags) {
assert(TableIndex < SimpleEnumValueTablesSize);
const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex];
auto *Arg = Args.getLastArg(Opt);
if (!Arg)
- return None;
+ return std::nullopt;
StringRef ArgValue = Arg->getValue();
if (auto MaybeEnumVal = findValueTableByName(Table, ArgValue))
@@ -304,7 +305,7 @@ static llvm::Optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
Diags.Report(diag::err_drv_invalid_value)
<< Arg->getAsString(Args) << ArgValue;
- return None;
+ return std::nullopt;
}
static void denormalizeSimpleEnumImpl(SmallVectorImpl<const char *> &Args,
@@ -333,32 +334,33 @@ static void denormalizeSimpleEnum(SmallVectorImpl<const char *> &Args,
static_cast<unsigned>(Value));
}
-static Optional<std::string> normalizeString(OptSpecifier Opt, int TableIndex,
- const ArgList &Args,
- DiagnosticsEngine &Diags) {
+static std::optional<std::string> normalizeString(OptSpecifier Opt,
+ int TableIndex,
+ const ArgList &Args,
+ DiagnosticsEngine &Diags) {
auto *Arg = Args.getLastArg(Opt);
if (!Arg)
- return None;
+ return std::nullopt;
return std::string(Arg->getValue());
}
template <typename IntTy>
-static Optional<IntTy> normalizeStringIntegral(OptSpecifier Opt, int,
- const ArgList &Args,
- DiagnosticsEngine &Diags) {
+static std::optional<IntTy> normalizeStringIntegral(OptSpecifier Opt, int,
+ const ArgList &Args,
+ DiagnosticsEngine &Diags) {
auto *Arg = Args.getLastArg(Opt);
if (!Arg)
- return None;
+ return std::nullopt;
IntTy Res;
if (StringRef(Arg->getValue()).getAsInteger(0, Res)) {
Diags.Report(diag::err_drv_invalid_int_value)
<< Arg->getAsString(Args) << Arg->getValue();
- return None;
+ return std::nullopt;
}
return Res;
}
-static Optional<std::vector<std::string>>
+static std::optional<std::vector<std::string>>
normalizeStringVector(OptSpecifier Opt, int, const ArgList &Args,
DiagnosticsEngine &) {
return Args.getAllArgValues(Opt);
@@ -396,12 +398,13 @@ static void denormalizeStringVector(SmallVectorImpl<const char *> &Args,
}
}
-static Optional<std::string> normalizeTriple(OptSpecifier Opt, int TableIndex,
- const ArgList &Args,
- DiagnosticsEngine &Diags) {
+static std::optional<std::string> normalizeTriple(OptSpecifier Opt,
+ int TableIndex,
+ const ArgList &Args,
+ DiagnosticsEngine &Diags) {
auto *Arg = Args.getLastArg(Opt);
if (!Arg)
- return None;
+ return std::nullopt;
return llvm::Triple::normalize(Arg->getValue());
}
@@ -490,9 +493,6 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
if (LangOpts.AppleKext && !LangOpts.CPlusPlus)
Diags.Report(diag::warn_c_kext);
- if (Args.hasArg(OPT_fconcepts_ts))
- Diags.Report(diag::warn_fe_concepts_ts_flag);
-
if (LangOpts.NewAlignOverride &&
!llvm::isPowerOf2_32(LangOpts.NewAlignOverride)) {
Arg *A = Args.getLastArg(OPT_fnew_alignment_EQ);
@@ -510,6 +510,10 @@ static bool FixupInvocation(CompilerInvocation &Invocation,
Diags.Report(diag::err_drv_argument_not_allowed_with)
<< "-fgnu89-inline" << GetInputKindName(IK);
+ if (Args.hasArg(OPT_hlsl_entrypoint) && !LangOpts.HLSL)
+ Diags.Report(diag::err_drv_argument_not_allowed_with)
+ << "-hlsl-entry" << GetInputKindName(IK);
+
if (Args.hasArg(OPT_fgpu_allow_device_init) && !LangOpts.HIP)
Diags.Report(diag::warn_ignored_hip_only_option)
<< Args.getLastArg(OPT_fgpu_allow_device_init)->getAsString(Args);
@@ -903,14 +907,6 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
#include "clang/Driver/Options.inc"
#undef ANALYZER_OPTION_WITH_MARSHALLING
- if (Args.hasArg(OPT_analyzer_store))
- Diags.Report(diag::warn_analyzer_deprecated_option) << "-analyzer-store"
- << "clang-16";
- if (Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks))
- Diags.Report(diag::warn_analyzer_deprecated_option)
- << "-analyzer-opt-analyze-nested-blocks"
- << "clang-16";
-
if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) {
StringRef Name = A->getValue();
AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name)
@@ -1024,6 +1020,15 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
A->claim();
Opts.Config[key] = std::string(val);
+
+ // FIXME: Remove this hunk after clang-17 released.
+ constexpr auto SingleFAM =
+ "consider-single-element-arrays-as-flexible-array-members";
+ if (key == SingleFAM) {
+ Diags.Report(diag::warn_analyzer_deprecated_option_with_alternative)
+ << SingleFAM << "clang-17"
+ << "-fstrict-flex-arrays=<N>";
+ }
}
}
@@ -1061,11 +1066,12 @@ static void initOption(AnalyzerOptions::ConfigTable &Config,
static void initOption(AnalyzerOptions::ConfigTable &Config,
DiagnosticsEngine *Diags,
bool &OptionField, StringRef Name, bool DefaultVal) {
- auto PossiblyInvalidVal = llvm::StringSwitch<Optional<bool>>(
- getStringOption(Config, Name, (DefaultVal ? "true" : "false")))
- .Case("true", true)
- .Case("false", false)
- .Default(None);
+ auto PossiblyInvalidVal =
+ llvm::StringSwitch<std::optional<bool>>(
+ getStringOption(Config, Name, (DefaultVal ? "true" : "false")))
+ .Case("true", true)
+ .Case("false", false)
+ .Default(std::nullopt);
if (!PossiblyInvalidVal) {
if (Diags)
@@ -1297,17 +1303,23 @@ static std::string serializeXRayInstrumentationBundle(const XRayInstrSet &S) {
// Set the profile kind using fprofile-instrument-use-path.
static void setPGOUseInstrumentor(CodeGenOptions &Opts,
- const Twine &ProfileName) {
+ const Twine &ProfileName,
+ DiagnosticsEngine &Diags) {
auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName);
- // In error, return silently and let Clang PGOUse report the error message.
if (auto E = ReaderOrErr.takeError()) {
- llvm::consumeError(std::move(E));
- Opts.setProfileUse(CodeGenOptions::ProfileClangInstr);
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "Error in reading profile %0: %1");
+ llvm::handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EI) {
+ Diags.Report(DiagID) << ProfileName.str() << EI.message();
+ });
return;
}
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader =
std::move(ReaderOrErr.get());
- if (PGOReader->isIRLevelProfile()) {
+ // Currently memprof profiles are only added at the IR level. Mark the profile
+ // type as IR in that case as well and the subsequent matching needs to detect
+ // which is available (might be one or both).
+ if (PGOReader->isIRLevelProfile() || PGOReader->hasMemoryProfile()) {
if (PGOReader->hasCSIRLevelProfile())
Opts.setProfileUse(CodeGenOptions::ProfileCSIRInstr);
else
@@ -1352,7 +1364,7 @@ void CompilerInvocation::GenerateCodeGenArgs(
else if (!Opts.DirectAccessExternalData && LangOpts->PICLevel == 0)
GenerateArg(Args, OPT_fno_direct_access_external_data, SA);
- Optional<StringRef> DebugInfoVal;
+ std::optional<StringRef> DebugInfoVal;
switch (Opts.DebugInfo) {
case codegenoptions::DebugLineTablesOnly:
DebugInfoVal = "line-tables-only";
@@ -1373,10 +1385,10 @@ void CompilerInvocation::GenerateCodeGenArgs(
DebugInfoVal = "unused-types";
break;
case codegenoptions::NoDebugInfo: // default value
- DebugInfoVal = None;
+ DebugInfoVal = std::nullopt;
break;
case codegenoptions::LocTrackingOnly: // implied value
- DebugInfoVal = None;
+ DebugInfoVal = std::nullopt;
break;
}
if (DebugInfoVal)
@@ -1482,9 +1494,6 @@ void CompilerInvocation::GenerateCodeGenArgs(
else if (Opts.CFProtectionBranch)
GenerateArg(Args, OPT_fcf_protection_EQ, "branch", SA);
- if (Opts.IBTSeal)
- GenerateArg(Args, OPT_mibt_seal, SA);
-
if (Opts.FunctionReturnThunks)
GenerateArg(Args, OPT_mfunction_return_EQ, "thunk-extern", SA);
@@ -1496,13 +1505,8 @@ void CompilerInvocation::GenerateCodeGenArgs(
F.Filename, SA);
}
- // TODO: Consider removing marshalling annotations from f[no_]emulated_tls.
- // That would make it easy to generate the option only **once** if it was
- // explicitly set to non-default value.
- if (Opts.ExplicitEmulatedTLS) {
- GenerateArg(
- Args, Opts.EmulatedTLS ? OPT_femulated_tls : OPT_fno_emulated_tls, SA);
- }
+ GenerateArg(
+ Args, Opts.EmulatedTLS ? OPT_femulated_tls : OPT_fno_emulated_tls, SA);
if (Opts.FPDenormalMode != llvm::DenormalMode::getIEEE())
GenerateArg(Args, OPT_fdenormal_fp_math_EQ, Opts.FPDenormalMode.str(), SA);
@@ -1713,7 +1717,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
StringRef Value = A->getValue();
if (Value != "simple" && Value != "mangled")
Diags.Report(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
+ << A->getSpelling() << A->getValue();
Opts.setDebugSimpleTemplateNames(
StringRef(A->getValue()) == "simple"
? codegenoptions::DebugTemplateNamesKind::Simple
@@ -1721,7 +1725,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
}
if (!Opts.ProfileInstrumentUsePath.empty())
- setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath);
+ setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath, Diags);
if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ)) {
Opts.TimePasses = true;
@@ -1849,9 +1853,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.FunctionReturnThunks = static_cast<unsigned>(Val);
}
- if (Opts.PrepareForLTO && Args.hasArg(OPT_mibt_seal))
- Opts.IBTSeal = 1;
-
for (auto *A :
Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_builtin_bitcode)) {
CodeGenOptions::BitcodeFileToLink F;
@@ -1866,9 +1867,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.LinkBitcodeFiles.push_back(F);
}
- if (Args.getLastArg(OPT_femulated_tls) ||
- Args.getLastArg(OPT_fno_emulated_tls)) {
- Opts.ExplicitEmulatedTLS = true;
+ if (!Args.getLastArg(OPT_femulated_tls) &&
+ !Args.getLastArg(OPT_fno_emulated_tls)) {
+ Opts.EmulatedTLS = T.hasDefaultEmulatedTLS();
}
if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) {
@@ -1982,7 +1983,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
} else {
Opts.DiagnosticsHotnessThreshold = *ResultOrErr;
if ((!Opts.DiagnosticsHotnessThreshold ||
- Opts.DiagnosticsHotnessThreshold.value() > 0) &&
+ *Opts.DiagnosticsHotnessThreshold > 0) &&
!UsingProfile)
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
<< "-fdiagnostics-hotness-threshold=";
@@ -1999,7 +2000,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
} else {
Opts.DiagnosticsMisExpectTolerance = *ResultOrErr;
if ((!Opts.DiagnosticsMisExpectTolerance ||
- Opts.DiagnosticsMisExpectTolerance.value() > 0) &&
+ *Opts.DiagnosticsMisExpectTolerance > 0) &&
!UsingProfile)
Diags.Report(diag::warn_drv_diagnostics_misexpect_requires_pgo)
<< "-fdiagnostics-misexpect-tolerance=";
@@ -2146,6 +2147,16 @@ static bool ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
Opts.ExtraDeps.emplace_back(std::string(Val), EDK_ModuleFile);
}
+ // Check for invalid combinations of header-include-format
+ // and header-include-filtering.
+ if ((Opts.HeaderIncludeFormat == HIFMT_Textual &&
+ Opts.HeaderIncludeFiltering != HIFIL_None) ||
+ (Opts.HeaderIncludeFormat == HIFMT_JSON &&
+ Opts.HeaderIncludeFiltering != HIFIL_Only_Direct_System))
+ Diags.Report(diag::err_drv_print_header_env_var_combination_cc1)
+ << Args.getLastArg(OPT_header_include_format_EQ)->getValue()
+ << Args.getLastArg(OPT_header_include_filtering_EQ)->getValue();
+
return Diags.getNumErrors() == NumErrorsBefore;
}
@@ -2353,7 +2364,7 @@ clang::CreateAndPopulateDiagOpts(ArrayRef<const char *> Argv) {
bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
DiagnosticsEngine *Diags,
bool DefaultDiagColor) {
- Optional<DiagnosticsEngine> IgnoringDiags;
+ std::optional<DiagnosticsEngine> IgnoringDiags;
if (!Diags) {
IgnoringDiags.emplace(new DiagnosticIDs(), new DiagnosticOptions(),
new IgnoringDiagConsumer());
@@ -2471,7 +2482,6 @@ static const auto &getFrontendActionTable() {
{frontend::GenerateModule, OPT_emit_module},
{frontend::GenerateModuleInterface, OPT_emit_module_interface},
- {frontend::GenerateHeaderModule, OPT_emit_header_module},
{frontend::GenerateHeaderUnit, OPT_emit_header_unit},
{frontend::GeneratePCH, OPT_emit_pch},
{frontend::GenerateInterfaceStubs, OPT_emit_interface_stubs},
@@ -2496,22 +2506,23 @@ static const auto &getFrontendActionTable() {
}
/// Maps command line option to frontend action.
-static Optional<frontend::ActionKind> getFrontendAction(OptSpecifier &Opt) {
+static std::optional<frontend::ActionKind>
+getFrontendAction(OptSpecifier &Opt) {
for (const auto &ActionOpt : getFrontendActionTable())
if (ActionOpt.second == Opt.getID())
return ActionOpt.first;
- return None;
+ return std::nullopt;
}
/// Maps frontend action to command line option.
-static Optional<OptSpecifier>
+static std::optional<OptSpecifier>
getProgramActionOpt(frontend::ActionKind ProgramAction) {
for (const auto &ActionOpt : getFrontendActionTable())
if (ActionOpt.first == ProgramAction)
return OptSpecifier(ActionOpt.second);
- return None;
+ return std::nullopt;
}
static void GenerateFrontendArgs(const FrontendOptions &Opts,
@@ -2530,7 +2541,7 @@ static void GenerateFrontendArgs(const FrontendOptions &Opts,
#include "clang/Driver/Options.inc"
#undef FRONTEND_OPTION_WITH_MARSHALLING
- Optional<OptSpecifier> ProgramActionOpt =
+ std::optional<OptSpecifier> ProgramActionOpt =
getProgramActionOpt(Opts.ProgramAction);
// Generating a simple flag covers most frontend actions.
@@ -2709,7 +2720,7 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::ParseSyntaxOnly;
if (const Arg *A = Args.getLastArg(OPT_Action_Group)) {
OptSpecifier Opt = OptSpecifier(A->getOption().getID());
- Optional<frontend::ActionKind> ProgramAction = getFrontendAction(Opt);
+ std::optional<frontend::ActionKind> ProgramAction = getFrontendAction(Opt);
assert(ProgramAction && "Option specifier not in Action_Group.");
if (ProgramAction == frontend::ASTDump &&
@@ -2982,8 +2993,8 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
auto Matches = [](const HeaderSearchOptions::Entry &Entry,
llvm::ArrayRef<frontend::IncludeDirGroup> Groups,
- llvm::Optional<bool> IsFramework,
- llvm::Optional<bool> IgnoreSysRoot) {
+ std::optional<bool> IsFramework,
+ std::optional<bool> IgnoreSysRoot) {
return llvm::is_contained(Groups, Entry.Group) &&
(!IsFramework || (Entry.IsFramework == *IsFramework)) &&
(!IgnoreSysRoot || (Entry.IgnoreSysRoot == *IgnoreSysRoot));
@@ -2993,8 +3004,8 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
auto End = Opts.UserEntries.end();
// Add -I..., -F..., and -index-header-map options in order.
- for (; It < End &&
- Matches(*It, {frontend::IndexHeaderMap, frontend::Angled}, None, true);
+ for (; It < End && Matches(*It, {frontend::IndexHeaderMap, frontend::Angled},
+ std::nullopt, true);
++It) {
OptSpecifier Opt = [It, Matches]() {
if (Matches(*It, frontend::IndexHeaderMap, true, true))
@@ -3032,7 +3043,8 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts,
GenerateArg(Args, OPT_idirafter, It->Path, SA);
for (; It < End && Matches(*It, {frontend::Quoted}, false, true); ++It)
GenerateArg(Args, OPT_iquote, It->Path, SA);
- for (; It < End && Matches(*It, {frontend::System}, false, None); ++It)
+ for (; It < End && Matches(*It, {frontend::System}, false, std::nullopt);
+ ++It)
GenerateArg(Args, It->IgnoreSysRoot ? OPT_isystem : OPT_iwithsysroot,
It->Path, SA);
for (; It < End && Matches(*It, {frontend::System}, true, true); ++It)
@@ -3488,9 +3500,6 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
if (Opts.OpenMPCUDAMode)
GenerateArg(Args, OPT_fopenmp_cuda_mode, SA);
- if (Opts.OpenMPCUDAForceFullRuntime)
- GenerateArg(Args, OPT_fopenmp_cuda_force_full_runtime, SA);
-
// The arguments used to set Optimize, OptimizeSize and NoInlineDefine are
// generated from CodeGenOptions.
@@ -3526,6 +3535,8 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "12.0", SA);
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver14)
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "14.0", SA);
+ else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver15)
+ GenerateArg(Args, OPT_fclang_abi_compat_EQ, "15.0", SA);
if (Opts.getSignReturnAddressScope() ==
LangOptions::SignReturnAddressScopeKind::All)
@@ -3802,7 +3813,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
else
Opts.LongDoubleSize = 0;
}
- if (Opts.FastRelaxedMath)
+ if (Opts.FastRelaxedMath || Opts.CLUnsafeMath)
Opts.setDefaultFPContractMode(LangOptions::FPM_Fast);
llvm::sort(Opts.ModuleFeatures);
@@ -3940,11 +3951,6 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.OpenMPCUDAMode = Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN()) &&
Args.hasArg(options::OPT_fopenmp_cuda_mode);
- // Set CUDA mode for OpenMP target NVPTX/AMDGCN if specified in options
- Opts.OpenMPCUDAForceFullRuntime =
- Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN()) &&
- Args.hasArg(options::OPT_fopenmp_cuda_force_full_runtime);
-
// FIXME: Eliminate this dependency.
unsigned Opt = getOptimizationLevel(Args, IK, Diags),
OptSize = getOptimizationLevelSize(Args);
@@ -4018,6 +4024,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.setClangABICompat(LangOptions::ClangABI::Ver12);
else if (Major <= 14)
Opts.setClangABICompat(LangOptions::ClangABI::Ver14);
+ else if (Major <= 15)
+ Opts.setClangABICompat(LangOptions::ClangABI::Ver15);
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
@@ -4107,6 +4115,14 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (const Arg *A = Args.getLastArg(OPT_frandomize_layout_seed_EQ))
Opts.RandstructSeed = A->getValue(0);
+ // Validate options for HLSL
+ if (Opts.HLSL) {
+ bool SupportedTarget = T.getArch() == llvm::Triple::dxil &&
+ T.getOS() == llvm::Triple::ShaderModel;
+ if (!SupportedTarget)
+ Diags.Report(diag::err_drv_hlsl_unsupported_target) << T.str();
+ }
+
return Diags.getNumErrors() == NumErrorsBefore;
}
@@ -4127,7 +4143,6 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
case frontend::FixIt:
case frontend::GenerateModule:
case frontend::GenerateModuleInterface:
- case frontend::GenerateHeaderModule:
case frontend::GenerateHeaderUnit:
case frontend::GeneratePCH:
case frontend::GenerateInterfaceStubs:
@@ -4224,6 +4239,9 @@ static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
for (const auto &RF : Opts.RemappedFiles)
GenerateArg(Args, OPT_remap_file, RF.first + ";" + RF.second, SA);
+ if (Opts.SourceDateEpoch)
+ GenerateArg(Args, OPT_source_date_epoch, Twine(*Opts.SourceDateEpoch), SA);
+
// Don't handle LexEditorPlaceholders. It is implied by the action that is
// generated elsewhere.
}
@@ -4306,6 +4324,22 @@ static bool ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.addRemappedFile(Split.first, Split.second);
}
+ if (const Arg *A = Args.getLastArg(OPT_source_date_epoch)) {
+ StringRef Epoch = A->getValue();
+ // SOURCE_DATE_EPOCH, if specified, must be a non-negative decimal integer.
+ // On time64 systems, pick 253402300799 (the UNIX timestamp of
+ // 9999-12-31T23:59:59Z) as the upper bound.
+ const uint64_t MaxTimestamp =
+ std::min<uint64_t>(std::numeric_limits<time_t>::max(), 253402300799);
+ uint64_t V;
+ if (Epoch.getAsInteger(10, V) || V > MaxTimestamp) {
+ Diags.Report(diag::err_fe_invalid_source_date_epoch)
+ << Epoch << MaxTimestamp;
+ } else {
+ Opts.SourceDateEpoch = V;
+ }
+ }
+
// Always avoid lexing editor placeholders when we're just running the
// preprocessor as we never want to emit the
// "editor placeholder in source file" error in PP only mode.
@@ -4524,8 +4558,10 @@ bool CompilerInvocation::CreateFromArgsImpl(
}
// Store the command-line for using in the CodeView backend.
- Res.getCodeGenOpts().Argv0 = Argv0;
- append_range(Res.getCodeGenOpts().CommandLineArgs, CommandLineArgs);
+ if (Res.getCodeGenOpts().CodeViewCommandLine) {
+ Res.getCodeGenOpts().Argv0 = Argv0;
+ append_range(Res.getCodeGenOpts().CommandLineArgs, CommandLineArgs);
+ }
FixupInvocation(Res, Diags, Args, DashX);
@@ -4544,7 +4580,10 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Invocation,
return CreateFromArgsImpl(Invocation, CommandLineArgs, Diags, Argv0);
},
[](CompilerInvocation &Invocation, SmallVectorImpl<const char *> &Args,
- StringAllocator SA) { Invocation.generateCC1CommandLine(Args, SA); },
+ StringAllocator SA) {
+ Args.push_back("-cc1");
+ Invocation.generateCC1CommandLine(Args, SA);
+ },
Invocation, DummyInvocation, CommandLineArgs, Diags, Argv0);
}
@@ -4665,6 +4704,37 @@ void CompilerInvocation::generateCC1CommandLine(
GenerateDependencyOutputArgs(DependencyOutputOpts, Args, SA);
}
+std::vector<std::string> CompilerInvocation::getCC1CommandLine() const {
+ // Set up string allocator.
+ llvm::BumpPtrAllocator Alloc;
+ llvm::StringSaver Strings(Alloc);
+ auto SA = [&Strings](const Twine &Arg) { return Strings.save(Arg).data(); };
+
+ // Synthesize full command line from the CompilerInvocation, including "-cc1".
+ SmallVector<const char *, 32> Args{"-cc1"};
+ generateCC1CommandLine(Args, SA);
+
+ // Convert arguments to the return type.
+ return std::vector<std::string>{Args.begin(), Args.end()};
+}
+
+void CompilerInvocation::resetNonModularOptions() {
+ getLangOpts()->resetNonModularOptions();
+ getPreprocessorOpts().resetNonModularOptions();
+}
+
+void CompilerInvocation::clearImplicitModuleBuildOptions() {
+ getLangOpts()->ImplicitModules = false;
+ getHeaderSearchOpts().ImplicitModuleMaps = false;
+ getHeaderSearchOpts().ModuleCachePath.clear();
+ getHeaderSearchOpts().ModulesValidateOncePerBuildSession = false;
+ getHeaderSearchOpts().BuildSessionTimestamp = 0;
+ // The specific values we canonicalize to for pruning don't affect behaviour,
+ /// so use the default values so they may be dropped from the command-line.
+ getHeaderSearchOpts().ModuleCachePruneInterval = 7 * 24 * 60 * 60;
+ getHeaderSearchOpts().ModuleCachePruneAfter = 31 * 24 * 60 * 60;
+}
+
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
clang::createVFSFromCompilerInvocation(const CompilerInvocation &CI,
DiagnosticsEngine &Diags) {
@@ -4676,12 +4746,19 @@ IntrusiveRefCntPtr<llvm::vfs::FileSystem>
clang::createVFSFromCompilerInvocation(
const CompilerInvocation &CI, DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
- if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
+ return createVFSFromOverlayFiles(CI.getHeaderSearchOpts().VFSOverlayFiles,
+ Diags, std::move(BaseFS));
+}
+
+IntrusiveRefCntPtr<llvm::vfs::FileSystem> clang::createVFSFromOverlayFiles(
+ ArrayRef<std::string> VFSOverlayFiles, DiagnosticsEngine &Diags,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
+ if (VFSOverlayFiles.empty())
return BaseFS;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> Result = BaseFS;
// earlier vfs files are on the bottom
- for (const auto &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
+ for (const auto &File : VFSOverlayFiles) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
Result->getBufferForFile(File);
if (!Buffer) {
diff --git a/clang/lib/Frontend/DependencyFile.cpp b/clang/lib/Frontend/DependencyFile.cpp
index 06ddb0f0db20..fe4218b6e672 100644
--- a/clang/lib/Frontend/DependencyFile.cpp
+++ b/clang/lib/Frontend/DependencyFile.cpp
@@ -21,10 +21,10 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
@@ -44,7 +44,7 @@ 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!
- if (Optional<StringRef> Filename =
+ if (std::optional<StringRef> Filename =
PP.getSourceManager().getNonBuiltinFilenameForID(FID))
DepCollector.maybeAddDependency(
llvm::sys::path::remove_leading_dotslash(*Filename),
@@ -65,7 +65,7 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
- Optional<FileEntryRef> File, StringRef SearchPath,
+ OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) override {
if (!File)
@@ -76,7 +76,7 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
}
void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
- Optional<FileEntryRef> File,
+ OptionalFileEntryRef File,
SrcMgr::CharacteristicKind FileType) override {
if (!File)
return;
@@ -109,7 +109,9 @@ struct DepCollectorMMCallbacks : public ModuleMapCallbacks {
struct DepCollectorASTListener : public ASTReaderListener {
DependencyCollector &DepCollector;
- DepCollectorASTListener(DependencyCollector &L) : DepCollector(L) { }
+ FileManager &FileMgr;
+ DepCollectorASTListener(DependencyCollector &L, FileManager &FileMgr)
+ : DepCollector(L), FileMgr(FileMgr) {}
bool needsInputFileVisitation() override { return true; }
bool needsSystemInputFileVisitation() override {
return DepCollector.needSystemDependencies();
@@ -125,6 +127,11 @@ struct DepCollectorASTListener : public ASTReaderListener {
if (IsOverridden || IsExplicitModule)
return true;
+ // Run this through the FileManager in order to respect 'use-external-name'
+ // in case we have a VFS overlay.
+ if (auto FE = FileMgr.getOptionalFileRef(Filename))
+ Filename = FE->getName();
+
DepCollector.maybeAddDependency(Filename, /*FromModule*/true, IsSystem,
/*IsModuleFile*/false, /*IsMissing*/false);
return true;
@@ -160,10 +167,7 @@ bool DependencyCollector::addDependency(StringRef Filename) {
}
static bool isSpecialFilename(StringRef Filename) {
- return llvm::StringSwitch<bool>(Filename)
- .Case("<built-in>", true)
- .Case("<stdin>", true)
- .Default(false);
+ return Filename == "<built-in>";
}
bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
@@ -180,7 +184,8 @@ void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
std::make_unique<DepCollectorMMCallbacks>(*this));
}
void DependencyCollector::attachToASTReader(ASTReader &R) {
- R.addListener(std::make_unique<DepCollectorASTListener>(*this));
+ R.addListener(
+ std::make_unique<DepCollectorASTListener>(*this, R.getFileManager()));
}
DependencyFileGenerator::DependencyFileGenerator(
@@ -329,7 +334,7 @@ void DependencyFileGenerator::outputDependencyFile(DiagnosticsEngine &Diags) {
void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
// Write out the dependency targets, trying to avoid overly long
// lines when possible. We try our best to emit exactly the same
- // dependency file as GCC (4.2), assuming the included files are the
+ // dependency file as GCC>=10, assuming the included files are the
// same.
const unsigned MaxColumns = 75;
unsigned Columns = 0;
@@ -356,6 +361,8 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
// duplicates.
ArrayRef<std::string> Files = getDependencies();
for (StringRef File : Files) {
+ if (File == "<stdin>")
+ continue;
// Start a new line if this would exceed the column limit. Make
// sure to leave space for a trailing " \" in case we need to
// break the line on the next iteration.
@@ -376,7 +383,6 @@ void DependencyFileGenerator::outputDependencyFile(llvm::raw_ostream &OS) {
for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
if (Index++ == InputFileIndex)
continue;
- OS << '\n';
PrintFilename(OS, *I, OutputFormat);
OS << ":\n";
}
diff --git a/clang/lib/Frontend/DependencyGraph.cpp b/clang/lib/Frontend/DependencyGraph.cpp
index 4cbdb3d5eeb8..6aad04370f6e 100644
--- a/clang/lib/Frontend/DependencyGraph.cpp
+++ b/clang/lib/Frontend/DependencyGraph.cpp
@@ -48,7 +48,7 @@ public:
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
- Optional<FileEntryRef> File, StringRef SearchPath,
+ OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) override;
@@ -66,21 +66,15 @@ void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
}
void DependencyGraphCallback::InclusionDirective(
- SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- Optional<FileEntryRef> File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported,
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+ bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
+ StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
if (!File)
return;
SourceManager &SM = PP->getSourceManager();
- Optional<FileEntryRef> FromFile =
+ OptionalFileEntryRef FromFile =
SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
if (!FromFile)
return;
diff --git a/clang/lib/Frontend/DiagnosticRenderer.cpp b/clang/lib/Frontend/DiagnosticRenderer.cpp
index 0afc8f3b1dab..9177ba9f4f06 100644
--- a/clang/lib/Frontend/DiagnosticRenderer.cpp
+++ b/clang/lib/Frontend/DiagnosticRenderer.cpp
@@ -18,7 +18,6 @@
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -148,7 +147,7 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
void DiagnosticRenderer::emitBasicNote(StringRef Message) {
emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note,
- Message, None, DiagOrStoredDiag());
+ Message, std::nullopt, DiagOrStoredDiag());
}
/// Prints an include stack when appropriate for a particular
@@ -453,7 +452,7 @@ void DiagnosticRenderer::emitSingleMacroExpansion(
Message << "expanded from macro '" << MacroName << "'";
emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(),
- SpellingRanges, None);
+ SpellingRanges, std::nullopt);
}
/// Check that the macro argument location of Loc starts with ArgumentLoc.
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 7b07ab948f64..1e276642016d 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -11,13 +11,17 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileEntry.h"
#include "clang/Basic/LangStandard.h"
+#include "clang/Basic/Sarif.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/LayoutOverrideSource.h"
#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Frontend/SARIFDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LiteralSupport.h"
@@ -25,6 +29,7 @@
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Sema/HLSLExternalSemaSource.h"
+#include "clang/Sema/MultiplexExternalSemaSource.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/GlobalModuleIndex.h"
@@ -35,6 +40,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
+#include <memory>
#include <system_error>
using namespace clang;
@@ -192,10 +198,8 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
ActionType == PluginASTAction::CmdlineBeforeMainAction) {
// This is O(|plugins| * |add_plugins|), but since both numbers are
// way below 50 in practice, that's ok.
- if (llvm::any_of(CI.getFrontendOpts().AddPluginActions,
- [&](const std::string &PluginAction) {
- return PluginAction == Plugin.getName();
- })) {
+ if (llvm::is_contained(CI.getFrontendOpts().AddPluginActions,
+ Plugin.getName())) {
if (ActionType == PluginASTAction::CmdlineBeforeMainAction)
ActionType = PluginASTAction::AddBeforeMainAction;
else
@@ -332,7 +336,7 @@ static std::error_code collectModuleHeaderIncludes(
return std::error_code();
// Resolve all lazy header directives to header files.
- ModMap.resolveHeaderDirectives(Module, /*File=*/llvm::None);
+ ModMap.resolveHeaderDirectives(Module, /*File=*/std::nullopt);
// If any headers are missing, we can't build this module. In most cases,
// diagnostics for this should have already been produced; we only get here
@@ -373,7 +377,9 @@ static std::error_code collectModuleHeaderIncludes(
llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative);
llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
- SmallVector<std::pair<std::string, const FileEntry *>, 8> Headers;
+ SmallVector<
+ std::pair<std::string, OptionalFileEntryRefDegradesToFileEntryPtr>, 8>
+ Headers;
for (llvm::vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End;
Dir != End && !EC; Dir.increment(EC)) {
// Check whether this entry has an extension typically associated with
@@ -383,7 +389,7 @@ static std::error_code collectModuleHeaderIncludes(
.Default(false))
continue;
- auto Header = FileMgr.getFile(Dir->path());
+ auto Header = FileMgr.getOptionalFileRef(Dir->path());
// FIXME: This shouldn't happen unless there is a file system race. Is
// that worth diagnosing?
if (!Header)
@@ -635,11 +641,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (&MF != &PrimaryModule)
CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName);
- ASTReader->visitTopLevelModuleMaps(
- PrimaryModule, [&](const FileEntry *FE) {
- CI.getFrontendOpts().ModuleMapFiles.push_back(
- std::string(FE->getName()));
- });
+ ASTReader->visitTopLevelModuleMaps(PrimaryModule, [&](FileEntryRef FE) {
+ CI.getFrontendOpts().ModuleMapFiles.push_back(
+ std::string(FE.getName()));
+ });
}
// Set up the input file for replay purposes.
@@ -717,8 +722,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
return false;
}
}
- if (!CI.hasSourceManager())
+ if (!CI.hasSourceManager()) {
CI.createSourceManager(CI.getFileManager());
+ if (CI.getDiagnosticOpts().getFormat() == DiagnosticOptions::SARIF) {
+ static_cast<SARIFDiagnosticPrinter *>(&CI.getDiagnosticClient())
+ ->setSarifWriter(
+ std::make_unique<SarifDocumentWriter>(CI.getSourceManager()));
+ }
+ }
// Set up embedding for any specified files. Do this before we load any
// source files, including the primary module map for the compilation.
@@ -770,9 +781,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
Dir != DirEnd && !EC; Dir.increment(EC)) {
// Check whether this is an acceptable AST file.
if (ASTReader::isAcceptableASTFile(
- Dir->path(), FileMgr, CI.getPCHContainerReader(),
- CI.getLangOpts(), CI.getTargetOpts(), CI.getPreprocessorOpts(),
- SpecificModuleCachePath)) {
+ Dir->path(), FileMgr, CI.getModuleCache(),
+ CI.getPCHContainerReader(), CI.getLangOpts(),
+ CI.getTargetOpts(), CI.getPreprocessorOpts(),
+ SpecificModuleCachePath, /*RequireStrictOptionMatches=*/true)) {
PPOpts.ImplicitPCHInclude = std::string(Dir->path());
Found = true;
break;
@@ -814,7 +826,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
Dir = *DirOrErr;
SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1> CWD;
CWD.push_back({nullptr, Dir});
- Optional<FileEntryRef> FE =
+ OptionalFileEntryRef FE =
HS.LookupFile(FileName, SourceLocation(),
/*Angled*/ Input.getKind().getHeaderUnitKind() ==
InputKind::HeaderUnit_System,
@@ -905,6 +917,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.getDiagnostics().Report(diag::err_module_map_not_found) << Filename;
}
+ // If compiling implementation of a module, load its module map file now.
+ (void)CI.getPreprocessor().getCurrentModuleImplementation();
+
// Add a module declaration scope so that modules from -fmodule-map-file
// arguments may shadow modules found implicitly in search paths.
CI.getPreprocessor()
@@ -1018,9 +1033,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// Setup HLSL External Sema Source
if (CI.getLangOpts().HLSL && CI.hasASTContext()) {
- IntrusiveRefCntPtr<ExternalASTSource> HLSLSema(
+ IntrusiveRefCntPtr<ExternalSemaSource> HLSLSema(
new HLSLExternalSemaSource());
- CI.getASTContext().setExternalSource(HLSLSema);
+ if (auto *SemaSource = dyn_cast_if_present<ExternalSemaSource>(
+ CI.getASTContext().getExternalSource())) {
+ IntrusiveRefCntPtr<ExternalSemaSource> MultiSema(
+ new MultiplexExternalSemaSource(SemaSource, HLSLSema.get()));
+ CI.getASTContext().setExternalSource(MultiSema);
+ } else
+ CI.getASTContext().setExternalSource(HLSLSema);
}
FailureCleanup.release();
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index f833541caa25..2d81178fa60e 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -33,6 +33,7 @@
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
+#include <optional>
#include <system_error>
using namespace clang;
@@ -265,77 +266,6 @@ GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,
return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
}
-bool GenerateHeaderModuleAction::PrepareToExecuteAction(
- CompilerInstance &CI) {
- if (!CI.getLangOpts().Modules) {
- CI.getDiagnostics().Report(diag::err_header_module_requires_modules);
- return false;
- }
-
- auto &Inputs = CI.getFrontendOpts().Inputs;
- if (Inputs.empty())
- return GenerateModuleAction::BeginInvocation(CI);
-
- auto Kind = Inputs[0].getKind();
-
- // Convert the header file inputs into a single module input buffer.
- SmallString<256> HeaderContents;
- ModuleHeaders.reserve(Inputs.size());
- for (const FrontendInputFile &FIF : Inputs) {
- // FIXME: We should support re-compiling from an AST file.
- if (FIF.getKind().getFormat() != InputKind::Source || !FIF.isFile()) {
- CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
- << (FIF.isFile() ? FIF.getFile()
- : FIF.getBuffer().getBufferIdentifier());
- return true;
- }
-
- HeaderContents += "#include \"";
- HeaderContents += FIF.getFile();
- HeaderContents += "\"\n";
- ModuleHeaders.push_back(std::string(FIF.getFile()));
- }
- Buffer = llvm::MemoryBuffer::getMemBufferCopy(
- HeaderContents, Module::getModuleInputBufferName());
-
- // Set that buffer up as our "real" input.
- Inputs.clear();
- Inputs.push_back(
- FrontendInputFile(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false));
-
- return GenerateModuleAction::PrepareToExecuteAction(CI);
-}
-
-bool GenerateHeaderModuleAction::BeginSourceFileAction(
- CompilerInstance &CI) {
- CI.getLangOpts().setCompilingModule(LangOptions::CMK_HeaderModule);
-
- // Synthesize a Module object for the given headers.
- auto &HS = CI.getPreprocessor().getHeaderSearchInfo();
- SmallVector<Module::Header, 16> Headers;
- for (StringRef Name : ModuleHeaders) {
- Optional<FileEntryRef> FE = HS.LookupFile(
- Name, SourceLocation(), /*Angled*/ false, nullptr, nullptr, None,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
- if (!FE) {
- CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
- << Name;
- continue;
- }
- Headers.push_back(
- {std::string(Name), std::string(Name), &FE->getFileEntry()});
- }
- HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers);
-
- return GenerateModuleAction::BeginSourceFileAction(CI);
-}
-
-std::unique_ptr<raw_pwrite_stream>
-GenerateHeaderModuleAction::CreateOutputFile(CompilerInstance &CI,
- StringRef InFile) {
- return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
-}
-
bool GenerateHeaderUnitAction::BeginSourceFileAction(CompilerInstance &CI) {
if (!CI.getLangOpts().CPlusPlusModules) {
CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules);
@@ -470,6 +400,8 @@ private:
return "ConstraintSubstitution";
case CodeSynthesisContext::ConstraintNormalization:
return "ConstraintNormalization";
+ case CodeSynthesisContext::RequirementParameterInstantiation:
+ return "RequirementParameterInstantiation";
case CodeSynthesisContext::ParameterMappingSubstitution:
return "ParameterMappingSubstitution";
case CodeSynthesisContext::RequirementInstantiation:
@@ -849,7 +781,8 @@ void DumpModuleInfoAction::ExecuteAction() {
assert(isCurrentFileAST() && "dumping non-AST?");
// Set up the output file.
std::unique_ptr<llvm::raw_fd_ostream> OutFile;
- StringRef OutputFileName = getCompilerInstance().getFrontendOpts().OutputFile;
+ CompilerInstance &CI = getCompilerInstance();
+ StringRef OutputFileName = CI.getFrontendOpts().OutputFile;
if (!OutputFileName.empty() && OutputFileName != "-") {
std::error_code EC;
OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC,
@@ -859,14 +792,14 @@ void DumpModuleInfoAction::ExecuteAction() {
llvm::raw_ostream &Out = OutputStream ? *OutputStream : llvm::outs();
Out << "Information for module file '" << getCurrentFile() << "':\n";
- auto &FileMgr = getCompilerInstance().getFileManager();
+ auto &FileMgr = CI.getFileManager();
auto Buffer = FileMgr.getBufferForFile(getCurrentFile());
StringRef Magic = (*Buffer)->getMemBufferRef().getBuffer();
bool IsRaw = (Magic.size() >= 4 && Magic[0] == 'C' && Magic[1] == 'P' &&
Magic[2] == 'C' && Magic[3] == 'H');
Out << " Module format: " << (IsRaw ? "raw" : "obj") << "\n";
- Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ Preprocessor &PP = CI.getPreprocessor();
DumpModuleInfoListener Listener(Out);
HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts();
@@ -920,12 +853,12 @@ void DumpModuleInfoAction::ExecuteAction() {
if (Primary) {
if (!Primary->submodules().empty())
Out << " Sub Modules:\n";
- for (auto MI : Primary->submodules()) {
+ for (auto *MI : Primary->submodules()) {
PrintSubMapEntry(MI->Name, MI->Kind);
}
if (!Primary->Imports.empty())
Out << " Imports:\n";
- for (auto IMP : Primary->Imports) {
+ for (auto *IMP : Primary->Imports) {
PrintSubMapEntry(IMP->Name, IMP->Kind);
}
if (!Primary->Exports.empty())
@@ -936,6 +869,20 @@ void DumpModuleInfoAction::ExecuteAction() {
}
}
}
+
+ // Emit the macro definitions in the module file so that we can know how
+ // much definitions in the module file quickly.
+ // TODO: Emit the macro definition bodies completely.
+ if (auto FilteredMacros = llvm::make_filter_range(
+ R->getPreprocessor().macros(),
+ [](const auto &Macro) { return Macro.first->isFromAST(); });
+ !FilteredMacros.empty()) {
+ Out << " Macro Definitions:\n";
+ for (/*<IdentifierInfo *, MacroState> pair*/ const auto &Macro :
+ FilteredMacros)
+ Out << " " << Macro.first->getName() << "\n";
+ }
+
// Now let's print out any modules we did not see as part of the Primary.
for (auto SM : SubModMap) {
if (!SM.second.Seen && SM.second.Mod) {
@@ -950,7 +897,8 @@ void DumpModuleInfoAction::ExecuteAction() {
// The reminder of the output is produced from the listener as the AST
// FileCcontrolBlock is (re-)parsed.
ASTReader::readASTFileControlBlock(
- getCurrentFile(), FileMgr, getCompilerInstance().getPCHContainerReader(),
+ getCurrentFile(), FileMgr, CI.getModuleCache(),
+ CI.getPCHContainerReader(),
/*FindModuleFileExtensions=*/true, Listener,
HSOpts.ModulesValidateDiagnosticOptions);
}
@@ -1023,7 +971,7 @@ void PrintPreprocessedAction::ExecuteAction() {
if (llvm::Triple(LLVM_HOST_TRIPLE).isOSWindows()) {
BinaryMode = true;
const SourceManager &SM = CI.getSourceManager();
- if (llvm::Optional<llvm::MemoryBufferRef> Buffer =
+ if (std::optional<llvm::MemoryBufferRef> Buffer =
SM.getBufferOrNone(SM.getMainFileID())) {
const char *cur = Buffer->getBufferStart();
const char *end = Buffer->getBufferEnd();
diff --git a/clang/lib/Frontend/FrontendOptions.cpp b/clang/lib/Frontend/FrontendOptions.cpp
index a7bdae343a94..bf83b27c1367 100644
--- a/clang/lib/Frontend/FrontendOptions.cpp
+++ b/clang/lib/Frontend/FrontendOptions.cpp
@@ -33,5 +33,6 @@ InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
.Cases("cu", "cuh", Language::CUDA)
.Case("hip", Language::HIP)
.Cases("ll", "bc", Language::LLVM_IR)
+ .Case("hlsl", Language::HLSL)
.Default(Language::Unknown);
}
diff --git a/clang/lib/Frontend/HeaderIncludeGen.cpp b/clang/lib/Frontend/HeaderIncludeGen.cpp
index 5db8792bf420..2ab480940264 100644
--- a/clang/lib/Frontend/HeaderIncludeGen.cpp
+++ b/clang/lib/Frontend/HeaderIncludeGen.cpp
@@ -12,6 +12,7 @@
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/JSON.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -49,6 +50,43 @@ public:
void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
SrcMgr::CharacteristicKind FileType) override;
};
+
+/// A callback for emitting header usage information to a file in JSON. Each
+/// line in the file is a JSON object that includes the source file name and
+/// the list of headers directly or indirectly included from it. For example:
+///
+/// {"source":"/tmp/foo.c",
+/// "includes":["/usr/include/stdio.h", "/usr/include/stdlib.h"]}
+///
+/// To reduce the amount of data written to the file, we only record system
+/// headers that are directly included from a file that isn't in the system
+/// directory.
+class HeaderIncludesJSONCallback : public PPCallbacks {
+ SourceManager &SM;
+ raw_ostream *OutputFile;
+ bool OwnsOutputFile;
+ SmallVector<std::string, 16> IncludedHeaders;
+
+public:
+ HeaderIncludesJSONCallback(const Preprocessor *PP, raw_ostream *OutputFile_,
+ bool OwnsOutputFile_)
+ : SM(PP->getSourceManager()), OutputFile(OutputFile_),
+ OwnsOutputFile(OwnsOutputFile_) {}
+
+ ~HeaderIncludesJSONCallback() override {
+ if (OwnsOutputFile)
+ delete OutputFile;
+ }
+
+ void EndOfMainFile() override;
+
+ void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType,
+ FileID PrevFID) override;
+
+ void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
+ SrcMgr::CharacteristicKind FileType) override;
+};
}
static void PrintHeaderInfo(raw_ostream *OutputFile, StringRef Filename,
@@ -116,16 +154,33 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP,
}
}
- // Print header info for extra headers, pretending they were discovered by
- // the regular preprocessor. The primary use case is to support proper
- // generation of Make / Ninja file dependencies for implicit includes, such
- // as sanitizer ignorelists. It's only important for cl.exe compatibility,
- // the GNU way to generate rules is -M / -MM / -MD / -MMD.
- for (const auto &Header : DepOpts.ExtraDeps)
- PrintHeaderInfo(OutputFile, Header.first, ShowDepth, 2, MSStyle);
- PP.addPPCallbacks(std::make_unique<HeaderIncludesCallback>(
- &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
- MSStyle));
+ switch (DepOpts.HeaderIncludeFormat) {
+ case HIFMT_None:
+ llvm_unreachable("unexpected header format kind");
+ case HIFMT_Textual: {
+ assert(DepOpts.HeaderIncludeFiltering == HIFIL_None &&
+ "header filtering is currently always disabled when output format is"
+ "textual");
+ // Print header info for extra headers, pretending they were discovered by
+ // the regular preprocessor. The primary use case is to support proper
+ // generation of Make / Ninja file dependencies for implicit includes, such
+ // as sanitizer ignorelists. It's only important for cl.exe compatibility,
+ // the GNU way to generate rules is -M / -MM / -MD / -MMD.
+ for (const auto &Header : DepOpts.ExtraDeps)
+ PrintHeaderInfo(OutputFile, Header.first, ShowDepth, 2, MSStyle);
+ PP.addPPCallbacks(std::make_unique<HeaderIncludesCallback>(
+ &PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
+ MSStyle));
+ break;
+ }
+ case HIFMT_JSON: {
+ assert(DepOpts.HeaderIncludeFiltering == HIFIL_Only_Direct_System &&
+ "only-direct-system is the only option for filtering");
+ PP.addPPCallbacks(std::make_unique<HeaderIncludesJSONCallback>(
+ &PP, OutputFile, OwnsOutputFile));
+ break;
+ }
+ }
}
void HeaderIncludesCallback::FileChanged(SourceLocation Loc,
@@ -197,3 +252,65 @@ void HeaderIncludesCallback::FileSkipped(const FileEntryRef &SkippedFile, const
PrintHeaderInfo(OutputFile, SkippedFile.getName(), ShowDepth,
CurrentIncludeDepth + 1, MSStyle);
}
+
+void HeaderIncludesJSONCallback::EndOfMainFile() {
+ const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID());
+ SmallString<256> MainFile(FE->getName());
+ SM.getFileManager().makeAbsolutePath(MainFile);
+
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ llvm::json::OStream JOS(OS);
+ JOS.object([&] {
+ JOS.attribute("source", MainFile.c_str());
+ JOS.attributeArray("includes", [&] {
+ llvm::StringSet<> SeenHeaders;
+ for (const std::string &H : IncludedHeaders)
+ if (SeenHeaders.insert(H).second)
+ JOS.value(H);
+ });
+ });
+ OS << "\n";
+
+ if (OutputFile->get_kind() == raw_ostream::OStreamKind::OK_FDStream) {
+ llvm::raw_fd_ostream *FDS = static_cast<llvm::raw_fd_ostream *>(OutputFile);
+ if (auto L = FDS->lock())
+ *OutputFile << Str;
+ } else
+ *OutputFile << Str;
+}
+
+/// Determine whether the header file should be recorded. The header file should
+/// be recorded only if the header file is a system header and the current file
+/// isn't a system header.
+static bool shouldRecordNewFile(SrcMgr::CharacteristicKind NewFileType,
+ SourceLocation PrevLoc, SourceManager &SM) {
+ return SrcMgr::isSystem(NewFileType) && !SM.isInSystemHeader(PrevLoc);
+}
+
+void HeaderIncludesJSONCallback::FileChanged(
+ SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind NewFileType, FileID PrevFID) {
+ if (PrevFID.isInvalid() ||
+ !shouldRecordNewFile(NewFileType, SM.getLocForStartOfFile(PrevFID), SM))
+ return;
+
+ // Unless we are exiting a #include, make sure to skip ahead to the line the
+ // #include directive was at.
+ PresumedLoc UserLoc = SM.getPresumedLoc(Loc);
+ if (UserLoc.isInvalid())
+ return;
+
+ if (Reason == PPCallbacks::EnterFile &&
+ UserLoc.getFilename() != StringRef("<command line>"))
+ IncludedHeaders.push_back(UserLoc.getFilename());
+}
+
+void HeaderIncludesJSONCallback::FileSkipped(
+ const FileEntryRef &SkippedFile, const Token &FilenameTok,
+ SrcMgr::CharacteristicKind FileType) {
+ if (!shouldRecordNewFile(FileType, FilenameTok.getLocation(), SM))
+ return;
+
+ IncludedHeaders.push_back(SkippedFile.getName().str());
+}
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 20bfbf144a30..208c6a8db159 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/HLSLRuntime.h"
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SyncScope.h"
@@ -298,12 +299,12 @@ static void DefineFastIntType(unsigned TypeWidth, bool IsSigned,
/// Get the value the ATOMIC_*_LOCK_FREE macro should have for a type with
/// the specified properties.
-static const char *getLockFreeValue(unsigned TypeWidth, unsigned InlineWidth) {
+static const char *getLockFreeValue(unsigned TypeWidth, const TargetInfo &TI) {
// Fully-aligned, power-of-2 sizes no larger than the inline
// width will be inlined as lock-free operations.
// Note: we do not need to check alignment since _Atomic(T) is always
// appropriately-aligned in clang.
- if ((TypeWidth & (TypeWidth - 1)) == 0 && TypeWidth <= InlineWidth)
+ if (TI.hasBuiltinAtomic(TypeWidth, TypeWidth))
return "2"; // "always lock free"
// We cannot be certain what operations the lib calls might be
// able to implement as lock-free on future processors.
@@ -402,8 +403,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__SHADER_STAGE_LIBRARY",
Twine((uint32_t)ShaderStage::Library));
// The current shader stage itself
- uint32_t StageInteger = (uint32_t)TI.getTriple().getEnvironment() -
- (uint32_t)llvm::Triple::Pixel;
+ uint32_t StageInteger = static_cast<uint32_t>(
+ hlsl::getStageFromEnvironment(TI.getTriple().getEnvironment()));
Builder.defineMacro("__SHADER_TARGET_STAGE", Twine(StageInteger));
// Add target versions
@@ -605,7 +606,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_unicode_literals", "200710L");
Builder.defineMacro("__cpp_user_defined_literals", "200809L");
Builder.defineMacro("__cpp_lambdas", "200907L");
- Builder.defineMacro("__cpp_constexpr", LangOpts.CPlusPlus2b ? "202110L"
+ Builder.defineMacro("__cpp_constexpr", LangOpts.CPlusPlus2b ? "202211L"
: LangOpts.CPlusPlus20 ? "201907L"
: LangOpts.CPlusPlus17 ? "201603L"
: LangOpts.CPlusPlus14 ? "201304L"
@@ -673,7 +674,11 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
// C++20 features.
if (LangOpts.CPlusPlus20) {
- //Builder.defineMacro("__cpp_aggregate_paren_init", "201902L");
+ Builder.defineMacro("__cpp_aggregate_paren_init", "201902L");
+
+ // P0848 is implemented, but we're still waiting for other concepts
+ // issues to be addressed before bumping __cpp_concepts up to 202002L.
+ // Refer to the discussion of this at https://reviews.llvm.org/D128619.
Builder.defineMacro("__cpp_concepts", "201907L");
Builder.defineMacro("__cpp_conditional_explicit", "201806L");
//Builder.defineMacro("__cpp_consteval", "201811L");
@@ -690,10 +695,17 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_implicit_move", "202011L");
Builder.defineMacro("__cpp_size_t_suffix", "202011L");
Builder.defineMacro("__cpp_if_consteval", "202106L");
- Builder.defineMacro("__cpp_multidimensional_subscript", "202110L");
+ Builder.defineMacro("__cpp_multidimensional_subscript", "202211L");
}
+
+ // We provide those C++2b features as extensions in earlier language modes, so
+ // we also define their feature test macros.
+ if (LangOpts.CPlusPlus11)
+ Builder.defineMacro("__cpp_static_call_operator", "202207L");
+ Builder.defineMacro("__cpp_named_character_escapes", "202207L");
+
if (LangOpts.Char8)
- Builder.defineMacro("__cpp_char8_t", "201811L");
+ Builder.defineMacro("__cpp_char8_t", "202207L");
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
// TS features.
@@ -936,14 +948,14 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__LITTLE_ENDIAN__");
}
- if (TI.getPointerWidth(0) == 64 && TI.getLongWidth() == 64
- && TI.getIntWidth() == 32) {
+ if (TI.getPointerWidth(LangAS::Default) == 64 && TI.getLongWidth() == 64 &&
+ TI.getIntWidth() == 32) {
Builder.defineMacro("_LP64");
Builder.defineMacro("__LP64__");
}
- if (TI.getPointerWidth(0) == 32 && TI.getLongWidth() == 32
- && TI.getIntWidth() == 32) {
+ if (TI.getPointerWidth(LangAS::Default) == 32 && TI.getLongWidth() == 32 &&
+ TI.getIntWidth() == 32) {
Builder.defineMacro("_ILP32");
Builder.defineMacro("__ILP32__");
}
@@ -976,7 +988,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSizeAndWidth("__SIZE", TI.getSizeType(), TI, Builder);
DefineTypeSizeAndWidth("__UINTMAX", TI.getUIntMaxType(), TI, Builder);
- DefineTypeSizeAndWidth("__PTRDIFF", TI.getPtrDiffType(0), TI, Builder);
+ DefineTypeSizeAndWidth("__PTRDIFF", TI.getPtrDiffType(LangAS::Default), TI,
+ Builder);
DefineTypeSizeAndWidth("__INTPTR", TI.getIntPtrType(), TI, Builder);
DefineTypeSizeAndWidth("__UINTPTR", TI.getUIntPtrType(), TI, Builder);
@@ -986,10 +999,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSizeof("__SIZEOF_LONG__", TI.getLongWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_LONG_DOUBLE__",TI.getLongDoubleWidth(),TI,Builder);
DefineTypeSizeof("__SIZEOF_LONG_LONG__", TI.getLongLongWidth(), TI, Builder);
- DefineTypeSizeof("__SIZEOF_POINTER__", TI.getPointerWidth(0), TI, Builder);
+ DefineTypeSizeof("__SIZEOF_POINTER__", TI.getPointerWidth(LangAS::Default),
+ TI, Builder);
DefineTypeSizeof("__SIZEOF_SHORT__", TI.getShortWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_PTRDIFF_T__",
- TI.getTypeWidth(TI.getPtrDiffType(0)), TI, Builder);
+ TI.getTypeWidth(TI.getPtrDiffType(LangAS::Default)), TI,
+ Builder);
DefineTypeSizeof("__SIZEOF_SIZE_T__",
TI.getTypeWidth(TI.getSizeType()), TI, Builder);
DefineTypeSizeof("__SIZEOF_WCHAR_T__",
@@ -1007,8 +1022,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineFmt("__UINTMAX", TI.getUIntMaxType(), TI, Builder);
Builder.defineMacro("__UINTMAX_C_SUFFIX__",
TI.getTypeConstantSuffix(TI.getUIntMaxType()));
- DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(0), Builder);
- DefineFmt("__PTRDIFF", TI.getPtrDiffType(0), TI, Builder);
+ DefineType("__PTRDIFF_TYPE__", TI.getPtrDiffType(LangAS::Default), Builder);
+ DefineFmt("__PTRDIFF", TI.getPtrDiffType(LangAS::Default), TI, Builder);
DefineType("__INTPTR_TYPE__", TI.getIntPtrType(), Builder);
DefineFmt("__INTPTR", TI.getIntPtrType(), TI, Builder);
DefineType("__SIZE_TYPE__", TI.getSizeType(), Builder);
@@ -1039,7 +1054,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
// Define a __POINTER_WIDTH__ macro for stdint.h.
Builder.defineMacro("__POINTER_WIDTH__",
- Twine((int)TI.getPointerWidth(0)));
+ Twine((int)TI.getPointerWidth(LangAS::Default)));
// Define __BIGGEST_ALIGNMENT__ to be compatible with gcc.
Builder.defineMacro("__BIGGEST_ALIGNMENT__",
@@ -1138,11 +1153,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
auto addLockFreeMacros = [&](const llvm::Twine &Prefix) {
// Used by libc++ and libstdc++ to implement ATOMIC_<foo>_LOCK_FREE.
- unsigned InlineWidthBits = TI.getMaxAtomicInlineWidth();
#define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \
Builder.defineMacro(Prefix + #TYPE "_LOCK_FREE", \
- getLockFreeValue(TI.get##Type##Width(), \
- InlineWidthBits));
+ getLockFreeValue(TI.get##Type##Width(), TI));
DEFINE_LOCK_FREE_MACRO(BOOL, Bool);
DEFINE_LOCK_FREE_MACRO(CHAR, Char);
if (LangOpts.Char8)
@@ -1154,9 +1167,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DEFINE_LOCK_FREE_MACRO(INT, Int);
DEFINE_LOCK_FREE_MACRO(LONG, Long);
DEFINE_LOCK_FREE_MACRO(LLONG, LongLong);
- Builder.defineMacro(Prefix + "POINTER_LOCK_FREE",
- getLockFreeValue(TI.getPointerWidth(0),
- InlineWidthBits));
+ Builder.defineMacro(
+ Prefix + "POINTER_LOCK_FREE",
+ getLockFreeValue(TI.getPointerWidth(LangAS::Default), TI));
#undef DEFINE_LOCK_FREE_MACRO
};
addLockFreeMacros("__CLANG_ATOMIC_");
@@ -1293,8 +1306,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
}
/// InitializePreprocessor - Initialize the preprocessor getting it and the
-/// environment ready to process a single file. This returns true on error.
-///
+/// environment ready to process a single file.
void clang::InitializePreprocessor(
Preprocessor &PP, const PreprocessorOptions &InitOpts,
const PCHContainerReader &PCHContainerRdr,
diff --git a/clang/lib/Frontend/ModuleDependencyCollector.cpp b/clang/lib/Frontend/ModuleDependencyCollector.cpp
index 7e19ed3d56e5..b4b312bc93b9 100644
--- a/clang/lib/Frontend/ModuleDependencyCollector.cpp
+++ b/clang/lib/Frontend/ModuleDependencyCollector.cpp
@@ -26,13 +26,19 @@ namespace {
/// Private implementations for ModuleDependencyCollector
class ModuleDependencyListener : public ASTReaderListener {
ModuleDependencyCollector &Collector;
+ FileManager &FileMgr;
public:
- ModuleDependencyListener(ModuleDependencyCollector &Collector)
- : Collector(Collector) {}
+ ModuleDependencyListener(ModuleDependencyCollector &Collector,
+ FileManager &FileMgr)
+ : Collector(Collector), FileMgr(FileMgr) {}
bool needsInputFileVisitation() override { return true; }
bool needsSystemInputFileVisitation() override { return true; }
bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
bool IsExplicitModule) override {
+ // Run this through the FileManager in order to respect 'use-external-name'
+ // in case we have a VFS overlay.
+ if (auto FE = FileMgr.getOptionalFileRef(Filename))
+ Filename = FE->getName();
Collector.addFile(Filename);
return true;
}
@@ -48,7 +54,7 @@ struct ModuleDependencyPPCallbacks : public PPCallbacks {
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
- Optional<FileEntryRef> File, StringRef SearchPath,
+ OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) override {
if (!File)
@@ -99,7 +105,8 @@ struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks {
}
void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
- R.addListener(std::make_unique<ModuleDependencyListener>(*this));
+ R.addListener(
+ std::make_unique<ModuleDependencyListener>(*this, R.getFileManager()));
}
void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) {
diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp
index e3c346655049..579a0b8b614d 100644
--- a/clang/lib/Frontend/PrecompiledPreamble.cpp
+++ b/clang/lib/Frontend/PrecompiledPreamble.cpp
@@ -97,10 +97,10 @@ public:
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
- Optional<FileEntryRef> File, StringRef SearchPath,
+ OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) override {
- // File is None if it wasn't found.
+ // File is std::nullopt if it wasn't found.
// (We have some false negatives if PP recovered e.g. <foo> -> "foo")
if (File)
return;
diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index e3bd7178aefe..ffa85e523c03 100644
--- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -146,7 +146,7 @@ public:
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
- Optional<FileEntryRef> File, StringRef SearchPath,
+ OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) override;
void Ident(SourceLocation Loc, StringRef str) override;
@@ -389,15 +389,9 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
}
void PrintPPOutputPPCallbacks::InclusionDirective(
- SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- Optional<FileEntryRef> File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported,
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+ bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
+ StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
// In -dI mode, dump #include directives prior to dumping their content or
// interpretation.
@@ -877,7 +871,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
Tok.getLiteralData()) {
OS.write(Tok.getLiteralData(), Tok.getLength());
- } else if (Tok.getLength() < llvm::array_lengthof(Buffer)) {
+ } else if (Tok.getLength() < std::size(Buffer)) {
const char *TokPtr = Buffer;
unsigned Len = PP.getSpelling(Tok, TokPtr);
OS.write(TokPtr, Len);
diff --git a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
index 9141adec58c4..d3a3db0139c6 100644
--- a/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -18,6 +18,7 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace llvm;
@@ -73,7 +74,7 @@ private:
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange,
- Optional<FileEntryRef> File, StringRef SearchPath,
+ OptionalFileEntryRef File, StringRef SearchPath,
StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) override;
void If(SourceLocation Loc, SourceRange ConditionRange,
@@ -181,16 +182,12 @@ void InclusionRewriter::FileSkipped(const FileEntryRef & /*SkippedFile*/,
/// FileChanged() or FileSkipped() is called after this (or neither is
/// called if this #include results in an error or does not textually include
/// anything).
-void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
- const Token &/*IncludeTok*/,
- StringRef /*FileName*/,
- bool /*IsAngled*/,
- CharSourceRange /*FilenameRange*/,
- Optional<FileEntryRef> /*File*/,
- StringRef /*SearchPath*/,
- StringRef /*RelativePath*/,
- const Module *Imported,
- SrcMgr::CharacteristicKind FileType){
+void InclusionRewriter::InclusionDirective(
+ SourceLocation HashLoc, const Token & /*IncludeTok*/,
+ StringRef /*FileName*/, bool /*IsAngled*/,
+ CharSourceRange /*FilenameRange*/, OptionalFileEntryRef /*File*/,
+ StringRef /*SearchPath*/, StringRef /*RelativePath*/,
+ const Module *Imported, SrcMgr::CharacteristicKind FileType) {
if (Imported) {
auto P = ModuleIncludes.insert(std::make_pair(HashLoc, Imported));
(void)P;
@@ -252,7 +249,8 @@ bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const {
}
void InclusionRewriter::detectMainFileEOL() {
- Optional<MemoryBufferRef> FromFile = *SM.getBufferOrNone(SM.getMainFileID());
+ std::optional<MemoryBufferRef> FromFile =
+ *SM.getBufferOrNone(SM.getMainFileID());
assert(FromFile);
if (!FromFile)
return; // Should never happen, but whatever.
@@ -283,27 +281,33 @@ void InclusionRewriter::OutputContentUpTo(const MemoryBufferRef &FromFile,
StringRef TextToWrite(FromFile.getBufferStart() + WriteFrom,
WriteTo - WriteFrom);
+ // count lines manually, it's faster than getPresumedLoc()
+ Line += TextToWrite.count(LocalEOL);
if (MainEOL == LocalEOL) {
OS << TextToWrite;
- // count lines manually, it's faster than getPresumedLoc()
- Line += TextToWrite.count(LocalEOL);
- if (EnsureNewline && !TextToWrite.endswith(LocalEOL))
- OS << MainEOL;
} else {
// Output the file one line at a time, rewriting the line endings as we go.
StringRef Rest = TextToWrite;
while (!Rest.empty()) {
- StringRef LineText;
- std::tie(LineText, Rest) = Rest.split(LocalEOL);
+ // Identify and output the next line excluding an EOL sequence if present.
+ size_t Idx = Rest.find(LocalEOL);
+ StringRef LineText = Rest.substr(0, Idx);
OS << LineText;
- Line++;
- if (!Rest.empty())
+ if (Idx != StringRef::npos) {
+ // An EOL sequence was present, output the EOL sequence for the
+ // main source file and skip past the local EOL sequence.
OS << MainEOL;
+ Idx += LocalEOL.size();
+ }
+ // Strip the line just handled. If Idx is npos or matches the end of the
+ // text, Rest will be set to an empty string and the loop will terminate.
+ Rest = Rest.substr(Idx);
}
- if (TextToWrite.endswith(LocalEOL) || EnsureNewline)
- OS << MainEOL;
}
+ if (EnsureNewline && !TextToWrite.endswith(LocalEOL))
+ OS << MainEOL;
+
WriteFrom = WriteTo;
}
diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index 2967bb3faa32..94bd2befd0b2 100644
--- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -853,7 +853,7 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
if (D->isBitField())
IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
- if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
+ if (!IvarT->getAs<TypedefType>() && IvarT->isRecordType()) {
RecordDecl *RD = IvarT->castAs<RecordType>()->getDecl();
RD = RD->getDefinition();
if (RD && !RD->getDeclName().getAsIdentifierInfo()) {
@@ -3629,7 +3629,7 @@ bool RewriteModernObjC::IsTagDefinedInsideClass(ObjCContainerDecl *IDecl,
/// It handles elaborated types, as well as enum types in the process.
bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type,
std::string &Result) {
- if (isa<TypedefType>(Type)) {
+ if (Type->getAs<TypedefType>()) {
Result += "\t";
return false;
}
@@ -3724,7 +3724,7 @@ void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl,
void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDecl,
std::string &Result) {
QualType Type = fieldDecl->getType();
- if (isa<TypedefType>(Type))
+ if (Type->getAs<TypedefType>())
return;
if (Type->isArrayType())
Type = Context->getBaseElementType(Type);
@@ -6723,7 +6723,7 @@ static void Write_IvarOffsetVar(RewriteModernObjC &RewriteObj,
std::string &Result,
ArrayRef<ObjCIvarDecl *> Ivars,
ObjCInterfaceDecl *CDecl) {
- // FIXME. visibilty of offset symbols may have to be set; for Darwin
+ // FIXME. visibility of offset symbols may have to be set; for Darwin
// this is what happens:
/**
if (Ivar->getAccessControl() == ObjCIvarDecl::Private ||
@@ -7496,7 +7496,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
if (D->isBitField())
IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
- if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
+ if (!IvarT->getAs<TypedefType>() && IvarT->isRecordType()) {
RecordDecl *RD = IvarT->castAs<RecordType>()->getDecl();
RD = RD->getDefinition();
if (RD && !RD->getDeclName().getAsIdentifierInfo()) {
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
new file mode 100644
index 000000000000..416e9132afaf
--- /dev/null
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -0,0 +1,225 @@
+//===--------- SARIFDiagnostic.cpp - SARIF Diagnostic Formatting ----------===//
+//
+// 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/Frontend/SARIFDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Sarif.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Locale.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <string>
+
+namespace clang {
+
+SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
+ DiagnosticOptions *DiagOpts,
+ SarifDocumentWriter *Writer)
+ : DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}
+
+// FIXME(llvm-project/issues/57323): Refactor Diagnostic classes.
+void SARIFDiagnostic::emitDiagnosticMessage(
+ FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
+ StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+
+ const auto *Diag = D.dyn_cast<const Diagnostic *>();
+
+ if (!Diag)
+ return;
+
+ SarifRule Rule = SarifRule::create().setRuleId(std::to_string(Diag->getID()));
+
+ Rule = addDiagnosticLevelToRule(Rule, Level);
+
+ unsigned RuleIdx = Writer->createRule(Rule);
+
+ SarifResult Result =
+ SarifResult::create(RuleIdx).setDiagnosticMessage(Message);
+
+ if (Loc.isValid())
+ Result = addLocationToResult(Result, Loc, PLoc, Ranges, *Diag);
+
+ Writer->appendResult(Result);
+}
+
+SarifResult SARIFDiagnostic::addLocationToResult(
+ SarifResult Result, FullSourceLoc Loc, PresumedLoc PLoc,
+ ArrayRef<CharSourceRange> Ranges, const Diagnostic &Diag) {
+ SmallVector<CharSourceRange> Locations = {};
+
+ if (PLoc.isInvalid()) {
+ // At least add the file name if available:
+ FileID FID = Loc.getFileID();
+ if (FID.isValid()) {
+ if (const FileEntry *FE = Loc.getFileEntry()) {
+ emitFilename(FE->getName(), Loc.getManager());
+ // FIXME(llvm-project/issues/57366): File-only locations
+ }
+ }
+ return Result;
+ }
+
+ FileID CaretFileID = Loc.getExpansionLoc().getFileID();
+
+ for (const CharSourceRange Range : Ranges) {
+ // Ignore invalid ranges.
+ if (Range.isInvalid())
+ continue;
+
+ auto &SM = Loc.getManager();
+ SourceLocation B = SM.getExpansionLoc(Range.getBegin());
+ CharSourceRange ERange = SM.getExpansionRange(Range.getEnd());
+ SourceLocation E = ERange.getEnd();
+ bool IsTokenRange = ERange.isTokenRange();
+
+ std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
+ std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+
+ // If the start or end of the range is in another file, just discard
+ // it.
+ if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
+ continue;
+
+ // Add in the length of the token, so that we cover multi-char
+ // tokens.
+ unsigned TokSize = 0;
+ if (IsTokenRange)
+ TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
+
+ FullSourceLoc BF(B, SM), EF(E, SM);
+ SourceLocation BeginLoc = SM.translateLineCol(
+ BF.getFileID(), BF.getLineNumber(), BF.getColumnNumber());
+ SourceLocation EndLoc = SM.translateLineCol(
+ EF.getFileID(), EF.getLineNumber(), EF.getColumnNumber() + TokSize);
+
+ Locations.push_back(
+ CharSourceRange{SourceRange{BeginLoc, EndLoc}, /* ITR = */ false});
+ // FIXME: Additional ranges should use presumed location in both
+ // Text and SARIF diagnostics.
+ }
+
+ auto &SM = Loc.getManager();
+ auto FID = PLoc.getFileID();
+ // Visual Studio 2010 or earlier expects column number to be off by one.
+ unsigned int ColNo = (LangOpts.MSCompatibilityVersion &&
+ !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
+ ? PLoc.getColumn() - 1
+ : PLoc.getColumn();
+ SourceLocation DiagLoc = SM.translateLineCol(FID, PLoc.getLine(), ColNo);
+
+ // FIXME(llvm-project/issues/57366): Properly process #line directives.
+ Locations.push_back(
+ CharSourceRange{SourceRange{DiagLoc, DiagLoc}, /* ITR = */ false});
+
+ return Result.setLocations(Locations);
+}
+
+SarifRule
+SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
+ DiagnosticsEngine::Level Level) {
+ auto Config = SarifReportingConfiguration::create();
+
+ switch (Level) {
+ case DiagnosticsEngine::Note:
+ Config = Config.setLevel(SarifResultLevel::Note);
+ break;
+ case DiagnosticsEngine::Remark:
+ Config = Config.setLevel(SarifResultLevel::None);
+ break;
+ case DiagnosticsEngine::Warning:
+ Config = Config.setLevel(SarifResultLevel::Warning);
+ break;
+ case DiagnosticsEngine::Error:
+ Config = Config.setLevel(SarifResultLevel::Error).setRank(50);
+ break;
+ case DiagnosticsEngine::Fatal:
+ Config = Config.setLevel(SarifResultLevel::Error).setRank(100);
+ break;
+ case DiagnosticsEngine::Ignored:
+ assert(false && "Invalid diagnostic type");
+ }
+
+ return Rule.setDefaultConfiguration(Config);
+}
+
+llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
+ const SourceManager &SM) {
+ if (DiagOpts->AbsolutePath) {
+ llvm::ErrorOr<const FileEntry *> File =
+ SM.getFileManager().getFile(Filename);
+ if (File) {
+ // We want to print a simplified absolute path, i. e. without "dots".
+ //
+ // The hardest part here are the paths like "<part1>/<link>/../<part2>".
+ // On Unix-like systems, we cannot just collapse "<link>/..", because
+ // paths are resolved sequentially, and, thereby, the path
+ // "<part1>/<part2>" may point to a different location. That is why
+ // we use FileManager::getCanonicalName(), which expands all indirections
+ // with llvm::sys::fs::real_path() and caches the result.
+ //
+ // On the other hand, it would be better to preserve as much of the
+ // original path as possible, because that helps a user to recognize it.
+ // real_path() expands all links, which is sometimes too much. Luckily,
+ // 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<256> TmpFilename = (*File)->getName();
+ llvm::sys::fs::make_absolute(TmpFilename);
+ llvm::sys::path::native(TmpFilename);
+ llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
+ Filename = StringRef(TmpFilename.data(), TmpFilename.size());
+#else
+ Filename = SM.getFileManager().getCanonicalName(*File);
+#endif
+ }
+ }
+
+ return Filename;
+}
+
+/// Print out the file/line/column information and include trace.
+///
+/// This method handlen the emission of the diagnostic location information.
+/// This includes extracting as much location information as is present for
+/// the diagnostic and printing it, as well as any include stack or source
+/// ranges necessary.
+void SARIFDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {
+ assert(false && "Not implemented in SARIF mode");
+}
+
+void SARIFDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
+ assert(false && "Not implemented in SARIF mode");
+}
+
+void SARIFDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
+ StringRef ModuleName) {
+ assert(false && "Not implemented in SARIF mode");
+}
+
+void SARIFDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName) {
+ assert(false && "Not implemented in SARIF mode");
+}
+} // namespace clang
diff --git a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
new file mode 100644
index 000000000000..73928d19a031
--- /dev/null
+++ b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
@@ -0,0 +1,83 @@
+//===------- SARIFDiagnosticPrinter.cpp - Diagnostic Printer---------------===//
+//
+// 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 diagnostic client prints out their diagnostic messages in SARIF format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/SARIFDiagnosticPrinter.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/Sarif.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Frontend/SARIFDiagnostic.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+namespace clang {
+
+SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream &OS,
+ DiagnosticOptions *Diags)
+ : OS(OS), DiagOpts(Diags) {}
+
+void SARIFDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
+ const Preprocessor *PP) {
+ // Build the SARIFDiagnostic utility.
+ assert(hasSarifWriter() && "Writer not set!");
+ assert(!SARIFDiag && "SARIFDiagnostic already set.");
+ SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, &*DiagOpts, &*Writer);
+ // Initialize the SARIF object.
+ Writer->createRun("clang", Prefix);
+}
+
+void SARIFDiagnosticPrinter::EndSourceFile() {
+ assert(SARIFDiag && "SARIFDiagnostic has not been set.");
+ Writer->endRun();
+ llvm::json::Value Value(Writer->createDocument());
+ OS << "\n" << Value << "\n\n";
+ OS.flush();
+ SARIFDiag.reset();
+}
+
+void SARIFDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
+ const Diagnostic &Info) {
+ assert(SARIFDiag && "SARIFDiagnostic has not been set.");
+ // Default implementation (Warnings/errors count). Keeps track of the
+ // number of errors.
+ DiagnosticConsumer::HandleDiagnostic(Level, Info);
+
+ // Render the diagnostic message into a temporary buffer eagerly. We'll use
+ // this later as we add the diagnostic to the SARIF object.
+ SmallString<100> OutStr;
+ Info.FormatDiagnostic(OutStr);
+
+ llvm::raw_svector_ostream DiagMessageStream(OutStr);
+
+ // Use a dedicated, simpler path for diagnostics without a valid location.
+ // This is important as if the location is missing, we may be emitting
+ // diagnostics in a context that lacks language options, a source manager, or
+ // other infrastructure necessary when emitting more rich diagnostics.
+ if (Info.getLocation().isInvalid()) {
+ // FIXME: Enable diagnostics without a source manager
+ return;
+ }
+
+ // Assert that the rest of our infrastructure is setup properly.
+ assert(DiagOpts && "Unexpected diagnostic without options set");
+ assert(Info.hasSourceManager() &&
+ "Unexpected diagnostic with no source manager");
+
+ SARIFDiag->emitDiagnostic(
+ FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level,
+ DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints(), &Info);
+}
+} // namespace clang
diff --git a/clang/lib/Frontend/SerializedDiagnosticReader.cpp b/clang/lib/Frontend/SerializedDiagnosticReader.cpp
index eca6f5ee1803..5f5ed41b0462 100644
--- a/clang/lib/Frontend/SerializedDiagnosticReader.cpp
+++ b/clang/lib/Frontend/SerializedDiagnosticReader.cpp
@@ -10,7 +10,6 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Frontend/SerializedDiagnostics.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Bitstream/BitCodes.h"
@@ -20,6 +19,7 @@
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/ManagedStatic.h"
#include <cstdint>
+#include <optional>
#include <system_error>
using namespace clang;
@@ -35,7 +35,7 @@ std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
return SDError::CouldNotLoad;
llvm::BitstreamCursor Stream(**Buffer);
- Optional<llvm::BitstreamBlockInfo> BlockInfo;
+ std::optional<llvm::BitstreamBlockInfo> BlockInfo;
if (Stream.AtEndOfStream())
return SDError::InvalidSignature;
@@ -73,7 +73,7 @@ std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
switch (MaybeSubBlockID.get()) {
case llvm::bitc::BLOCKINFO_BLOCK_ID: {
- Expected<Optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =
+ Expected<std::optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo =
Stream.ReadBlockInfoBlock();
if (!MaybeBlockInfo) {
// FIXME this drops the error on the floor.
@@ -184,7 +184,7 @@ SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
consumeError(std::move(Err));
return SDError::MalformedMetadataBlock;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Cursor::BlockEnd:
if (!VersionChecked)
return SDError::MissingVersion;
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp
index ab0dbcef6534..809d5309d1af 100644
--- a/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/clang/lib/Frontend/TextDiagnostic.cpp
@@ -20,6 +20,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <optional>
using namespace clang;
@@ -332,8 +333,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
return;
// No special characters are allowed in CaretLine.
- assert(CaretLine.end() ==
- llvm::find_if(CaretLine, [](char c) { return c < ' ' || '~' < c; }));
+ assert(llvm::none_of(CaretLine, [](char c) { return c < ' ' || '~' < c; }));
// Find the slice that we need to display the full caret line
// correctly.
@@ -924,15 +924,16 @@ void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
}
/// Find the suitable set of lines to show to include a set of ranges.
-static llvm::Optional<std::pair<unsigned, unsigned>>
+static std::optional<std::pair<unsigned, unsigned>>
findLinesForRange(const CharSourceRange &R, FileID FID,
const SourceManager &SM) {
- if (!R.isValid()) return None;
+ if (!R.isValid())
+ return std::nullopt;
SourceLocation Begin = R.getBegin();
SourceLocation End = R.getEnd();
if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
- return None;
+ return std::nullopt;
return std::make_pair(SM.getExpansionLineNumber(Begin),
SM.getExpansionLineNumber(End));
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index f67dceea9135..378f7ddd0159 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -541,7 +541,7 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
ExpectedLoc = SourceLocation();
} else {
// Lookup file via Preprocessor, like a #include.
- Optional<FileEntryRef> File =
+ OptionalFileEntryRef File =
PP->LookupFile(Pos, Filename, false, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr);
if (!File) {
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 6927d2ed47aa..47157ca5092b 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -65,8 +65,6 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
return std::make_unique<GenerateModuleFromModuleMapAction>();
case GenerateModuleInterface:
return std::make_unique<GenerateModuleInterfaceAction>();
- case GenerateHeaderModule:
- return std::make_unique<GenerateHeaderModuleAction>();
case GenerateHeaderUnit:
return std::make_unique<GenerateHeaderUnitAction>();
case GeneratePCH: return std::make_unique<GeneratePCHAction>();
diff --git a/clang/lib/Headers/__clang_cuda_texture_intrinsics.h b/clang/lib/Headers/__clang_cuda_texture_intrinsics.h
index 3c0f0026f1f0..a71952211237 100644
--- a/clang/lib/Headers/__clang_cuda_texture_intrinsics.h
+++ b/clang/lib/Headers/__clang_cuda_texture_intrinsics.h
@@ -666,6 +666,7 @@ __device__ static void __tex_fetch(__T *__ptr, cudaTextureObject_t __handle,
__tex_fetch_v4<__op>::template __run<__FetchT>(__handle, __args...));
}
+#if CUDA_VERSION < 12000
// texture<> objects get magically converted into a texture reference. However,
// there's no way to convert them to cudaTextureObject_t on C++ level. So, we
// cheat a bit and use inline assembly to do it. It costs us an extra register
@@ -713,6 +714,7 @@ __tex_fetch(__DataT *, __RetT *__ptr,
__tex_fetch_v4<__op>::template __run<__FetchT>(
__tex_handle_to_obj(__handle), __args...));
}
+#endif // CUDA_VERSION
} // namespace __cuda_tex
} // namespace
#pragma pop_macro("__ASM_OUT")
diff --git a/clang/lib/Headers/__clang_hip_libdevice_declares.h b/clang/lib/Headers/__clang_hip_libdevice_declares.h
index 8be848ba2aa3..be25f4b4a050 100644
--- a/clang/lib/Headers/__clang_hip_libdevice_declares.h
+++ b/clang/lib/Headers/__clang_hip_libdevice_declares.h
@@ -288,12 +288,17 @@ __llvm_amdgcn_rsq_f64(double __x) {
__device__ __attribute__((const)) _Float16 __ocml_ceil_f16(_Float16);
__device__ _Float16 __ocml_cos_f16(_Float16);
+__device__ __attribute__((const)) _Float16 __ocml_cvtrtn_f16_f32(float);
+__device__ __attribute__((const)) _Float16 __ocml_cvtrtp_f16_f32(float);
+__device__ __attribute__((const)) _Float16 __ocml_cvtrtz_f16_f32(float);
__device__ __attribute__((pure)) _Float16 __ocml_exp_f16(_Float16);
__device__ __attribute__((pure)) _Float16 __ocml_exp10_f16(_Float16);
__device__ __attribute__((pure)) _Float16 __ocml_exp2_f16(_Float16);
__device__ __attribute__((const)) _Float16 __ocml_floor_f16(_Float16);
__device__ __attribute__((const)) _Float16 __ocml_fma_f16(_Float16, _Float16,
_Float16);
+__device__ __attribute__((const)) _Float16 __ocml_fmax_f16(_Float16, _Float16);
+__device__ __attribute__((const)) _Float16 __ocml_fmin_f16(_Float16, _Float16);
__device__ __attribute__((const)) _Float16 __ocml_fabs_f16(_Float16);
__device__ __attribute__((const)) int __ocml_isinf_f16(_Float16);
__device__ __attribute__((const)) int __ocml_isnan_f16(_Float16);
diff --git a/clang/lib/Headers/__clang_hip_math.h b/clang/lib/Headers/__clang_hip_math.h
index ef7e087b832c..537dd0fca870 100644
--- a/clang/lib/Headers/__clang_hip_math.h
+++ b/clang/lib/Headers/__clang_hip_math.h
@@ -70,9 +70,9 @@ __DEVICE__ void __static_assert_equal_size() {
#endif
__DEVICE__
-uint64_t __make_mantissa_base8(const char *__tagp) {
+uint64_t __make_mantissa_base8(const char *__tagp __attribute__((nonnull))) {
uint64_t __r = 0;
- while (__tagp) {
+ while (*__tagp != '\0') {
char __tmp = *__tagp;
if (__tmp >= '0' && __tmp <= '7')
@@ -87,9 +87,9 @@ uint64_t __make_mantissa_base8(const char *__tagp) {
}
__DEVICE__
-uint64_t __make_mantissa_base10(const char *__tagp) {
+uint64_t __make_mantissa_base10(const char *__tagp __attribute__((nonnull))) {
uint64_t __r = 0;
- while (__tagp) {
+ while (*__tagp != '\0') {
char __tmp = *__tagp;
if (__tmp >= '0' && __tmp <= '9')
@@ -104,9 +104,9 @@ uint64_t __make_mantissa_base10(const char *__tagp) {
}
__DEVICE__
-uint64_t __make_mantissa_base16(const char *__tagp) {
+uint64_t __make_mantissa_base16(const char *__tagp __attribute__((nonnull))) {
uint64_t __r = 0;
- while (__tagp) {
+ while (*__tagp != '\0') {
char __tmp = *__tagp;
if (__tmp >= '0' && __tmp <= '9')
@@ -125,10 +125,7 @@ uint64_t __make_mantissa_base16(const char *__tagp) {
}
__DEVICE__
-uint64_t __make_mantissa(const char *__tagp) {
- if (!__tagp)
- return 0u;
-
+uint64_t __make_mantissa(const char *__tagp __attribute__((nonnull))) {
if (*__tagp == '0') {
++__tagp;
@@ -233,7 +230,7 @@ __DEVICE__
float expm1f(float __x) { return __ocml_expm1_f32(__x); }
__DEVICE__
-float fabsf(float __x) { return __ocml_fabs_f32(__x); }
+float fabsf(float __x) { return __builtin_fabsf(__x); }
__DEVICE__
float fdimf(float __x, float __y) { return __ocml_fdim_f32(__x, __y); }
@@ -359,7 +356,7 @@ float modff(float __x, float *__iptr) {
}
__DEVICE__
-float nanf(const char *__tagp) {
+float nanf(const char *__tagp __attribute__((nonnull))) {
union {
float val;
struct ieee_float {
@@ -792,7 +789,7 @@ __DEVICE__
double expm1(double __x) { return __ocml_expm1_f64(__x); }
__DEVICE__
-double fabs(double __x) { return __ocml_fabs_f64(__x); }
+double fabs(double __x) { return __builtin_fabs(__x); }
__DEVICE__
double fdim(double __x, double __y) { return __ocml_fdim_f64(__x, __y); }
diff --git a/clang/lib/Headers/__clang_hip_runtime_wrapper.h b/clang/lib/Headers/__clang_hip_runtime_wrapper.h
index 10cec58ed12f..0508731de106 100644
--- a/clang/lib/Headers/__clang_hip_runtime_wrapper.h
+++ b/clang/lib/Headers/__clang_hip_runtime_wrapper.h
@@ -113,6 +113,7 @@ __attribute__((weak)) inline __device__ void free(void *__ptr) {
#include <__clang_hip_libdevice_declares.h>
#include <__clang_hip_math.h>
+#include <__clang_hip_stdlib.h>
#if defined(__HIPCC_RTC__)
#include <__clang_hip_cmath.h>
diff --git a/clang/lib/Headers/__clang_hip_stdlib.h b/clang/lib/Headers/__clang_hip_stdlib.h
new file mode 100644
index 000000000000..bd770e2415f9
--- /dev/null
+++ b/clang/lib/Headers/__clang_hip_stdlib.h
@@ -0,0 +1,43 @@
+/*===---- __clang_hip_stdlib.h - Device-side HIP math support --------------===
+ *
+ * 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 __CLANG_HIP_STDLIB_H__
+
+#if !defined(__HIP__) && !defined(__OPENMP_AMDGCN__)
+#error "This file is for HIP and OpenMP AMDGCN device compilation only."
+#endif
+
+#if !defined(__cplusplus)
+
+#include <limits.h>
+
+#ifdef __OPENMP_AMDGCN__
+#define __DEVICE__ static inline __attribute__((always_inline, nothrow))
+#else
+#define __DEVICE__ static __device__ inline __attribute__((always_inline))
+#endif
+
+__DEVICE__
+int abs(int __x) {
+ int __sgn = __x >> (sizeof(int) * CHAR_BIT - 1);
+ return (__x ^ __sgn) - __sgn;
+}
+__DEVICE__
+long labs(long __x) {
+ long __sgn = __x >> (sizeof(long) * CHAR_BIT - 1);
+ return (__x ^ __sgn) - __sgn;
+}
+__DEVICE__
+long long llabs(long long __x) {
+ long long __sgn = __x >> (sizeof(long long) * CHAR_BIT - 1);
+ return (__x ^ __sgn) - __sgn;
+}
+
+#endif // !defined(__cplusplus)
+
+#endif // #define __CLANG_HIP_STDLIB_H__
diff --git a/clang/lib/Headers/altivec.h b/clang/lib/Headers/altivec.h
index 0b1e76e81cc7..f50466ec9637 100644
--- a/clang/lib/Headers/altivec.h
+++ b/clang/lib/Headers/altivec.h
@@ -17323,32 +17323,32 @@ provided.
#define vec_ncipherlast_be __builtin_altivec_crypto_vncipherlast
#ifdef __VSX__
-static __inline__ vector unsigned long long __attribute__((__always_inline__))
-__builtin_crypto_vsbox(vector unsigned long long __a) {
+static __inline__ vector unsigned char __attribute__((__always_inline__))
+__builtin_crypto_vsbox(vector unsigned char __a) {
return __builtin_altivec_crypto_vsbox(__a);
}
-static __inline__ vector unsigned long long __attribute__((__always_inline__))
-__builtin_crypto_vcipher(vector unsigned long long __a,
- vector unsigned long long __b) {
+static __inline__ vector unsigned char __attribute__((__always_inline__))
+__builtin_crypto_vcipher(vector unsigned char __a,
+ vector unsigned char __b) {
return __builtin_altivec_crypto_vcipher(__a, __b);
}
-static __inline__ vector unsigned long long __attribute__((__always_inline__))
-__builtin_crypto_vcipherlast(vector unsigned long long __a,
- vector unsigned long long __b) {
+static __inline__ vector unsigned char __attribute__((__always_inline__))
+__builtin_crypto_vcipherlast(vector unsigned char __a,
+ vector unsigned char __b) {
return __builtin_altivec_crypto_vcipherlast(__a, __b);
}
-static __inline__ vector unsigned long long __attribute__((__always_inline__))
-__builtin_crypto_vncipher(vector unsigned long long __a,
- vector unsigned long long __b) {
+static __inline__ vector unsigned char __attribute__((__always_inline__))
+__builtin_crypto_vncipher(vector unsigned char __a,
+ vector unsigned char __b) {
return __builtin_altivec_crypto_vncipher(__a, __b);
}
-static __inline__ vector unsigned long long __attribute__((__always_inline__))
-__builtin_crypto_vncipherlast(vector unsigned long long __a,
- vector unsigned long long __b) {
+static __inline__ vector unsigned char __attribute__((__always_inline__))
+__builtin_crypto_vncipherlast(vector unsigned char __a,
+ vector unsigned char __b) {
return __builtin_altivec_crypto_vncipherlast(__a, __b);
}
#endif /* __VSX__ */
diff --git a/clang/lib/Headers/amxfp16intrin.h b/clang/lib/Headers/amxfp16intrin.h
new file mode 100644
index 000000000000..ed798245d41e
--- /dev/null
+++ b/clang/lib/Headers/amxfp16intrin.h
@@ -0,0 +1,58 @@
+/*===------------- amxfp16intrin.h - AMX_FP16 intrinsics -*- 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 __IMMINTRIN_H
+#error "Never use <amxfp16intrin.h> directly; use <immintrin.h> instead."
+#endif /* __IMMINTRIN_H */
+
+#ifndef __AMX_FP16INTRIN_H
+#define __AMX_FP16INTRIN_H
+#ifdef __x86_64__
+
+/// Compute dot-product of FP16 (16-bit) floating-point pairs in tiles \a a
+/// and \a b, accumulating the intermediate single-precision (32-bit)
+/// floating-point elements with elements in \a dst, and store the 32-bit
+/// result back to tile \a dst.
+///
+/// \headerfile <immintrin.h>
+///
+/// \code
+/// void _tile_dpfp16ps (__tile dst, __tile a, __tile b)
+/// \endcode
+///
+/// \code{.operation}
+/// FOR m := 0 TO dst.rows - 1
+/// tmp := dst.row[m]
+/// FOR k := 0 TO (a.colsb / 4) - 1
+/// FOR n := 0 TO (dst.colsb / 4) - 1
+/// tmp.fp32[n] += FP32(a.row[m].fp16[2*k+0]) *
+/// FP32(b.row[k].fp16[2*n+0])
+/// tmp.fp32[n] += FP32(a.row[m].fp16[2*k+1]) *
+/// FP32(b.row[k].fp16[2*n+1])
+/// ENDFOR
+/// ENDFOR
+/// write_row_and_zero(dst, m, tmp, dst.colsb)
+/// ENDFOR
+/// zero_upper_rows(dst, dst.rows)
+/// zero_tileconfig_start()
+/// \endcode
+///
+/// This intrinsic corresponds to the \c TDPFP16PS instruction.
+///
+/// \param dst
+/// The destination tile. Max size is 1024 Bytes.
+/// \param a
+/// The 1st source tile. Max size is 1024 Bytes.
+/// \param b
+/// The 2nd source tile. Max size is 1024 Bytes.
+#define _tile_dpfp16ps(dst, a, b) \
+ __builtin_ia32_tdpfp16ps(dst, a, b)
+
+#endif /* __x86_64__ */
+#endif /* __AMX_FP16INTRIN_H */
diff --git a/clang/lib/Headers/amxintrin.h b/clang/lib/Headers/amxintrin.h
index ec67a87e39ca..baa56f5b28e8 100644
--- a/clang/lib/Headers/amxintrin.h
+++ b/clang/lib/Headers/amxintrin.h
@@ -22,6 +22,8 @@
__attribute__((__always_inline__, __nodebug__, __target__("amx-int8")))
#define __DEFAULT_FN_ATTRS_BF16 \
__attribute__((__always_inline__, __nodebug__, __target__("amx-bf16")))
+#define __DEFAULT_FN_ATTRS_FP16 \
+ __attribute__((__always_inline__, __nodebug__, __target__("amx-fp16")))
/// Load tile configuration from a 64-byte memory location specified by
/// "mem_addr". The tile configuration includes the tile type palette, the
@@ -290,6 +292,13 @@ _tile_dpbf16ps_internal(unsigned short m, unsigned short n, unsigned short k,
return __builtin_ia32_tdpbf16ps_internal(m, n, k, dst, src1, src2);
}
+/// This is internal intrinsic. C/C++ user should avoid calling it directly.
+static __inline__ _tile1024i __DEFAULT_FN_ATTRS_FP16
+_tile_dpfp16ps_internal(unsigned short m, unsigned short n, unsigned short k,
+ _tile1024i dst, _tile1024i src1, _tile1024i src2) {
+ return __builtin_ia32_tdpfp16ps_internal(m, n, k, dst, src1, src2);
+}
+
/// This struct pack the shape and tile data together for user. We suggest
/// initializing the struct as early as possible, because compiler depends
/// on the shape information to do configure. The constant value is preferred
@@ -484,9 +493,32 @@ static __inline__ void __tile_dpbf16ps(__tile1024i *dst, __tile1024i src0,
src0.tile, src1.tile);
}
+/// Compute dot-product of FP16 (16-bit) floating-point pairs in tiles src0 and
+/// src1, accumulating the intermediate single-precision (32-bit) floating-point
+/// elements with elements in "dst", and store the 32-bit result back to tile
+/// "dst".
+///
+/// \headerfile <immintrin.h>
+///
+/// This intrinsic corresponds to the <c> TDPFP16PS </c> instruction.
+///
+/// \param dst
+/// The destination tile. Max size is 1024 Bytes.
+/// \param src0
+/// The 1st source tile. Max size is 1024 Bytes.
+/// \param src1
+/// The 2nd source tile. Max size is 1024 Bytes.
+__DEFAULT_FN_ATTRS_FP16
+static __inline__ void __tile_dpfp16ps(__tile1024i *dst, __tile1024i src0,
+ __tile1024i src1) {
+ dst->tile = _tile_dpfp16ps_internal(src0.row, src1.col, src0.col, dst->tile,
+ src0.tile, src1.tile);
+}
+
#undef __DEFAULT_FN_ATTRS_TILE
#undef __DEFAULT_FN_ATTRS_INT8
#undef __DEFAULT_FN_ATTRS_BF16
+#undef __DEFAULT_FN_ATTRS_FP16
#endif /* __x86_64__ */
#endif /* __AMXINTRIN_H */
diff --git a/clang/lib/Headers/arm_acle.h b/clang/lib/Headers/arm_acle.h
index 1cfc1403276d..e086f1f02dad 100644
--- a/clang/lib/Headers/arm_acle.h
+++ b/clang/lib/Headers/arm_acle.h
@@ -64,7 +64,7 @@ static __inline__ void __attribute__((__always_inline__, __nodebug__)) __yield(v
}
#endif
-#if __ARM_32BIT_STATE
+#if defined(__ARM_32BIT_STATE) && __ARM_32BIT_STATE
#define __dbg(t) __builtin_arm_dbg(t)
#endif
@@ -82,7 +82,7 @@ __swp(uint32_t __x, volatile uint32_t *__p) {
/* 8.6.1 Data prefetch */
#define __pld(addr) __pldx(0, 0, 0, addr)
-#if __ARM_32BIT_STATE
+#if defined(__ARM_32BIT_STATE) && __ARM_32BIT_STATE
#define __pldx(access_kind, cache_level, retention_policy, addr) \
__builtin_arm_prefetch(addr, access_kind, 1)
#else
@@ -93,7 +93,7 @@ __swp(uint32_t __x, volatile uint32_t *__p) {
/* 8.6.2 Instruction prefetch */
#define __pli(addr) __plix(0, 0, addr)
-#if __ARM_32BIT_STATE
+#if defined(__ARM_32BIT_STATE) && __ARM_32BIT_STATE
#define __plix(cache_level, retention_policy, addr) \
__builtin_arm_prefetch(addr, 0, 0)
#else
@@ -140,17 +140,17 @@ __rorl(unsigned long __x, uint32_t __y) {
/* CLZ */
static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
__clz(uint32_t __t) {
- return __builtin_clz(__t);
+ return (uint32_t)__builtin_clz(__t);
}
static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
__clzl(unsigned long __t) {
- return __builtin_clzl(__t);
+ return (unsigned long)__builtin_clzl(__t);
}
static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__))
__clzll(uint64_t __t) {
- return __builtin_clzll(__t);
+ return (uint64_t)__builtin_clzll(__t);
}
/* CLS */
@@ -201,7 +201,7 @@ __rev16(uint32_t __t) {
static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__))
__rev16ll(uint64_t __t) {
- return (((uint64_t)__rev16(__t >> 32)) << 32) | __rev16(__t);
+ return (((uint64_t)__rev16(__t >> 32)) << 32) | (uint64_t)__rev16((uint32_t)__t);
}
static __inline__ unsigned long __attribute__((__always_inline__, __nodebug__))
@@ -216,7 +216,7 @@ __rev16l(unsigned long __t) {
/* REVSH */
static __inline__ int16_t __attribute__((__always_inline__, __nodebug__))
__revsh(int16_t __t) {
- return __builtin_bswap16(__t);
+ return (int16_t)__builtin_bswap16((uint16_t)__t);
}
/* RBIT */
@@ -227,7 +227,7 @@ __rbit(uint32_t __t) {
static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__))
__rbitll(uint64_t __t) {
-#if __ARM_32BIT_STATE
+#if defined(__ARM_32BIT_STATE) && __ARM_32BIT_STATE
return (((uint64_t)__builtin_arm_rbit(__t)) << 32) |
__builtin_arm_rbit(__t >> 32);
#else
@@ -247,7 +247,7 @@ __rbitl(unsigned long __t) {
/*
* 9.3 16-bit multiplications
*/
-#if __ARM_FEATURE_DSP
+#if defined(__ARM_FEATURE_DSP) && __ARM_FEATURE_DSP
static __inline__ int32_t __attribute__((__always_inline__,__nodebug__))
__smulbb(int32_t __a, int32_t __b) {
return __builtin_arm_smulbb(__a, __b);
@@ -277,17 +277,17 @@ __smulwt(int32_t __a, int32_t __b) {
/*
* 9.4 Saturating intrinsics
*
- * FIXME: Change guard to their corrosponding __ARM_FEATURE flag when Q flag
+ * FIXME: Change guard to their corresponding __ARM_FEATURE flag when Q flag
* intrinsics are implemented and the flag is enabled.
*/
/* 9.4.1 Width-specified saturation intrinsics */
-#if __ARM_FEATURE_SAT
+#if defined(__ARM_FEATURE_SAT) && __ARM_FEATURE_SAT
#define __ssat(x, y) __builtin_arm_ssat(x, y)
#define __usat(x, y) __builtin_arm_usat(x, y)
#endif
/* 9.4.2 Saturating addition and subtraction intrinsics */
-#if __ARM_FEATURE_DSP
+#if defined(__ARM_FEATURE_DSP) && __ARM_FEATURE_DSP
static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
__qadd(int32_t __t, int32_t __v) {
return __builtin_arm_qadd(__t, __v);
@@ -305,7 +305,7 @@ __qdbl(int32_t __t) {
#endif
/* 9.4.3 Accumultating multiplications */
-#if __ARM_FEATURE_DSP
+#if defined(__ARM_FEATURE_DSP) && __ARM_FEATURE_DSP
static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
__smlabb(int32_t __a, int32_t __b, int32_t __c) {
return __builtin_arm_smlabb(__a, __b, __c);
@@ -334,13 +334,13 @@ __smlawt(int32_t __a, int32_t __b, int32_t __c) {
/* 9.5.4 Parallel 16-bit saturation */
-#if __ARM_FEATURE_SIMD32
+#if defined(__ARM_FEATURE_SIMD32) && __ARM_FEATURE_SIMD32
#define __ssat16(x, y) __builtin_arm_ssat16(x, y)
#define __usat16(x, y) __builtin_arm_usat16(x, y)
#endif
/* 9.5.5 Packing and unpacking */
-#if __ARM_FEATURE_SIMD32
+#if defined(__ARM_FEATURE_SIMD32) && __ARM_FEATURE_SIMD32
typedef int32_t int8x4_t;
typedef int32_t int16x2_t;
typedef uint32_t uint8x4_t;
@@ -365,7 +365,7 @@ __uxtb16(int8x4_t __a) {
#endif
/* 9.5.6 Parallel selection */
-#if __ARM_FEATURE_SIMD32
+#if defined(__ARM_FEATURE_SIMD32) && __ARM_FEATURE_SIMD32
static __inline__ uint8x4_t __attribute__((__always_inline__, __nodebug__))
__sel(uint8x4_t __a, uint8x4_t __b) {
return __builtin_arm_sel(__a, __b);
@@ -373,7 +373,7 @@ __sel(uint8x4_t __a, uint8x4_t __b) {
#endif
/* 9.5.7 Parallel 8-bit addition and subtraction */
-#if __ARM_FEATURE_SIMD32
+#if defined(__ARM_FEATURE_SIMD32) && __ARM_FEATURE_SIMD32
static __inline__ int8x4_t __attribute__((__always_inline__, __nodebug__))
__qadd8(int8x4_t __a, int8x4_t __b) {
return __builtin_arm_qadd8(__a, __b);
@@ -425,7 +425,7 @@ __usub8(uint8x4_t __a, uint8x4_t __b) {
#endif
/* 9.5.8 Sum of 8-bit absolute differences */
-#if __ARM_FEATURE_SIMD32
+#if defined(__ARM_FEATURE_SIMD32) && __ARM_FEATURE_SIMD32
static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
__usad8(uint8x4_t __a, uint8x4_t __b) {
return __builtin_arm_usad8(__a, __b);
@@ -437,7 +437,7 @@ __usada8(uint8x4_t __a, uint8x4_t __b, uint32_t __c) {
#endif
/* 9.5.9 Parallel 16-bit addition and subtraction */
-#if __ARM_FEATURE_SIMD32
+#if defined(__ARM_FEATURE_SIMD32) && __ARM_FEATURE_SIMD32
static __inline__ int16x2_t __attribute__((__always_inline__, __nodebug__))
__qadd16(int16x2_t __a, int16x2_t __b) {
return __builtin_arm_qadd16(__a, __b);
@@ -537,7 +537,7 @@ __usub16(uint16x2_t __a, uint16x2_t __b) {
#endif
/* 9.5.10 Parallel 16-bit multiplications */
-#if __ARM_FEATURE_SIMD32
+#if defined(__ARM_FEATURE_SIMD32) && __ARM_FEATURE_SIMD32
static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
__smlad(int16x2_t __a, int16x2_t __b, int32_t __c) {
return __builtin_arm_smlad(__a, __b, __c);
@@ -589,155 +589,156 @@ __smusdx(int16x2_t __a, int16x2_t __b) {
#endif
/* 9.7 CRC32 intrinsics */
-#if __ARM_FEATURE_CRC32
-static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+#if (defined(__ARM_FEATURE_CRC32) && __ARM_FEATURE_CRC32) || \
+ (defined(__ARM_64BIT_STATE) && __ARM_64BIT_STATE)
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__, target("crc")))
__crc32b(uint32_t __a, uint8_t __b) {
return __builtin_arm_crc32b(__a, __b);
}
-static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__, target("crc")))
__crc32h(uint32_t __a, uint16_t __b) {
return __builtin_arm_crc32h(__a, __b);
}
-static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__, target("crc")))
__crc32w(uint32_t __a, uint32_t __b) {
return __builtin_arm_crc32w(__a, __b);
}
-static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__, target("crc")))
__crc32d(uint32_t __a, uint64_t __b) {
return __builtin_arm_crc32d(__a, __b);
}
-static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__, target("crc")))
__crc32cb(uint32_t __a, uint8_t __b) {
return __builtin_arm_crc32cb(__a, __b);
}
-static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__, target("crc")))
__crc32ch(uint32_t __a, uint16_t __b) {
return __builtin_arm_crc32ch(__a, __b);
}
-static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__, target("crc")))
__crc32cw(uint32_t __a, uint32_t __b) {
return __builtin_arm_crc32cw(__a, __b);
}
-static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__, target("crc")))
__crc32cd(uint32_t __a, uint64_t __b) {
return __builtin_arm_crc32cd(__a, __b);
}
#endif
/* Armv8.3-A Javascript conversion intrinsic */
-#if __ARM_64BIT_STATE && defined(__ARM_FEATURE_JCVT)
-static __inline__ int32_t __attribute__((__always_inline__, __nodebug__))
+#if defined(__ARM_64BIT_STATE) && __ARM_64BIT_STATE
+static __inline__ int32_t __attribute__((__always_inline__, __nodebug__, target("v8.3a")))
__jcvt(double __a) {
return __builtin_arm_jcvt(__a);
}
#endif
/* Armv8.5-A FP rounding intrinsics */
-#if __ARM_64BIT_STATE && defined(__ARM_FEATURE_FRINT)
-static __inline__ float __attribute__((__always_inline__, __nodebug__))
-__frint32zf(float __a) {
- return __builtin_arm_frint32zf(__a);
+#if defined(__ARM_64BIT_STATE) && __ARM_64BIT_STATE
+static __inline__ float __attribute__((__always_inline__, __nodebug__, target("v8.5a")))
+__rint32zf(float __a) {
+ return __builtin_arm_rint32zf(__a);
}
-static __inline__ double __attribute__((__always_inline__, __nodebug__))
-__frint32z(double __a) {
- return __builtin_arm_frint32z(__a);
+static __inline__ double __attribute__((__always_inline__, __nodebug__, target("v8.5a")))
+__rint32z(double __a) {
+ return __builtin_arm_rint32z(__a);
}
-static __inline__ float __attribute__((__always_inline__, __nodebug__))
-__frint64zf(float __a) {
- return __builtin_arm_frint64zf(__a);
+static __inline__ float __attribute__((__always_inline__, __nodebug__, target("v8.5a")))
+__rint64zf(float __a) {
+ return __builtin_arm_rint64zf(__a);
}
-static __inline__ double __attribute__((__always_inline__, __nodebug__))
-__frint64z(double __a) {
- return __builtin_arm_frint64z(__a);
+static __inline__ double __attribute__((__always_inline__, __nodebug__, target("v8.5a")))
+__rint64z(double __a) {
+ return __builtin_arm_rint64z(__a);
}
-static __inline__ float __attribute__((__always_inline__, __nodebug__))
-__frint32xf(float __a) {
- return __builtin_arm_frint32xf(__a);
+static __inline__ float __attribute__((__always_inline__, __nodebug__, target("v8.5a")))
+__rint32xf(float __a) {
+ return __builtin_arm_rint32xf(__a);
}
-static __inline__ double __attribute__((__always_inline__, __nodebug__))
-__frint32x(double __a) {
- return __builtin_arm_frint32x(__a);
+static __inline__ double __attribute__((__always_inline__, __nodebug__, target("v8.5a")))
+__rint32x(double __a) {
+ return __builtin_arm_rint32x(__a);
}
-static __inline__ float __attribute__((__always_inline__, __nodebug__))
-__frint64xf(float __a) {
- return __builtin_arm_frint64xf(__a);
+static __inline__ float __attribute__((__always_inline__, __nodebug__, target("v8.5a")))
+__rint64xf(float __a) {
+ return __builtin_arm_rint64xf(__a);
}
-static __inline__ double __attribute__((__always_inline__, __nodebug__))
-__frint64x(double __a) {
- return __builtin_arm_frint64x(__a);
+static __inline__ double __attribute__((__always_inline__, __nodebug__, target("v8.5a")))
+__rint64x(double __a) {
+ return __builtin_arm_rint64x(__a);
}
#endif
/* Armv8.7-A load/store 64-byte intrinsics */
-#if __ARM_64BIT_STATE && defined(__ARM_FEATURE_LS64)
+#if defined(__ARM_64BIT_STATE) && __ARM_64BIT_STATE
typedef struct {
uint64_t val[8];
} data512_t;
-static __inline__ data512_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ data512_t __attribute__((__always_inline__, __nodebug__, target("ls64")))
__arm_ld64b(const void *__addr) {
- data512_t __value;
- __builtin_arm_ld64b(__addr, __value.val);
- return __value;
+ data512_t __value;
+ __builtin_arm_ld64b(__addr, __value.val);
+ return __value;
}
-static __inline__ void __attribute__((__always_inline__, __nodebug__))
+static __inline__ void __attribute__((__always_inline__, __nodebug__, target("ls64")))
__arm_st64b(void *__addr, data512_t __value) {
- __builtin_arm_st64b(__addr, __value.val);
+ __builtin_arm_st64b(__addr, __value.val);
}
-static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__, target("ls64")))
__arm_st64bv(void *__addr, data512_t __value) {
- return __builtin_arm_st64bv(__addr, __value.val);
+ return __builtin_arm_st64bv(__addr, __value.val);
}
-static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__))
+static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__, target("ls64")))
__arm_st64bv0(void *__addr, data512_t __value) {
- return __builtin_arm_st64bv0(__addr, __value.val);
+ return __builtin_arm_st64bv0(__addr, __value.val);
}
#endif
/* 10.1 Special register intrinsics */
#define __arm_rsr(sysreg) __builtin_arm_rsr(sysreg)
#define __arm_rsr64(sysreg) __builtin_arm_rsr64(sysreg)
+#define __arm_rsr128(sysreg) __builtin_arm_rsr128(sysreg)
#define __arm_rsrp(sysreg) __builtin_arm_rsrp(sysreg)
#define __arm_rsrf(sysreg) __builtin_bit_cast(float, __arm_rsr(sysreg))
#define __arm_rsrf64(sysreg) __builtin_bit_cast(double, __arm_rsr64(sysreg))
#define __arm_wsr(sysreg, v) __builtin_arm_wsr(sysreg, v)
#define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v)
+#define __arm_wsr128(sysreg, v) __builtin_arm_wsr128(sysreg, v)
#define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v)
#define __arm_wsrf(sysreg, v) __arm_wsr(sysreg, __builtin_bit_cast(uint32_t, v))
#define __arm_wsrf64(sysreg, v) __arm_wsr64(sysreg, __builtin_bit_cast(uint64_t, v))
/* Memory Tagging Extensions (MTE) Intrinsics */
-#if __ARM_FEATURE_MEMORY_TAGGING
+#if defined(__ARM_64BIT_STATE) && __ARM_64BIT_STATE
#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)
#define __arm_mte_exclude_tag(__ptr, __excluded) __builtin_arm_gmi(__ptr, __excluded)
#define __arm_mte_get_tag(__ptr) __builtin_arm_ldg(__ptr)
#define __arm_mte_set_tag(__ptr) __builtin_arm_stg(__ptr)
#define __arm_mte_ptrdiff(__ptra, __ptrb) __builtin_arm_subp(__ptra, __ptrb)
-#endif
/* Memory Operations Intrinsics */
-#if __ARM_FEATURE_MOPS && __ARM_FEATURE_MEMORY_TAGGING
#define __arm_mops_memset_tag(__tagged_address, __value, __size) \
__builtin_arm_mops_memset_tag(__tagged_address, __value, __size)
#endif
/* Transactional Memory Extension (TME) Intrinsics */
-#if __ARM_FEATURE_TME
+#if defined(__ARM_FEATURE_TME) && __ARM_FEATURE_TME
#define _TMFAILURE_REASON 0x00007fffu
#define _TMFAILURE_RTRY 0x00008000u
@@ -759,12 +760,12 @@ __arm_st64bv0(void *__addr, data512_t __value) {
#endif /* __ARM_FEATURE_TME */
/* Armv8.5-A Random number generation intrinsics */
-#if __ARM_64BIT_STATE && defined(__ARM_FEATURE_RNG)
-static __inline__ int __attribute__((__always_inline__, __nodebug__))
+#if defined(__ARM_64BIT_STATE) && __ARM_64BIT_STATE
+static __inline__ int __attribute__((__always_inline__, __nodebug__, target("rand")))
__rndr(uint64_t *__p) {
return __builtin_arm_rndr(__p);
}
-static __inline__ int __attribute__((__always_inline__, __nodebug__))
+static __inline__ int __attribute__((__always_inline__, __nodebug__, target("rand")))
__rndrrs(uint64_t *__p) {
return __builtin_arm_rndrrs(__p);
}
diff --git a/clang/lib/Headers/arm_neon_sve_bridge.h b/clang/lib/Headers/arm_neon_sve_bridge.h
index 17699d8d11dd..a9fbdbaf4bb9 100644
--- a/clang/lib/Headers/arm_neon_sve_bridge.h
+++ b/clang/lib/Headers/arm_neon_sve_bridge.h
@@ -159,7 +159,6 @@ svfloat32_t svdup_neonq_f32(float32x4_t);
__ai __attribute__((__clang_arm_builtin_alias(__builtin_sve_svdup_neonq_f64)))
svfloat64_t svdup_neonq_f64(float64x2_t);
-#if defined(__ARM_FEATURE_SVE_BF16)
__aio __attribute__((__clang_arm_builtin_alias(__builtin_sve_svset_neonq_bf16)))
svbfloat16_t svset_neonq(svbfloat16_t, bfloat16x8_t);
__ai __attribute__((__clang_arm_builtin_alias(__builtin_sve_svset_neonq_bf16)))
@@ -172,7 +171,6 @@ __aio __attribute__((__clang_arm_builtin_alias(__builtin_sve_svdup_neonq_bf16)))
svbfloat16_t svdup_neonq(bfloat16x8_t);
__ai __attribute__((__clang_arm_builtin_alias(__builtin_sve_svdup_neonq_bf16)))
svbfloat16_t svdup_neonq_bf16(bfloat16x8_t);
-#endif // defined(__ARM_FEATURE_SVE_BF16)
#undef __ai
#undef __aio
diff --git a/clang/lib/Headers/avx512bf16intrin.h b/clang/lib/Headers/avx512bf16intrin.h
index 09653738d40a..a864c1e3350b 100644
--- a/clang/lib/Headers/avx512bf16intrin.h
+++ b/clang/lib/Headers/avx512bf16intrin.h
@@ -10,12 +10,14 @@
#error "Never use <avx512bf16intrin.h> directly; include <immintrin.h> instead."
#endif
+#ifdef __SSE2__
+
#ifndef __AVX512BF16INTRIN_H
#define __AVX512BF16INTRIN_H
-typedef short __m512bh __attribute__((__vector_size__(64), __aligned__(64)));
-typedef short __m256bh __attribute__((__vector_size__(32), __aligned__(32)));
-typedef unsigned short __bfloat16;
+typedef __bf16 __v32bf __attribute__((__vector_size__(64), __aligned__(64)));
+typedef __bf16 __m512bh __attribute__((__vector_size__(64), __aligned__(64)));
+typedef __bf16 __bfloat16 __attribute__((deprecated("use __bf16 instead")));
#define __DEFAULT_FN_ATTRS512 \
__attribute__((__always_inline__, __nodebug__, __target__("avx512bf16"), \
@@ -33,7 +35,7 @@ typedef unsigned short __bfloat16;
/// A bfloat data.
/// \returns A float data whose sign field and exponent field keep unchanged,
/// and fraction field is extended to 23 bits.
-static __inline__ float __DEFAULT_FN_ATTRS _mm_cvtsbh_ss(__bfloat16 __A) {
+static __inline__ float __DEFAULT_FN_ATTRS _mm_cvtsbh_ss(__bf16 __A) {
return __builtin_ia32_cvtsbf162ss_32(__A);
}
@@ -74,9 +76,9 @@ _mm512_cvtne2ps_pbh(__m512 __A, __m512 __B) {
/// conversion of __B, and higher 256 bits come from conversion of __A.
static __inline__ __m512bh __DEFAULT_FN_ATTRS512
_mm512_mask_cvtne2ps_pbh(__m512bh __W, __mmask32 __U, __m512 __A, __m512 __B) {
- return (__m512bh)__builtin_ia32_selectw_512((__mmask32)__U,
- (__v32hi)_mm512_cvtne2ps_pbh(__A, __B),
- (__v32hi)__W);
+ return (__m512bh)__builtin_ia32_selectpbf_512((__mmask32)__U,
+ (__v32bf)_mm512_cvtne2ps_pbh(__A, __B),
+ (__v32bf)__W);
}
/// Convert Two Packed Single Data to One Packed BF16 Data.
@@ -96,9 +98,9 @@ _mm512_mask_cvtne2ps_pbh(__m512bh __W, __mmask32 __U, __m512 __A, __m512 __B) {
/// conversion of __B, and higher 256 bits come from conversion of __A.
static __inline__ __m512bh __DEFAULT_FN_ATTRS512
_mm512_maskz_cvtne2ps_pbh(__mmask32 __U, __m512 __A, __m512 __B) {
- return (__m512bh)__builtin_ia32_selectw_512((__mmask32)__U,
- (__v32hi)_mm512_cvtne2ps_pbh(__A, __B),
- (__v32hi)_mm512_setzero_si512());
+ return (__m512bh)__builtin_ia32_selectpbf_512((__mmask32)__U,
+ (__v32bf)_mm512_cvtne2ps_pbh(__A, __B),
+ (__v32bf)_mm512_setzero_si512());
}
/// Convert Packed Single Data to Packed BF16 Data.
@@ -113,7 +115,7 @@ _mm512_maskz_cvtne2ps_pbh(__mmask32 __U, __m512 __A, __m512 __B) {
static __inline__ __m256bh __DEFAULT_FN_ATTRS512
_mm512_cvtneps_pbh(__m512 __A) {
return (__m256bh)__builtin_ia32_cvtneps2bf16_512_mask((__v16sf)__A,
- (__v16hi)_mm256_undefined_si256(),
+ (__v16bf)_mm256_undefined_si256(),
(__mmask16)-1);
}
@@ -134,7 +136,7 @@ _mm512_cvtneps_pbh(__m512 __A) {
static __inline__ __m256bh __DEFAULT_FN_ATTRS512
_mm512_mask_cvtneps_pbh(__m256bh __W, __mmask16 __U, __m512 __A) {
return (__m256bh)__builtin_ia32_cvtneps2bf16_512_mask((__v16sf)__A,
- (__v16hi)__W,
+ (__v16bf)__W,
(__mmask16)__U);
}
@@ -153,7 +155,7 @@ _mm512_mask_cvtneps_pbh(__m256bh __W, __mmask16 __U, __m512 __A) {
static __inline__ __m256bh __DEFAULT_FN_ATTRS512
_mm512_maskz_cvtneps_pbh(__mmask16 __U, __m512 __A) {
return (__m256bh)__builtin_ia32_cvtneps2bf16_512_mask((__v16sf)__A,
- (__v16hi)_mm256_setzero_si256(),
+ (__v16bf)_mm256_setzero_si256(),
(__mmask16)__U);
}
@@ -174,8 +176,8 @@ _mm512_maskz_cvtneps_pbh(__mmask16 __U, __m512 __A) {
static __inline__ __m512 __DEFAULT_FN_ATTRS512
_mm512_dpbf16_ps(__m512 __D, __m512bh __A, __m512bh __B) {
return (__m512)__builtin_ia32_dpbf16ps_512((__v16sf) __D,
- (__v16si) __A,
- (__v16si) __B);
+ (__v32bf) __A,
+ (__v32bf) __B);
}
/// Dot Product of BF16 Pairs Accumulated into Packed Single Precision.
@@ -277,3 +279,4 @@ _mm512_mask_cvtpbh_ps(__m512 __S, __mmask16 __U, __m256bh __A) {
#undef __DEFAULT_FN_ATTRS512
#endif
+#endif
diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h
index 61bc89c2b895..b19d2fb90ff5 100644
--- a/clang/lib/Headers/avx512fintrin.h
+++ b/clang/lib/Headers/avx512fintrin.h
@@ -256,8 +256,8 @@ _mm512_maskz_broadcastq_epi64 (__mmask8 __M, __m128i __A)
static __inline __m512 __DEFAULT_FN_ATTRS512
_mm512_setzero_ps(void)
{
- return __extension__ (__m512){ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
- 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
+ return __extension__ (__m512){ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
}
#define _mm512_setzero _mm512_setzero_ps
diff --git a/clang/lib/Headers/avx512fp16intrin.h b/clang/lib/Headers/avx512fp16intrin.h
index 99409a31b32b..5cdc37fde629 100644
--- a/clang/lib/Headers/avx512fp16intrin.h
+++ b/clang/lib/Headers/avx512fp16intrin.h
@@ -10,6 +10,8 @@
#error "Never use <avx512fp16intrin.h> directly; include <immintrin.h> instead."
#endif
+#ifdef __SSE2__
+
#ifndef __AVX512FP16INTRIN_H
#define __AVX512FP16INTRIN_H
@@ -17,12 +19,6 @@
typedef _Float16 __v32hf __attribute__((__vector_size__(64), __aligned__(64)));
typedef _Float16 __m512h __attribute__((__vector_size__(64), __aligned__(64)));
typedef _Float16 __m512h_u __attribute__((__vector_size__(64), __aligned__(1)));
-typedef _Float16 __v8hf __attribute__((__vector_size__(16), __aligned__(16)));
-typedef _Float16 __m128h __attribute__((__vector_size__(16), __aligned__(16)));
-typedef _Float16 __m128h_u __attribute__((__vector_size__(16), __aligned__(1)));
-typedef _Float16 __v16hf __attribute__((__vector_size__(32), __aligned__(32)));
-typedef _Float16 __m256h __attribute__((__vector_size__(32), __aligned__(32)));
-typedef _Float16 __m256h_u __attribute__((__vector_size__(32), __aligned__(1)));
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS512 \
@@ -829,7 +825,7 @@ static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_load_sh(void const *__dp) {
struct __mm_load_sh_struct {
_Float16 __u;
} __attribute__((__packed__, __may_alias__));
- _Float16 __u = ((struct __mm_load_sh_struct *)__dp)->__u;
+ _Float16 __u = ((const struct __mm_load_sh_struct *)__dp)->__u;
return (__m128h){__u, 0, 0, 0, 0, 0, 0, 0};
}
@@ -838,13 +834,13 @@ _mm_mask_load_sh(__m128h __W, __mmask8 __U, const void *__A) {
__m128h src = (__v8hf)__builtin_shufflevector(
(__v8hf)__W, (__v8hf)_mm_setzero_ph(), 0, 8, 8, 8, 8, 8, 8, 8);
- return (__m128h)__builtin_ia32_loadsh128_mask((__v8hf *)__A, src, __U & 1);
+ return (__m128h)__builtin_ia32_loadsh128_mask((const __v8hf *)__A, src, __U & 1);
}
static __inline__ __m128h __DEFAULT_FN_ATTRS128
_mm_maskz_load_sh(__mmask8 __U, const void *__A) {
return (__m128h)__builtin_ia32_loadsh128_mask(
- (__v8hf *)__A, (__v8hf)_mm_setzero_ph(), __U & 1);
+ (const __v8hf *)__A, (__v8hf)_mm_setzero_ph(), __U & 1);
}
static __inline__ __m512h __DEFAULT_FN_ATTRS512
@@ -3347,3 +3343,4 @@ _mm512_permutexvar_ph(__m512i __A, __m512h __B) {
#undef __DEFAULT_FN_ATTRS512
#endif
+#endif
diff --git a/clang/lib/Headers/avx512ifmavlintrin.h b/clang/lib/Headers/avx512ifmavlintrin.h
index 5889401d1055..3284ee182004 100644
--- a/clang/lib/Headers/avx512ifmavlintrin.h
+++ b/clang/lib/Headers/avx512ifmavlintrin.h
@@ -18,14 +18,21 @@
#define __DEFAULT_FN_ATTRS128 __attribute__((__always_inline__, __nodebug__, __target__("avx512ifma,avx512vl"), __min_vector_width__(128)))
#define __DEFAULT_FN_ATTRS256 __attribute__((__always_inline__, __nodebug__, __target__("avx512ifma,avx512vl"), __min_vector_width__(256)))
+#define _mm_madd52hi_epu64(X, Y, Z) \
+ ((__m128i)__builtin_ia32_vpmadd52huq128((__v2di)(X), (__v2di)(Y), \
+ (__v2di)(Z)))
+#define _mm256_madd52hi_epu64(X, Y, Z) \
+ ((__m256i)__builtin_ia32_vpmadd52huq256((__v4di)(X), (__v4di)(Y), \
+ (__v4di)(Z)))
-static __inline__ __m128i __DEFAULT_FN_ATTRS128
-_mm_madd52hi_epu64 (__m128i __X, __m128i __Y, __m128i __Z)
-{
- return (__m128i)__builtin_ia32_vpmadd52huq128((__v2di) __X, (__v2di) __Y,
- (__v2di) __Z);
-}
+#define _mm_madd52lo_epu64(X, Y, Z) \
+ ((__m128i)__builtin_ia32_vpmadd52luq128((__v2di)(X), (__v2di)(Y), \
+ (__v2di)(Z)))
+
+#define _mm256_madd52lo_epu64(X, Y, Z) \
+ ((__m256i)__builtin_ia32_vpmadd52luq256((__v4di)(X), (__v4di)(Y), \
+ (__v4di)(Z)))
static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_madd52hi_epu64 (__m128i __W, __mmask8 __M, __m128i __X, __m128i __Y)
@@ -44,13 +51,6 @@ _mm_maskz_madd52hi_epu64 (__mmask8 __M, __m128i __X, __m128i __Y, __m128i __Z)
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
-_mm256_madd52hi_epu64 (__m256i __X, __m256i __Y, __m256i __Z)
-{
- return (__m256i)__builtin_ia32_vpmadd52huq256((__v4di)__X, (__v4di)__Y,
- (__v4di)__Z);
-}
-
-static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_madd52hi_epu64 (__m256i __W, __mmask8 __M, __m256i __X, __m256i __Y)
{
return (__m256i)__builtin_ia32_selectq_256(__M,
@@ -67,13 +67,6 @@ _mm256_maskz_madd52hi_epu64 (__mmask8 __M, __m256i __X, __m256i __Y, __m256i __Z
}
static __inline__ __m128i __DEFAULT_FN_ATTRS128
-_mm_madd52lo_epu64 (__m128i __X, __m128i __Y, __m128i __Z)
-{
- return (__m128i)__builtin_ia32_vpmadd52luq128((__v2di)__X, (__v2di)__Y,
- (__v2di)__Z);
-}
-
-static __inline__ __m128i __DEFAULT_FN_ATTRS128
_mm_mask_madd52lo_epu64 (__m128i __W, __mmask8 __M, __m128i __X, __m128i __Y)
{
return (__m128i)__builtin_ia32_selectq_128(__M,
@@ -90,13 +83,6 @@ _mm_maskz_madd52lo_epu64 (__mmask8 __M, __m128i __X, __m128i __Y, __m128i __Z)
}
static __inline__ __m256i __DEFAULT_FN_ATTRS256
-_mm256_madd52lo_epu64 (__m256i __X, __m256i __Y, __m256i __Z)
-{
- return (__m256i)__builtin_ia32_vpmadd52luq256((__v4di)__X, (__v4di)__Y,
- (__v4di)__Z);
-}
-
-static __inline__ __m256i __DEFAULT_FN_ATTRS256
_mm256_mask_madd52lo_epu64 (__m256i __W, __mmask8 __M, __m256i __X, __m256i __Y)
{
return (__m256i)__builtin_ia32_selectq_256(__M,
diff --git a/clang/lib/Headers/avx512vlbf16intrin.h b/clang/lib/Headers/avx512vlbf16intrin.h
index 1cdbb28484ac..f5b8911fac2a 100644
--- a/clang/lib/Headers/avx512vlbf16intrin.h
+++ b/clang/lib/Headers/avx512vlbf16intrin.h
@@ -10,11 +10,11 @@
#error "Never use <avx512vlbf16intrin.h> directly; include <immintrin.h> instead."
#endif
+#ifdef __SSE2__
+
#ifndef __AVX512VLBF16INTRIN_H
#define __AVX512VLBF16INTRIN_H
-typedef short __m128bh __attribute__((__vector_size__(16), __aligned__(16)));
-
#define __DEFAULT_FN_ATTRS128 \
__attribute__((__always_inline__, __nodebug__, \
__target__("avx512vl, avx512bf16"), __min_vector_width__(128)))
@@ -59,9 +59,9 @@ _mm_cvtne2ps_pbh(__m128 __A, __m128 __B) {
/// conversion of __B, and higher 64 bits come from conversion of __A.
static __inline__ __m128bh __DEFAULT_FN_ATTRS128
_mm_mask_cvtne2ps_pbh(__m128bh __W, __mmask8 __U, __m128 __A, __m128 __B) {
- return (__m128bh)__builtin_ia32_selectw_128((__mmask8)__U,
- (__v8hi)_mm_cvtne2ps_pbh(__A, __B),
- (__v8hi)__W);
+ return (__m128bh)__builtin_ia32_selectpbf_128((__mmask8)__U,
+ (__v8bf)_mm_cvtne2ps_pbh(__A, __B),
+ (__v8bf)__W);
}
/// Convert Two Packed Single Data to One Packed BF16 Data.
@@ -81,9 +81,9 @@ _mm_mask_cvtne2ps_pbh(__m128bh __W, __mmask8 __U, __m128 __A, __m128 __B) {
/// conversion of __B, and higher 64 bits come from conversion of __A.
static __inline__ __m128bh __DEFAULT_FN_ATTRS128
_mm_maskz_cvtne2ps_pbh(__mmask8 __U, __m128 __A, __m128 __B) {
- return (__m128bh)__builtin_ia32_selectw_128((__mmask8)__U,
- (__v8hi)_mm_cvtne2ps_pbh(__A, __B),
- (__v8hi)_mm_setzero_si128());
+ return (__m128bh)__builtin_ia32_selectpbf_128((__mmask8)__U,
+ (__v8bf)_mm_cvtne2ps_pbh(__A, __B),
+ (__v8bf)_mm_setzero_si128());
}
/// Convert Two Packed Single Data to One Packed BF16 Data.
@@ -123,9 +123,9 @@ _mm256_cvtne2ps_pbh(__m256 __A, __m256 __B) {
/// conversion of __B, and higher 128 bits come from conversion of __A.
static __inline__ __m256bh __DEFAULT_FN_ATTRS256
_mm256_mask_cvtne2ps_pbh(__m256bh __W, __mmask16 __U, __m256 __A, __m256 __B) {
- return (__m256bh)__builtin_ia32_selectw_256((__mmask16)__U,
- (__v16hi)_mm256_cvtne2ps_pbh(__A, __B),
- (__v16hi)__W);
+ return (__m256bh)__builtin_ia32_selectpbf_256((__mmask16)__U,
+ (__v16bf)_mm256_cvtne2ps_pbh(__A, __B),
+ (__v16bf)__W);
}
/// Convert Two Packed Single Data to One Packed BF16 Data.
@@ -145,9 +145,9 @@ _mm256_mask_cvtne2ps_pbh(__m256bh __W, __mmask16 __U, __m256 __A, __m256 __B) {
/// conversion of __B, and higher 128 bits come from conversion of __A.
static __inline__ __m256bh __DEFAULT_FN_ATTRS256
_mm256_maskz_cvtne2ps_pbh(__mmask16 __U, __m256 __A, __m256 __B) {
- return (__m256bh)__builtin_ia32_selectw_256((__mmask16)__U,
- (__v16hi)_mm256_cvtne2ps_pbh(__A, __B),
- (__v16hi)_mm256_setzero_si256());
+ return (__m256bh)__builtin_ia32_selectpbf_256((__mmask16)__U,
+ (__v16bf)_mm256_cvtne2ps_pbh(__A, __B),
+ (__v16bf)_mm256_setzero_si256());
}
/// Convert Packed Single Data to Packed BF16 Data.
@@ -160,12 +160,8 @@ _mm256_maskz_cvtne2ps_pbh(__mmask16 __U, __m256 __A, __m256 __B) {
/// A 128-bit vector of [4 x float].
/// \returns A 128-bit vector of [8 x bfloat] whose lower 64 bits come from
/// conversion of __A, and higher 64 bits are 0.
-static __inline__ __m128bh __DEFAULT_FN_ATTRS128
-_mm_cvtneps_pbh(__m128 __A) {
- return (__m128bh)__builtin_ia32_cvtneps2bf16_128_mask((__v4sf) __A,
- (__v8hi)_mm_undefined_si128(),
- (__mmask8)-1);
-}
+#define _mm_cvtneps_pbh(A) \
+ ((__m128bh)__builtin_ia32_vcvtneps2bf16128((__v4sf)(A)))
/// Convert Packed Single Data to Packed BF16 Data.
///
@@ -185,7 +181,7 @@ _mm_cvtneps_pbh(__m128 __A) {
static __inline__ __m128bh __DEFAULT_FN_ATTRS128
_mm_mask_cvtneps_pbh(__m128bh __W, __mmask8 __U, __m128 __A) {
return (__m128bh)__builtin_ia32_cvtneps2bf16_128_mask((__v4sf) __A,
- (__v8hi)__W,
+ (__v8bf)__W,
(__mmask8)__U);
}
@@ -205,7 +201,7 @@ _mm_mask_cvtneps_pbh(__m128bh __W, __mmask8 __U, __m128 __A) {
static __inline__ __m128bh __DEFAULT_FN_ATTRS128
_mm_maskz_cvtneps_pbh(__mmask8 __U, __m128 __A) {
return (__m128bh)__builtin_ia32_cvtneps2bf16_128_mask((__v4sf) __A,
- (__v8hi)_mm_setzero_si128(),
+ (__v8bf)_mm_setzero_si128(),
(__mmask8)__U);
}
@@ -218,12 +214,8 @@ _mm_maskz_cvtneps_pbh(__mmask8 __U, __m128 __A) {
/// \param __A
/// A 256-bit vector of [8 x float].
/// \returns A 128-bit vector of [8 x bfloat] comes from conversion of __A.
-static __inline__ __m128bh __DEFAULT_FN_ATTRS256
-_mm256_cvtneps_pbh(__m256 __A) {
- return (__m128bh)__builtin_ia32_cvtneps2bf16_256_mask((__v8sf)__A,
- (__v8hi)_mm_undefined_si128(),
- (__mmask8)-1);
-}
+#define _mm256_cvtneps_pbh(A) \
+ ((__m128bh)__builtin_ia32_vcvtneps2bf16256((__v8sf)(A)))
/// Convert Packed Single Data to Packed BF16 Data.
///
@@ -242,7 +234,7 @@ _mm256_cvtneps_pbh(__m256 __A) {
static __inline__ __m128bh __DEFAULT_FN_ATTRS256
_mm256_mask_cvtneps_pbh(__m128bh __W, __mmask8 __U, __m256 __A) {
return (__m128bh)__builtin_ia32_cvtneps2bf16_256_mask((__v8sf)__A,
- (__v8hi)__W,
+ (__v8bf)__W,
(__mmask8)__U);
}
@@ -261,7 +253,7 @@ _mm256_mask_cvtneps_pbh(__m128bh __W, __mmask8 __U, __m256 __A) {
static __inline__ __m128bh __DEFAULT_FN_ATTRS256
_mm256_maskz_cvtneps_pbh(__mmask8 __U, __m256 __A) {
return (__m128bh)__builtin_ia32_cvtneps2bf16_256_mask((__v8sf)__A,
- (__v8hi)_mm_setzero_si128(),
+ (__v8bf)_mm_setzero_si128(),
(__mmask8)__U);
}
@@ -282,8 +274,8 @@ _mm256_maskz_cvtneps_pbh(__mmask8 __U, __m256 __A) {
static __inline__ __m128 __DEFAULT_FN_ATTRS128
_mm_dpbf16_ps(__m128 __D, __m128bh __A, __m128bh __B) {
return (__m128)__builtin_ia32_dpbf16ps_128((__v4sf)__D,
- (__v4si)__A,
- (__v4si)__B);
+ (__v8bf)__A,
+ (__v8bf)__B);
}
/// Dot Product of BF16 Pairs Accumulated into Packed Single Precision.
@@ -351,8 +343,8 @@ _mm_maskz_dpbf16_ps(__mmask8 __U, __m128 __D, __m128bh __A, __m128bh __B) {
static __inline__ __m256 __DEFAULT_FN_ATTRS256
_mm256_dpbf16_ps(__m256 __D, __m256bh __A, __m256bh __B) {
return (__m256)__builtin_ia32_dpbf16ps_256((__v8sf)__D,
- (__v8si)__A,
- (__v8si)__B);
+ (__v16bf)__A,
+ (__v16bf)__B);
}
/// Dot Product of BF16 Pairs Accumulated into Packed Single Precision.
@@ -413,11 +405,11 @@ _mm256_maskz_dpbf16_ps(__mmask8 __U, __m256 __D, __m256bh __A, __m256bh __B) {
/// A float data.
/// \returns A bf16 data whose sign field and exponent field keep unchanged,
/// and fraction field is truncated to 7 bits.
-static __inline__ __bfloat16 __DEFAULT_FN_ATTRS128 _mm_cvtness_sbh(float __A) {
+static __inline__ __bf16 __DEFAULT_FN_ATTRS128 _mm_cvtness_sbh(float __A) {
__v4sf __V = {__A, 0, 0, 0};
- __v8hi __R = __builtin_ia32_cvtneps2bf16_128_mask(
- (__v4sf)__V, (__v8hi)_mm_undefined_si128(), (__mmask8)-1);
- return (__bfloat16)__R[0];
+ __v8bf __R = __builtin_ia32_cvtneps2bf16_128_mask(
+ (__v4sf)__V, (__v8bf)_mm_undefined_si128(), (__mmask8)-1);
+ return (__bf16)__R[0];
}
/// Convert Packed BF16 Data to Packed float Data.
@@ -520,3 +512,4 @@ _mm256_mask_cvtpbh_ps(__m256 __S, __mmask8 __U, __m128bh __A) {
#undef __DEFAULT_FN_ATTRS256
#endif
+#endif
diff --git a/clang/lib/Headers/avx512vlbwintrin.h b/clang/lib/Headers/avx512vlbwintrin.h
index 521ccab27e04..148af5ab9a34 100644
--- a/clang/lib/Headers/avx512vlbwintrin.h
+++ b/clang/lib/Headers/avx512vlbwintrin.h
@@ -2803,6 +2803,358 @@ _mm256_mask_permutexvar_epi16 (__m256i __W, __mmask16 __M, __m256i __A,
(__v16hi)_mm256_dbsad_epu8((A), (B), (imm)), \
(__v16hi)_mm256_setzero_si256()))
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_reduce_add_epi16(__m128i __W) {
+ return __builtin_reduce_add((__v8hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_reduce_mul_epi16(__m128i __W) {
+ return __builtin_reduce_mul((__v8hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_reduce_and_epi16(__m128i __W) {
+ return __builtin_reduce_and((__v8hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_reduce_or_epi16(__m128i __W) {
+ return __builtin_reduce_or((__v8hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_add_epi16( __mmask8 __M, __m128i __W) {
+ __W = _mm_maskz_mov_epi16(__M, __W);
+ return __builtin_reduce_add((__v8hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_mul_epi16( __mmask8 __M, __m128i __W) {
+ __W = _mm_mask_mov_epi16(_mm_set1_epi16(1), __M, __W);
+ return __builtin_reduce_mul((__v8hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_and_epi16( __mmask8 __M, __m128i __W) {
+ __W = _mm_mask_mov_epi16(_mm_set1_epi16(-1), __M, __W);
+ return __builtin_reduce_and((__v8hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_or_epi16(__mmask8 __M, __m128i __W) {
+ __W = _mm_maskz_mov_epi16(__M, __W);
+ return __builtin_reduce_or((__v8hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_reduce_max_epi16(__m128i __V) {
+ return __builtin_reduce_max((__v8hi)__V);
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS128
+_mm_reduce_max_epu16(__m128i __V) {
+ return __builtin_reduce_max((__v8hu)__V);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_reduce_min_epi16(__m128i __V) {
+ return __builtin_reduce_min((__v8hi)__V);
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS128
+_mm_reduce_min_epu16(__m128i __V) {
+ return __builtin_reduce_min((__v8hu)__V);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_max_epi16(__mmask16 __M, __m128i __V) {
+ __V = _mm_mask_mov_epi16(_mm_set1_epi16(-32767-1), __M, __V);
+ return __builtin_reduce_max((__v8hi)__V);
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_max_epu16(__mmask16 __M, __m128i __V) {
+ __V = _mm_maskz_mov_epi16(__M, __V);
+ return __builtin_reduce_max((__v8hu)__V);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_min_epi16(__mmask16 __M, __m128i __V) {
+ __V = _mm_mask_mov_epi16(_mm_set1_epi16(32767), __M, __V);
+ return __builtin_reduce_min((__v8hi)__V);
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_min_epu16(__mmask16 __M, __m128i __V) {
+ __V = _mm_mask_mov_epi16(_mm_set1_epi16(-1), __M, __V);
+ return __builtin_reduce_min((__v8hu)__V);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_reduce_add_epi16(__m256i __W) {
+ return __builtin_reduce_add((__v16hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_reduce_mul_epi16(__m256i __W) {
+ return __builtin_reduce_mul((__v16hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_reduce_and_epi16(__m256i __W) {
+ return __builtin_reduce_and((__v16hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_reduce_or_epi16(__m256i __W) {
+ return __builtin_reduce_or((__v16hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_add_epi16( __mmask16 __M, __m256i __W) {
+ __W = _mm256_maskz_mov_epi16(__M, __W);
+ return __builtin_reduce_add((__v16hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_mul_epi16( __mmask16 __M, __m256i __W) {
+ __W = _mm256_mask_mov_epi16(_mm256_set1_epi16(1), __M, __W);
+ return __builtin_reduce_mul((__v16hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_and_epi16( __mmask16 __M, __m256i __W) {
+ __W = _mm256_mask_mov_epi16(_mm256_set1_epi16(-1), __M, __W);
+ return __builtin_reduce_and((__v16hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_or_epi16(__mmask16 __M, __m256i __W) {
+ __W = _mm256_maskz_mov_epi16(__M, __W);
+ return __builtin_reduce_or((__v16hi)__W);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_reduce_max_epi16(__m256i __V) {
+ return __builtin_reduce_max((__v16hi)__V);
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS256
+_mm256_reduce_max_epu16(__m256i __V) {
+ return __builtin_reduce_max((__v16hu)__V);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_reduce_min_epi16(__m256i __V) {
+ return __builtin_reduce_min((__v16hi)__V);
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS256
+_mm256_reduce_min_epu16(__m256i __V) {
+ return __builtin_reduce_min((__v16hu)__V);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_max_epi16(__mmask16 __M, __m256i __V) {
+ __V = _mm256_mask_mov_epi16(_mm256_set1_epi16(-32767-1), __M, __V);
+ return __builtin_reduce_max((__v16hi)__V);
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_max_epu16(__mmask16 __M, __m256i __V) {
+ __V = _mm256_maskz_mov_epi16(__M, __V);
+ return __builtin_reduce_max((__v16hu)__V);
+}
+
+static __inline__ short __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_min_epi16(__mmask16 __M, __m256i __V) {
+ __V = _mm256_mask_mov_epi16(_mm256_set1_epi16(32767), __M, __V);
+ return __builtin_reduce_min((__v16hi)__V);
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_min_epu16(__mmask16 __M, __m256i __V) {
+ __V = _mm256_mask_mov_epi16(_mm256_set1_epi16(-1), __M, __V);
+ return __builtin_reduce_min((__v16hu)__V);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_reduce_add_epi8(__m128i __W) {
+ return __builtin_reduce_add((__v16qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_reduce_mul_epi8(__m128i __W) {
+ return __builtin_reduce_mul((__v16qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_reduce_and_epi8(__m128i __W) {
+ return __builtin_reduce_and((__v16qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_reduce_or_epi8(__m128i __W) {
+ return __builtin_reduce_or((__v16qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_add_epi8(__mmask16 __M, __m128i __W) {
+ __W = _mm_maskz_mov_epi8(__M, __W);
+ return __builtin_reduce_add((__v16qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_mul_epi8(__mmask16 __M, __m128i __W) {
+ __W = _mm_mask_mov_epi8(_mm_set1_epi8(1), __M, __W);
+ return __builtin_reduce_mul((__v16qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_and_epi8(__mmask16 __M, __m128i __W) {
+ __W = _mm_mask_mov_epi8(_mm_set1_epi8(-1), __M, __W);
+ return __builtin_reduce_and((__v16qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_or_epi8(__mmask16 __M, __m128i __W) {
+ __W = _mm_maskz_mov_epi8(__M, __W);
+ return __builtin_reduce_or((__v16qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_reduce_max_epi8(__m128i __V) {
+ return __builtin_reduce_max((__v16qs)__V);
+}
+
+static __inline__ unsigned char __DEFAULT_FN_ATTRS128
+_mm_reduce_max_epu8(__m128i __V) {
+ return __builtin_reduce_max((__v16qu)__V);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_reduce_min_epi8(__m128i __V) {
+ return __builtin_reduce_min((__v16qs)__V);
+}
+
+static __inline__ unsigned char __DEFAULT_FN_ATTRS128
+_mm_reduce_min_epu8(__m128i __V) {
+ return __builtin_reduce_min((__v16qu)__V);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_max_epi8(__mmask16 __M, __m128i __V) {
+ __V = _mm_mask_mov_epi8(_mm_set1_epi8(-127-1), __M, __V);
+ return __builtin_reduce_max((__v16qs)__V);
+}
+
+static __inline__ unsigned char __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_max_epu8(__mmask16 __M, __m128i __V) {
+ __V = _mm_maskz_mov_epi8(__M, __V);
+ return __builtin_reduce_max((__v16qu)__V);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_min_epi8(__mmask16 __M, __m128i __V) {
+ __V = _mm_mask_mov_epi8(_mm_set1_epi8(127), __M, __V);
+ return __builtin_reduce_min((__v16qs)__V);
+}
+
+static __inline__ unsigned char __DEFAULT_FN_ATTRS128
+_mm_mask_reduce_min_epu8(__mmask16 __M, __m128i __V) {
+ __V = _mm_mask_mov_epi8(_mm_set1_epi8(-1), __M, __V);
+ return __builtin_reduce_min((__v16qu)__V);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_reduce_add_epi8(__m256i __W) {
+ return __builtin_reduce_add((__v32qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_reduce_mul_epi8(__m256i __W) {
+ return __builtin_reduce_mul((__v32qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_reduce_and_epi8(__m256i __W) {
+ return __builtin_reduce_and((__v32qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_reduce_or_epi8(__m256i __W) {
+ return __builtin_reduce_or((__v32qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_add_epi8(__mmask32 __M, __m256i __W) {
+ __W = _mm256_maskz_mov_epi8(__M, __W);
+ return __builtin_reduce_add((__v32qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_mul_epi8(__mmask32 __M, __m256i __W) {
+ __W = _mm256_mask_mov_epi8(_mm256_set1_epi8(1), __M, __W);
+ return __builtin_reduce_mul((__v32qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_and_epi8(__mmask32 __M, __m256i __W) {
+ __W = _mm256_mask_mov_epi8(_mm256_set1_epi8(-1), __M, __W);
+ return __builtin_reduce_and((__v32qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_or_epi8(__mmask32 __M, __m256i __W) {
+ __W = _mm256_maskz_mov_epi8(__M, __W);
+ return __builtin_reduce_or((__v32qs)__W);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_reduce_max_epi8(__m256i __V) {
+ return __builtin_reduce_max((__v32qs)__V);
+}
+
+static __inline__ unsigned char __DEFAULT_FN_ATTRS256
+_mm256_reduce_max_epu8(__m256i __V) {
+ return __builtin_reduce_max((__v32qu)__V);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_reduce_min_epi8(__m256i __V) {
+ return __builtin_reduce_min((__v32qs)__V);
+}
+
+static __inline__ unsigned char __DEFAULT_FN_ATTRS256
+_mm256_reduce_min_epu8(__m256i __V) {
+ return __builtin_reduce_min((__v32qu)__V);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_max_epi8(__mmask32 __M, __m256i __V) {
+ __V = _mm256_mask_mov_epi8(_mm256_set1_epi8(-127-1), __M, __V);
+ return __builtin_reduce_max((__v32qs)__V);
+}
+
+static __inline__ unsigned char __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_max_epu8(__mmask32 __M, __m256i __V) {
+ __V = _mm256_maskz_mov_epi8(__M, __V);
+ return __builtin_reduce_max((__v32qu)__V);
+}
+
+static __inline__ signed char __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_min_epi8(__mmask32 __M, __m256i __V) {
+ __V = _mm256_mask_mov_epi8(_mm256_set1_epi8(127), __M, __V);
+ return __builtin_reduce_min((__v32qs)__V);
+}
+
+static __inline__ unsigned char __DEFAULT_FN_ATTRS256
+_mm256_mask_reduce_min_epu8(__mmask32 __M, __m256i __V) {
+ __V = _mm256_mask_mov_epi8(_mm256_set1_epi8(-1), __M, __V);
+ return __builtin_reduce_min((__v32qu)__V);
+}
+
#undef __DEFAULT_FN_ATTRS128
#undef __DEFAULT_FN_ATTRS256
diff --git a/clang/lib/Headers/avx512vlfp16intrin.h b/clang/lib/Headers/avx512vlfp16intrin.h
index 3d27853ad964..d4a7d1b1c53e 100644
--- a/clang/lib/Headers/avx512vlfp16intrin.h
+++ b/clang/lib/Headers/avx512vlfp16intrin.h
@@ -11,6 +11,8 @@
"Never use <avx512vlfp16intrin.h> directly; include <immintrin.h> instead."
#endif
+#ifdef __SSE2__
+
#ifndef __AVX512VLFP16INTRIN_H
#define __AVX512VLFP16INTRIN_H
@@ -2066,3 +2068,4 @@ _mm_reduce_min_ph(__m128h __V) {
#undef __DEFAULT_FN_ATTRS256
#endif
+#endif
diff --git a/clang/lib/Headers/avxifmaintrin.h b/clang/lib/Headers/avxifmaintrin.h
new file mode 100644
index 000000000000..5c782d2a5b86
--- /dev/null
+++ b/clang/lib/Headers/avxifmaintrin.h
@@ -0,0 +1,177 @@
+/*===----------------- avxifmaintrin.h - IFMA intrinsics -------------------===
+ *
+ * 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 __IMMINTRIN_H
+#error "Never use <avxifmaintrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __AVXIFMAINTRIN_H
+#define __AVXIFMAINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS128 \
+ __attribute__((__always_inline__, __nodebug__, __target__("avxifma"), \
+ __min_vector_width__(128)))
+#define __DEFAULT_FN_ATTRS256 \
+ __attribute__((__always_inline__, __nodebug__, __target__("avxifma"), \
+ __min_vector_width__(256)))
+
+// must vex-encoding
+
+/// Multiply packed unsigned 52-bit integers in each 64-bit element of \a __Y
+/// and \a __Z to form a 104-bit intermediate result. Add the high 52-bit
+/// unsigned integer from the intermediate result with the corresponding
+/// unsigned 64-bit integer in \a __X, and store the results in \a dst.
+///
+/// \headerfile <immintrin.h>
+///
+/// \code
+/// __m128i
+/// _mm_madd52hi_avx_epu64 (__m128i __X, __m128i __Y, __m128i __Z)
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPMADD52HUQ instruction.
+///
+/// \return
+/// return __m128i dst.
+/// \param __X
+/// A 128-bit vector of [2 x i64]
+/// \param __Y
+/// A 128-bit vector of [2 x i64]
+/// \param __Z
+/// A 128-bit vector of [2 x i64]
+///
+/// \code{.operation}
+/// FOR j := 0 to 1
+/// i := j*64
+/// tmp[127:0] := ZeroExtend64(__Y[i+51:i]) * ZeroExtend64(__Z[i+51:i])
+/// dst[i+63:i] := __X[i+63:i] + ZeroExtend64(tmp[103:52])
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128i __DEFAULT_FN_ATTRS128
+_mm_madd52hi_avx_epu64(__m128i __X, __m128i __Y, __m128i __Z) {
+ return (__m128i)__builtin_ia32_vpmadd52huq128((__v2di)__X, (__v2di)__Y,
+ (__v2di)__Z);
+}
+
+/// Multiply packed unsigned 52-bit integers in each 64-bit element of \a __Y
+/// and \a __Z to form a 104-bit intermediate result. Add the high 52-bit
+/// unsigned integer from the intermediate result with the corresponding
+/// unsigned 64-bit integer in \a __X, and store the results in \a dst.
+///
+/// \headerfile <immintrin.h>
+///
+/// \code
+/// __m256i
+/// _mm256_madd52hi_avx_epu64 (__m256i __X, __m256i __Y, __m256i __Z)
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPMADD52HUQ instruction.
+///
+/// \return
+/// return __m256i dst.
+/// \param __X
+/// A 256-bit vector of [4 x i64]
+/// \param __Y
+/// A 256-bit vector of [4 x i64]
+/// \param __Z
+/// A 256-bit vector of [4 x i64]
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// i := j*64
+/// tmp[127:0] := ZeroExtend64(__Y[i+51:i]) * ZeroExtend64(__Z[i+51:i])
+/// dst[i+63:i] := __X[i+63:i] + ZeroExtend64(tmp[103:52])
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256i __DEFAULT_FN_ATTRS256
+_mm256_madd52hi_avx_epu64(__m256i __X, __m256i __Y, __m256i __Z) {
+ return (__m256i)__builtin_ia32_vpmadd52huq256((__v4di)__X, (__v4di)__Y,
+ (__v4di)__Z);
+}
+
+/// Multiply packed unsigned 52-bit integers in each 64-bit element of \a __Y
+/// and \a __Z to form a 104-bit intermediate result. Add the low 52-bit
+/// unsigned integer from the intermediate result with the corresponding
+/// unsigned 64-bit integer in \a __X, and store the results in \a dst.
+///
+/// \headerfile <immintrin.h>
+///
+/// \code
+/// __m128i
+/// _mm_madd52lo_avx_epu64 (__m128i __X, __m128i __Y, __m128i __Z)
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPMADD52LUQ instruction.
+///
+/// \return
+/// return __m128i dst.
+/// \param __X
+/// A 128-bit vector of [2 x i64]
+/// \param __Y
+/// A 128-bit vector of [2 x i64]
+/// \param __Z
+/// A 128-bit vector of [2 x i64]
+///
+/// \code{.operation}
+/// FOR j := 0 to 1
+/// i := j*64
+/// tmp[127:0] := ZeroExtend64(__Y[i+51:i]) * ZeroExtend64(__Z[i+51:i])
+/// dst[i+63:i] := __X[i+63:i] + ZeroExtend64(tmp[51:0])
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128i __DEFAULT_FN_ATTRS128
+_mm_madd52lo_avx_epu64(__m128i __X, __m128i __Y, __m128i __Z) {
+ return (__m128i)__builtin_ia32_vpmadd52luq128((__v2di)__X, (__v2di)__Y,
+ (__v2di)__Z);
+}
+
+/// Multiply packed unsigned 52-bit integers in each 64-bit element of \a __Y
+/// and \a __Z to form a 104-bit intermediate result. Add the low 52-bit
+/// unsigned integer from the intermediate result with the corresponding
+/// unsigned 64-bit integer in \a __X, and store the results in \a dst.
+///
+/// \headerfile <immintrin.h>
+///
+/// \code
+/// __m256i
+/// _mm256_madd52lo_avx_epu64 (__m256i __X, __m256i __Y, __m256i __Z)
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPMADD52LUQ instruction.
+///
+/// \return
+/// return __m256i dst.
+/// \param __X
+/// A 256-bit vector of [4 x i64]
+/// \param __Y
+/// A 256-bit vector of [4 x i64]
+/// \param __Z
+/// A 256-bit vector of [4 x i64]
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// i := j*64
+/// tmp[127:0] := ZeroExtend64(__Y[i+51:i]) * ZeroExtend64(__Z[i+51:i])
+/// dst[i+63:i] := __X[i+63:i] + ZeroExtend64(tmp[51:0])
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256i __DEFAULT_FN_ATTRS256
+_mm256_madd52lo_avx_epu64(__m256i __X, __m256i __Y, __m256i __Z) {
+ return (__m256i)__builtin_ia32_vpmadd52luq256((__v4di)__X, (__v4di)__Y,
+ (__v4di)__Z);
+}
+#undef __DEFAULT_FN_ATTRS128
+#undef __DEFAULT_FN_ATTRS256
+
+#endif // __AVXIFMAINTRIN_H
diff --git a/clang/lib/Headers/avxintrin.h b/clang/lib/Headers/avxintrin.h
index a8f953c260c2..ee31569c1623 100644
--- a/clang/lib/Headers/avxintrin.h
+++ b/clang/lib/Headers/avxintrin.h
@@ -39,6 +39,16 @@ typedef float __m256_u __attribute__ ((__vector_size__ (32), __aligned__(1)));
typedef double __m256d_u __attribute__((__vector_size__(32), __aligned__(1)));
typedef long long __m256i_u __attribute__((__vector_size__(32), __aligned__(1)));
+#ifdef __SSE2__
+/* Both _Float16 and __bf16 require SSE2 being enabled. */
+typedef _Float16 __v16hf __attribute__((__vector_size__(32), __aligned__(32)));
+typedef _Float16 __m256h __attribute__((__vector_size__(32), __aligned__(32)));
+typedef _Float16 __m256h_u __attribute__((__vector_size__(32), __aligned__(1)));
+
+typedef __bf16 __v16bf __attribute__((__vector_size__(32), __aligned__(32)));
+typedef __bf16 __m256bh __attribute__((__vector_size__(32), __aligned__(32)));
+#endif
+
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("avx"), __min_vector_width__(256)))
#define __DEFAULT_FN_ATTRS128 __attribute__((__always_inline__, __nodebug__, __target__("avx"), __min_vector_width__(128)))
@@ -4288,7 +4298,7 @@ _mm256_set1_epi64x(long long __q)
static __inline __m256d __DEFAULT_FN_ATTRS
_mm256_setzero_pd(void)
{
- return __extension__ (__m256d){ 0, 0, 0, 0 };
+ return __extension__ (__m256d){ 0.0, 0.0, 0.0, 0.0 };
}
/// Constructs a 256-bit floating-point vector of [8 x float] with all
@@ -4302,7 +4312,7 @@ _mm256_setzero_pd(void)
static __inline __m256 __DEFAULT_FN_ATTRS
_mm256_setzero_ps(void)
{
- return __extension__ (__m256){ 0, 0, 0, 0, 0, 0, 0, 0 };
+ return __extension__ (__m256){ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
}
/// Constructs a 256-bit integer vector initialized to zero.
diff --git a/clang/lib/Headers/avxneconvertintrin.h b/clang/lib/Headers/avxneconvertintrin.h
new file mode 100644
index 000000000000..1bef1c893787
--- /dev/null
+++ b/clang/lib/Headers/avxneconvertintrin.h
@@ -0,0 +1,484 @@
+/*===-------------- avxneconvertintrin.h - AVXNECONVERT --------------------===
+ *
+ * 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 __IMMINTRIN_H
+#error \
+ "Never use <avxneconvertintrin.h> directly; include <immintrin.h> instead."
+#endif // __IMMINTRIN_H
+
+#ifdef __SSE2__
+
+#ifndef __AVXNECONVERTINTRIN_H
+#define __AVXNECONVERTINTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS128 \
+ __attribute__((__always_inline__, __nodebug__, __target__("avxneconvert"), \
+ __min_vector_width__(128)))
+#define __DEFAULT_FN_ATTRS256 \
+ __attribute__((__always_inline__, __nodebug__, __target__("avxneconvert"), \
+ __min_vector_width__(256)))
+
+/// Convert scalar BF16 (16-bit) floating-point element
+/// stored at memory locations starting at location \a __A to a
+/// single-precision (32-bit) floating-point, broadcast it to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_bcstnebf16_ps(const void *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VBCSTNEBF162PS instruction.
+///
+/// \param __A
+/// A pointer to a 16-bit memory location. The address of the memory
+/// location does not have to be aligned.
+/// \returns
+/// A 128-bit vector of [4 x float].
+///
+/// \code{.operation}
+/// b := Convert_BF16_To_FP32(MEM[__A+15:__A])
+/// FOR j := 0 to 3
+/// m := j*32
+/// dst[m+31:m] := b
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128 __DEFAULT_FN_ATTRS128
+_mm_bcstnebf16_ps(const void *__A) {
+ return (__m128)__builtin_ia32_vbcstnebf162ps128((const __bf16 *)__A);
+}
+
+/// Convert scalar BF16 (16-bit) floating-point element
+/// stored at memory locations starting at location \a __A to a
+/// single-precision (32-bit) floating-point, broadcast it to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_bcstnebf16_ps(const void *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VBCSTNEBF162PS instruction.
+///
+/// \param __A
+/// A pointer to a 16-bit memory location. The address of the memory
+/// location does not have to be aligned.
+/// \returns
+/// A 256-bit vector of [8 x float].
+///
+/// \code{.operation}
+/// b := Convert_BF16_To_FP32(MEM[__A+15:__A])
+/// FOR j := 0 to 7
+/// m := j*32
+/// dst[m+31:m] := b
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256 __DEFAULT_FN_ATTRS256
+_mm256_bcstnebf16_ps(const void *__A) {
+ return (__m256)__builtin_ia32_vbcstnebf162ps256((const __bf16 *)__A);
+}
+
+/// Convert scalar half-precision (16-bit) floating-point element
+/// stored at memory locations starting at location \a __A to a
+/// single-precision (32-bit) floating-point, broadcast it to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_bcstnesh_ps(const void *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VBCSTNESH2PS instruction.
+///
+/// \param __A
+/// A pointer to a 16-bit memory location. The address of the memory
+/// location does not have to be aligned.
+/// \returns
+/// A 128-bit vector of [4 x float].
+///
+/// \code{.operation}
+/// b := Convert_FP16_To_FP32(MEM[__A+15:__A])
+/// FOR j := 0 to 3
+/// m := j*32
+/// dst[m+31:m] := b
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128 __DEFAULT_FN_ATTRS128
+_mm_bcstnesh_ps(const void *__A) {
+ return (__m128)__builtin_ia32_vbcstnesh2ps128((const _Float16 *)__A);
+}
+
+/// Convert scalar half-precision (16-bit) floating-point element
+/// stored at memory locations starting at location \a __A to a
+/// single-precision (32-bit) floating-point, broadcast it to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_bcstnesh_ps(const void *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VBCSTNESH2PS instruction.
+///
+/// \param __A
+/// A pointer to a 16-bit memory location. The address of the memory
+/// location does not have to be aligned.
+/// \returns
+/// A 256-bit vector of [8 x float].
+///
+/// \code{.operation}
+/// b := Convert_FP16_To_FP32(MEM[__A+15:__A])
+/// FOR j := 0 to 7
+/// m := j*32
+/// dst[m+31:m] := b
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256 __DEFAULT_FN_ATTRS256
+_mm256_bcstnesh_ps(const void *__A) {
+ return (__m256)__builtin_ia32_vbcstnesh2ps256((const _Float16 *)__A);
+}
+
+/// Convert packed BF16 (16-bit) floating-point even-indexed elements
+/// stored at memory locations starting at location \a __A to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_cvtneebf16_ps(const __m128bh *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEEBF162PS instruction.
+///
+/// \param __A
+/// A pointer to a 128-bit memory location containing 8 consecutive
+/// BF16 (16-bit) floating-point values.
+/// \returns
+/// A 128-bit vector of [4 x float].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// k := j*2
+/// i := k*16
+/// m := j*32
+/// dst[m+31:m] := Convert_BF16_To_FP32(MEM[__A+i+15:__A+i])
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128 __DEFAULT_FN_ATTRS128
+_mm_cvtneebf16_ps(const __m128bh *__A) {
+ return (__m128)__builtin_ia32_vcvtneebf162ps128((const __v8bf *)__A);
+}
+
+/// Convert packed BF16 (16-bit) floating-point even-indexed elements
+/// stored at memory locations starting at location \a __A to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_cvtneebf16_ps(const __m256bh *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEEBF162PS instruction.
+///
+/// \param __A
+/// A pointer to a 256-bit memory location containing 16 consecutive
+/// BF16 (16-bit) floating-point values.
+/// \returns
+/// A 256-bit vector of [8 x float].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// k := j*2
+/// i := k*16
+/// m := j*32
+/// dst[m+31:m] := Convert_BF16_To_FP32(MEM[__A+i+15:__A+i])
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256 __DEFAULT_FN_ATTRS256
+_mm256_cvtneebf16_ps(const __m256bh *__A) {
+ return (__m256)__builtin_ia32_vcvtneebf162ps256((const __v16bf *)__A);
+}
+
+/// Convert packed half-precision (16-bit) floating-point even-indexed elements
+/// stored at memory locations starting at location \a __A to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_cvtneeph_ps(const __m128h *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEEPH2PS instruction.
+///
+/// \param __A
+/// A pointer to a 128-bit memory location containing 8 consecutive
+/// half-precision (16-bit) floating-point values.
+/// \returns
+/// A 128-bit vector of [4 x float].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// k := j*2
+/// i := k*16
+/// m := j*32
+/// dst[m+31:m] := Convert_FP16_To_FP32(MEM[__A+i+15:__A+i])
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128 __DEFAULT_FN_ATTRS128
+_mm_cvtneeph_ps(const __m128h *__A) {
+ return (__m128)__builtin_ia32_vcvtneeph2ps128((const __v8hf *)__A);
+}
+
+/// Convert packed half-precision (16-bit) floating-point even-indexed elements
+/// stored at memory locations starting at location \a __A to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_cvtneeph_ps(const __m256h *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEEPH2PS instruction.
+///
+/// \param __A
+/// A pointer to a 256-bit memory location containing 16 consecutive
+/// half-precision (16-bit) floating-point values.
+/// \returns
+/// A 256-bit vector of [8 x float].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// k := j*2
+/// i := k*16
+/// m := j*32
+/// dst[m+31:m] := Convert_FP16_To_FP32(MEM[__A+i+15:__A+i])
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256 __DEFAULT_FN_ATTRS256
+_mm256_cvtneeph_ps(const __m256h *__A) {
+ return (__m256)__builtin_ia32_vcvtneeph2ps256((const __v16hf *)__A);
+}
+
+/// Convert packed BF16 (16-bit) floating-point odd-indexed elements
+/// stored at memory locations starting at location \a __A to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_cvtneobf16_ps(const __m128bh *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEOBF162PS instruction.
+///
+/// \param __A
+/// A pointer to a 128-bit memory location containing 8 consecutive
+/// BF16 (16-bit) floating-point values.
+/// \returns
+/// A 128-bit vector of [4 x float].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// k := j*2+1
+/// i := k*16
+/// m := j*32
+/// dst[m+31:m] := Convert_BF16_To_FP32(MEM[__A+i+15:__A+i])
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128 __DEFAULT_FN_ATTRS128
+_mm_cvtneobf16_ps(const __m128bh *__A) {
+ return (__m128)__builtin_ia32_vcvtneobf162ps128((const __v8bf *)__A);
+}
+
+/// Convert packed BF16 (16-bit) floating-point odd-indexed elements
+/// stored at memory locations starting at location \a __A to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_cvtneobf16_ps(const __m256bh *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEOBF162PS instruction.
+///
+/// \param __A
+/// A pointer to a 256-bit memory location containing 16 consecutive
+/// BF16 (16-bit) floating-point values.
+/// \returns
+/// A 256-bit vector of [8 x float].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// k := j*2+1
+/// i := k*16
+/// m := j*32
+/// dst[m+31:m] := Convert_BF16_To_FP32(MEM[__A+i+15:__A+i])
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256 __DEFAULT_FN_ATTRS256
+_mm256_cvtneobf16_ps(const __m256bh *__A) {
+ return (__m256)__builtin_ia32_vcvtneobf162ps256((const __v16bf *)__A);
+}
+
+/// Convert packed half-precision (16-bit) floating-point odd-indexed elements
+/// stored at memory locations starting at location \a __A to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_cvtneoph_ps(const __m128h *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEOPH2PS instruction.
+///
+/// \param __A
+/// A pointer to a 128-bit memory location containing 8 consecutive
+/// half-precision (16-bit) floating-point values.
+/// \returns
+/// A 128-bit vector of [4 x float].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// k := j*2+1
+/// i := k*16
+/// m := j*32
+/// dst[m+31:m] := Convert_FP16_To_FP32(MEM[__A+i+15:__A+i])
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128 __DEFAULT_FN_ATTRS128
+_mm_cvtneoph_ps(const __m128h *__A) {
+ return (__m128)__builtin_ia32_vcvtneoph2ps128((const __v8hf *)__A);
+}
+
+/// Convert packed half-precision (16-bit) floating-point odd-indexed elements
+/// stored at memory locations starting at location \a __A to packed
+/// single-precision (32-bit) floating-point elements, and store the results in
+/// \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_cvtneoph_ps(const __m256h *__A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEOPH2PS instruction.
+///
+/// \param __A
+/// A pointer to a 256-bit memory location containing 16 consecutive
+/// half-precision (16-bit) floating-point values.
+/// \returns
+/// A 256-bit vector of [8 x float].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// k := j*2+1
+/// i := k*16
+/// m := j*32
+/// dst[m+31:m] := Convert_FP16_To_FP32(MEM[__A+i+15:__A+i])
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256 __DEFAULT_FN_ATTRS256
+_mm256_cvtneoph_ps(const __m256h *__A) {
+ return (__m256)__builtin_ia32_vcvtneoph2ps256((const __v16hf *)__A);
+}
+
+/// Convert packed single-precision (32-bit) floating-point elements in \a __A
+/// to packed BF16 (16-bit) floating-point elements, and store the results in \a
+/// dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_cvtneps_avx_pbh(__m128 __A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEPS2BF16 instruction.
+///
+/// \param __A
+/// A 128-bit vector of [4 x float].
+/// \returns
+/// A 128-bit vector of [8 x bfloat].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// dst.word[j] := Convert_FP32_To_BF16(__A.fp32[j])
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128bh __DEFAULT_FN_ATTRS128
+_mm_cvtneps_avx_pbh(__m128 __A) {
+ return (__m128bh)__builtin_ia32_vcvtneps2bf16128((__v4sf)__A);
+}
+
+/// Convert packed single-precision (32-bit) floating-point elements in \a __A
+/// to packed BF16 (16-bit) floating-point elements, and store the results in \a
+/// dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_cvtneps_avx_pbh(__m256 __A);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VCVTNEPS2BF16 instruction.
+///
+/// \param __A
+/// A 256-bit vector of [8 x float].
+/// \returns
+/// A 128-bit vector of [8 x bfloat].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// dst.word[j] := Convert_FP32_To_BF16(a.fp32[j])
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128bh __DEFAULT_FN_ATTRS256
+_mm256_cvtneps_avx_pbh(__m256 __A) {
+ return (__m128bh)__builtin_ia32_vcvtneps2bf16256((__v8sf)__A);
+}
+
+#undef __DEFAULT_FN_ATTRS128
+#undef __DEFAULT_FN_ATTRS256
+
+#endif // __AVXNECONVERTINTRIN_H
+#endif // __SSE2__
diff --git a/clang/lib/Headers/avxvnniint8intrin.h b/clang/lib/Headers/avxvnniint8intrin.h
new file mode 100644
index 000000000000..b0b6cb853f71
--- /dev/null
+++ b/clang/lib/Headers/avxvnniint8intrin.h
@@ -0,0 +1,471 @@
+/*===-------- avxvnniint8intrin.h - AVXVNNIINT8 intrinsics -----------===
+ *
+ * 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 __IMMINTRIN_H
+#error \
+ "Never use <avxvnniint8intrin.h> directly; include <immintrin.h> instead."
+#endif
+
+#ifndef __AVXVNNIINT8INTRIN_H
+#define __AVXVNNIINT8INTRIN_H
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS256 \
+ __attribute__((__always_inline__, __nodebug__, __target__("avxvnniint8"), \
+ __min_vector_width__(256)))
+#define __DEFAULT_FN_ATTRS128 \
+ __attribute__((__always_inline__, __nodebug__, __target__("avxvnniint8"), \
+ __min_vector_width__(128)))
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding signed 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W, and store the packed 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_dpbssd_epi32(__m128i __W, __m128i __A, __m128i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 128-bit vector of [16 x char].
+/// \param __B
+/// A 128-bit vector of [16 x char].
+/// \returns
+/// A 128-bit vector of [4 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// tmp1.word := SignExtend16(__A.byte[4*j]) * SignExtend16(__B.byte[4*j])
+/// tmp2.word := SignExtend16(__A.byte[4*j+1]) * SignExtend16(__B.byte[4*j+1])
+/// tmp3.word := SignExtend16(__A.byte[4*j+2]) * SignExtend16(__B.byte[4*j+2])
+/// tmp4.word := SignExtend16(__A.byte[4*j+3]) * SignExtend16(__B.byte[4*j+3])
+/// dst.dword[j] := __W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_dpbssd_epi32(__m128i __W,
+ __m128i __A,
+ __m128i __B) {
+ return (__m128i)__builtin_ia32_vpdpbssd128((__v4si)__W, (__v4si)__A,
+ (__v4si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding signed 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W, and store the packed 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_dpbssd_epi32(__m256i __W, __m256i __A, __m256i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 256-bit vector of [32 x char].
+/// \param __B
+/// A 256-bit vector of [32 x char].
+/// \returns
+/// A 256-bit vector of [8 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// tmp1.word := SignExtend16(__A.byte[4*j]) * SignExtend16(__B.byte[4*j])
+/// tmp2.word := SignExtend16(__A.byte[4*j+1]) * SignExtend16(__B.byte[4*j+1])
+/// tmp3.word := SignExtend16(__A.byte[4*j+2]) * SignExtend16(__B.byte[4*j+2])
+/// tmp4.word := SignExtend16(__A.byte[4*j+3]) * SignExtend16(__B.byte[4*j+3])
+/// dst.dword[j] := __W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256i __DEFAULT_FN_ATTRS256
+_mm256_dpbssd_epi32(__m256i __W, __m256i __A, __m256i __B) {
+ return (__m256i)__builtin_ia32_vpdpbssd256((__v8si)__W, (__v8si)__A,
+ (__v8si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding signed 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W with signed saturation, and store the packed
+/// 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_dpbssds_epi32( __m128i __W, __m128i __A, __m128i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 128-bit vector of [16 x char].
+/// \param __B
+/// A 128-bit vector of [16 x char].
+/// \returns
+/// A 128-bit vector of [4 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// tmp1.word := SignExtend16(__A.byte[4*j]) * SignExtend16(__B.byte[4*j])
+/// tmp2.word := SignExtend16(__A.byte[4*j+1]) * SignExtend16(__B.byte[4*j+1])
+/// tmp3.word := SignExtend16(__A.byte[4*j+2]) * SignExtend16(__B.byte[4*j+2])
+/// tmp4.word := SignExtend16(__A.byte[4*j+3]) * SignExtend16(__B.byte[4*j+3])
+/// dst.dword[j] := SIGNED_DWORD_SATURATE(__W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4)
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_dpbssds_epi32(__m128i __W,
+ __m128i __A,
+ __m128i __B) {
+ return (__m128i)__builtin_ia32_vpdpbssds128((__v4si)__W, (__v4si)__A,
+ (__v4si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding signed 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W with signed saturation, and store the packed
+/// 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_dpbssds_epi32(__m256i __W, __m256i __A, __m256i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 256-bit vector of [32 x char].
+/// \param __B
+/// A 256-bit vector of [32 x char].
+/// \returns
+/// A 256-bit vector of [8 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// tmp1.word := SignExtend16(__A.byte[4*j]) * SignExtend16(__B.byte[4*j])
+/// tmp2.word := SignExtend16(__A.byte[4*j+1]) * SignExtend16(__B.byte[4*j+1])
+/// tmp3.word := SignExtend16(__A.byte[4*j+2]) * SignExtend16(__B.byte[4*j+2])
+/// tmp4.word := SignExtend16(__A.byte[4*j+3]) * SignExtend16(__B.byte[4*j+3])
+/// dst.dword[j] := SIGNED_DWORD_SATURATE(__W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4)
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256i __DEFAULT_FN_ATTRS256
+_mm256_dpbssds_epi32(__m256i __W, __m256i __A, __m256i __B) {
+ return (__m256i)__builtin_ia32_vpdpbssds256((__v8si)__W, (__v8si)__A,
+ (__v8si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding unsigned 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W, and store the packed 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_dpbsud_epi32(__m128i __W, __m128i __A, __m128i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 128-bit vector of [16 x char].
+/// \param __B
+/// A 128-bit vector of [16 x unsigned char].
+/// \returns
+/// A 128-bit vector of [4 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// tmp1.word := Signed(SignExtend16(__A.byte[4*j]) * ZeroExtend16(__B.byte[4*j]))
+/// tmp2.word := Signed(SignExtend16(__A.byte[4*j+1]) * ZeroExtend16(__B.byte[4*j+1]))
+/// tmp3.word := Signed(SignExtend16(__A.byte[4*j+2]) * ZeroExtend16(__B.byte[4*j+2]))
+/// tmp4.word := Signed(SignExtend16(__A.byte[4*j+3]) * ZeroExtend16(__B.byte[4*j+3]))
+/// dst.dword[j] := __W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_dpbsud_epi32(__m128i __W,
+ __m128i __A,
+ __m128i __B) {
+ return (__m128i)__builtin_ia32_vpdpbsud128((__v4si)__W, (__v4si)__A,
+ (__v4si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding unsigned 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W, and store the packed 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_dpbsud_epi32(__m256i __W, __m256i __A, __m256i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 256-bit vector of [32 x char].
+/// \param __B
+/// A 256-bit vector of [32 x unsigned char].
+/// \returns
+/// A 256-bit vector of [8 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// tmp1.word := Signed(SignExtend16(__A.byte[4*j]) * ZeroExtend16(__B.byte[4*j]))
+/// tmp2.word := Signed(SignExtend16(__A.byte[4*j+1]) * ZeroExtend16(__B.byte[4*j+1]))
+/// tmp3.word := Signed(SignExtend16(__A.byte[4*j+2]) * ZeroExtend16(__B.byte[4*j+2]))
+/// tmp4.word := Signed(SignExtend16(__A.byte[4*j+3]) * ZeroExtend16(__B.byte[4*j+3]))
+/// dst.dword[j] := __W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256i __DEFAULT_FN_ATTRS256
+_mm256_dpbsud_epi32(__m256i __W, __m256i __A, __m256i __B) {
+ return (__m256i)__builtin_ia32_vpdpbsud256((__v8si)__W, (__v8si)__A,
+ (__v8si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding unsigned 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W with signed saturation, and store the packed
+/// 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_dpbsuds_epi32( __m128i __W, __m128i __A, __m128i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 128-bit vector of [16 x char].
+/// \param __B
+/// A 128-bit vector of [16 x unsigned char].
+/// \returns
+/// A 128-bit vector of [4 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// tmp1.word := Signed(SignExtend16(__A.byte[4*j]) * ZeroExtend16(__B.byte[4*j]))
+/// tmp2.word := Signed(SignExtend16(__A.byte[4*j+1]) * ZeroExtend16(__B.byte[4*j+1]))
+/// tmp3.word := Signed(SignExtend16(__A.byte[4*j+2]) * ZeroExtend16(__B.byte[4*j+2]))
+/// tmp4.word := Signed(SignExtend16(__A.byte[4*j+3]) * ZeroExtend16(__B.byte[4*j+3]))
+/// dst.dword[j] := SIGNED_DWORD_SATURATE(__W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4)
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_dpbsuds_epi32(__m128i __W,
+ __m128i __A,
+ __m128i __B) {
+ return (__m128i)__builtin_ia32_vpdpbsuds128((__v4si)__W, (__v4si)__A,
+ (__v4si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding unsigned 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W with signed saturation, and store the packed
+/// 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_dpbsuds_epi32(__m256i __W, __m256i __A, __m256i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 256-bit vector of [32 x char].
+/// \param __B
+/// A 256-bit vector of [32 x unsigned char].
+/// \returns
+/// A 256-bit vector of [8 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// tmp1.word := Signed(SignExtend16(__A.byte[4*j]) * ZeroExtend16(__B.byte[4*j]))
+/// tmp2.word := Signed(SignExtend16(__A.byte[4*j+1]) * ZeroExtend16(__B.byte[4*j+1]))
+/// tmp3.word := Signed(SignExtend16(__A.byte[4*j+2]) * ZeroExtend16(__B.byte[4*j+2]))
+/// tmp4.word := Signed(SignExtend16(__A.byte[4*j+3]) * ZeroExtend16(__B.byte[4*j+3]))
+/// dst.dword[j] := SIGNED_DWORD_SATURATE(__W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4)
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256i __DEFAULT_FN_ATTRS256
+_mm256_dpbsuds_epi32(__m256i __W, __m256i __A, __m256i __B) {
+ return (__m256i)__builtin_ia32_vpdpbsuds256((__v8si)__W, (__v8si)__A,
+ (__v8si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of unsigned 8-bit integers in \a __A with
+/// corresponding unsigned 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W, and store the packed 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_dpbuud_epi32(__m128i __W, __m128i __A, __m128i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 128-bit vector of [16 x unsigned char].
+/// \param __B
+/// A 128-bit vector of [16 x unsigned char].
+/// \returns
+/// A 128-bit vector of [4 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// tmp1.word := ZeroExtend16(__A.byte[4*j]) * ZeroExtend16(__B.byte[4*j])
+/// tmp2.word := ZeroExtend16(__A.byte[4*j+1]) * ZeroExtend16(__B.byte[4*j+1])
+/// tmp3.word := ZeroExtend16(__A.byte[4*j+2]) * ZeroExtend16(__B.byte[4*j+2])
+/// tmp4.word := ZeroExtend16(__A.byte[4*j+3]) * ZeroExtend16(__B.byte[4*j+3])
+/// dst.dword[j] := __W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_dpbuud_epi32(__m128i __W,
+ __m128i __A,
+ __m128i __B) {
+ return (__m128i)__builtin_ia32_vpdpbuud128((__v4si)__W, (__v4si)__A,
+ (__v4si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of unsigned 8-bit integers in \a __A with
+/// corresponding unsigned 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W, and store the packed 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_dpbuud_epi32(__m256i __W, __m256i __A, __m256i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBSSD instruction.
+///
+/// \param __A
+/// A 256-bit vector of [32 x unsigned char].
+/// \param __B
+/// A 256-bit vector of [32 x unsigned char].
+/// \returns
+/// A 256-bit vector of [8 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// tmp1.word := ZeroExtend16(__A.byte[4*j]) * ZeroExtend16(__B.byte[4*j])
+/// tmp2.word := ZeroExtend16(__A.byte[4*j+1]) * ZeroExtend16(__B.byte[4*j+1])
+/// tmp3.word := ZeroExtend16(__A.byte[4*j+2]) * ZeroExtend16(__B.byte[4*j+2])
+/// tmp4.word := ZeroExtend16(__A.byte[4*j+3]) * ZeroExtend16(__B.byte[4*j+3])
+/// dst.dword[j] := __W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256i __DEFAULT_FN_ATTRS256
+_mm256_dpbuud_epi32(__m256i __W, __m256i __A, __m256i __B) {
+ return (__m256i)__builtin_ia32_vpdpbuud256((__v8si)__W, (__v8si)__A,
+ (__v8si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of unsigned 8-bit integers in \a __A with
+/// corresponding unsigned 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W with signed saturation, and store the packed
+/// 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm_dpbuuds_epi32( __m128i __W, __m128i __A, __m128i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBUUDS instruction.
+///
+/// \param __A
+/// A 128-bit vector of [16 x unsigned char].
+/// \param __B
+/// A 128-bit vector of [16 x unsigned char].
+/// \returns
+/// A 128-bit vector of [4 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 3
+/// tmp1.word := ZeroExtend16(__A.byte[4*j]) * ZeroExtend16(__B.byte[4*j])
+/// tmp2.word := ZeroExtend16(__A.byte[4*j+1]) * ZeroExtend16(__B.byte[4*j+1])
+/// tmp3.word := ZeroExtend16(__A.byte[4*j+2]) * ZeroExtend16(__B.byte[4*j+2])
+/// tmp4.word := ZeroExtend16(__A.byte[4*j+3]) * ZeroExtend16(__B.byte[4*j+3])
+/// dst.dword[j] := UNSIGNED_DWORD_SATURATE(__W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4)
+/// ENDFOR
+/// dst[MAX:128] := 0
+/// \endcode
+static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_dpbuuds_epi32(__m128i __W,
+ __m128i __A,
+ __m128i __B) {
+ return (__m128i)__builtin_ia32_vpdpbuuds128((__v4si)__W, (__v4si)__A,
+ (__v4si)__B);
+}
+
+/// Multiply groups of 4 adjacent pairs of signed 8-bit integers in \a __A with
+/// corresponding unsigned 8-bit integers in \a __B, producing 4 intermediate
+/// signed 16-bit results. Sum these 4 results with the corresponding
+/// 32-bit integer in \a __W with signed saturation, and store the packed
+/// 32-bit results in \a dst.
+///
+/// \headerfile <x86intrin.h>
+///
+/// \code
+/// _mm256_dpbuuds_epi32(__m256i __W, __m256i __A, __m256i __B);
+/// \endcode
+///
+/// This intrinsic corresponds to the \c VPDPBUUDS instruction.
+///
+/// \param __A
+/// A 256-bit vector of [32 x unsigned char].
+/// \param __B
+/// A 256-bit vector of [32 x unsigned char].
+/// \returns
+/// A 256-bit vector of [8 x int].
+///
+/// \code{.operation}
+/// FOR j := 0 to 7
+/// tmp1.word := ZeroExtend16(__A.byte[4*j]) * ZeroExtend16(__B.byte[4*j])
+/// tmp2.word := ZeroExtend16(__A.byte[4*j+1]) * ZeroExtend16(__B.byte[4*j+1])
+/// tmp3.word := ZeroExtend16(__A.byte[4*j+2]) * ZeroExtend16(__B.byte[4*j+2])
+/// tmp4.word := ZeroExtend16(__A.byte[4*j+3]) * ZeroExtend16(__B.byte[4*j+3])
+/// dst.dword[j] := UNSIGNED_DWORD_SATURATE(__W.dword[j] + tmp1 + tmp2 + tmp3 + tmp4)
+/// ENDFOR
+/// dst[MAX:256] := 0
+/// \endcode
+static __inline__ __m256i __DEFAULT_FN_ATTRS256
+_mm256_dpbuuds_epi32(__m256i __W, __m256i __A, __m256i __B) {
+ return (__m256i)__builtin_ia32_vpdpbuuds256((__v8si)__W, (__v8si)__A,
+ (__v8si)__B);
+}
+#undef __DEFAULT_FN_ATTRS128
+#undef __DEFAULT_FN_ATTRS256
+
+#endif // __AVXVNNIINT8INTRIN_H
diff --git a/clang/lib/Headers/cmpccxaddintrin.h b/clang/lib/Headers/cmpccxaddintrin.h
new file mode 100644
index 000000000000..6957498996c8
--- /dev/null
+++ b/clang/lib/Headers/cmpccxaddintrin.h
@@ -0,0 +1,70 @@
+/*===--------------- cmpccxaddintrin.h - CMPCCXADD intrinsics--------------===
+ *
+ *
+ * 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 __X86GPRINTRIN_H
+#error \
+ "Never use <cmpccxaddintrin.h> directly; include <x86gprintrin.h> instead."
+#endif // __X86GPRINTRIN_H
+
+#ifndef __CMPCCXADDINTRIN_H
+#define __CMPCCXADDINTRIN_H
+#ifdef __x86_64__
+
+typedef enum {
+ _CMPCCX_O, /* Overflow. */
+ _CMPCCX_NO, /* No overflow. */
+ _CMPCCX_B, /* Below. */
+ _CMPCCX_NB, /* Not below. */
+ _CMPCCX_Z, /* Zero. */
+ _CMPCCX_NZ, /* Not zero. */
+ _CMPCCX_BE, /* Below or equal. */
+ _CMPCCX_NBE, /* Neither below nor equal. */
+ _CMPCCX_S, /* Sign. */
+ _CMPCCX_NS, /* No sign. */
+ _CMPCCX_P, /* Parity. */
+ _CMPCCX_NP, /* No parity. */
+ _CMPCCX_L, /* Less. */
+ _CMPCCX_NL, /* Not less. */
+ _CMPCCX_LE, /* Less or equal. */
+ _CMPCCX_NLE, /* Neither less nor equal. */
+} _CMPCCX_ENUM;
+
+/// Compares the value from the memory __A with the value of __B. If the
+/// specified condition __D is met, then add the third operand __C to the
+/// __A and write it into __A, else the value of __A is unchanged. The return
+/// value is the original value of __A.
+///
+/// \headerfile <immintrin.h>
+///
+/// This intrinsic corresponds to the \c CMPCCXADD instructions.
+///
+/// \param __A
+/// __A pointer specifying the memory address.
+///
+/// \param __B
+/// A integer operand.
+///
+/// \param __C
+/// A integer operand.
+///
+/// \param __D
+/// The specified condition.
+///
+/// \returns a integer which is the original value of first operand.
+
+#define _cmpccxadd_epi32(__A, __B, __C, __D) \
+ ((int)(__builtin_ia32_cmpccxadd32((void *)(__A), (int)(__B), (int)(__C), \
+ (int)(__D))))
+
+#define _cmpccxadd_epi64(__A, __B, __C, __D) \
+ ((long long)(__builtin_ia32_cmpccxadd64((void *)(__A), (long long)(__B), \
+ (long long)(__C), (int)(__D))))
+
+#endif // __x86_64__
+#endif // __CMPCCXADDINTRIN_H
diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h
index 5d262a60735f..1ad6853a97c9 100644
--- a/clang/lib/Headers/cpuid.h
+++ b/clang/lib/Headers/cpuid.h
@@ -200,9 +200,18 @@
#define bit_AMXINT8 0x02000000
/* Features in %eax for leaf 7 sub-leaf 1 */
+#define bit_RAOINT 0x00000008
#define bit_AVXVNNI 0x00000010
#define bit_AVX512BF16 0x00000020
+#define bit_CMPCCXADD 0x00000080
+#define bit_AMXFP16 0x00200000
#define bit_HRESET 0x00400000
+#define bit_AVXIFMA 0x00800000
+
+/* Features in %edx for leaf 7 sub-leaf 1 */
+#define bit_AVXVNNIINT8 0x00000010
+#define bit_AVXNECONVERT 0x00000020
+#define bit_PREFETCHI 0x00004000
/* Features in %eax for leaf 13 sub-leaf 1 */
#define bit_XSAVEOPT 0x00000001
@@ -232,6 +241,7 @@
/* Features in %ebx for leaf 0x80000008 */
#define bit_CLZERO 0x00000001
+#define bit_RDPRU 0x00000010
#define bit_WBNOINVD 0x00000200
@@ -260,7 +270,8 @@
: "0"(__leaf), "2"(__count))
#endif
-static __inline int __get_cpuid_max (unsigned int __leaf, unsigned int *__sig)
+static __inline unsigned int __get_cpuid_max (unsigned int __leaf,
+ unsigned int *__sig)
{
unsigned int __eax, __ebx, __ecx, __edx;
#if __i386__
diff --git a/clang/lib/Headers/cuda_wrappers/cmath b/clang/lib/Headers/cuda_wrappers/cmath
new file mode 100644
index 000000000000..45f89beec9b4
--- /dev/null
+++ b/clang/lib/Headers/cuda_wrappers/cmath
@@ -0,0 +1,90 @@
+/*===---- cmath - CUDA wrapper for <cmath> ---------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __CLANG_CUDA_WRAPPERS_CMATH
+#define __CLANG_CUDA_WRAPPERS_CMATH
+
+#include_next <cmath>
+
+#if defined(_LIBCPP_STD_VER)
+
+// libc++ will need long double variants of these functions, but CUDA does not
+// provide them. We'll provide their declarations, which should allow the
+// headers to parse, but would not allow accidental use of them on a GPU.
+
+__attribute__((device)) long double logb(long double);
+__attribute__((device)) long double scalbn(long double, int);
+
+namespace std {
+
+// For __constexpr_fmin/fmax we only need device-side overloads before c++14
+// where they are not constexpr.
+#if _LIBCPP_STD_VER < 14
+
+__attribute__((device))
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 float __constexpr_fmax(float __x, float __y) _NOEXCEPT {
+ return __builtin_fmaxf(__x, __y);
+}
+
+__attribute__((device))
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 double __constexpr_fmax(double __x, double __y) _NOEXCEPT {
+ return __builtin_fmax(__x, __y);
+}
+
+__attribute__((device))
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 long double
+__constexpr_fmax(long double __x, long double __y) _NOEXCEPT {
+ return __builtin_fmaxl(__x, __y);
+}
+
+template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Tp>::value && is_arithmetic<_Up>::value, int> = 0>
+__attribute__((device))
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __promote<_Tp, _Up>::type
+__constexpr_fmax(_Tp __x, _Up __y) _NOEXCEPT {
+ using __result_type = typename __promote<_Tp, _Up>::type;
+ return std::__constexpr_fmax(static_cast<__result_type>(__x), static_cast<__result_type>(__y));
+}
+#endif // _LIBCPP_STD_VER < 14
+
+// For logb/scalbn templates we must always provide device overloads because
+// libc++ implementation uses __builtin_XXX which gets translated into a libcall
+// which we can't handle on GPU. We need to forward those to CUDA-provided
+// implementations.
+
+template <class _Tp>
+__attribute__((device))
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __constexpr_logb(_Tp __x) {
+ return ::logb(__x);
+}
+
+template <class _Tp>
+__attribute__((device))
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp __constexpr_scalbn(_Tp __x, int __exp) {
+ return ::scalbn(__x, __exp);
+}
+
+} // namespace std//
+
+#endif // _LIBCPP_STD_VER
+
+#endif // include guard
diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h
index a3f56e832b32..064d97493659 100644
--- a/clang/lib/Headers/emmintrin.h
+++ b/clang/lib/Headers/emmintrin.h
@@ -38,6 +38,16 @@ typedef unsigned char __v16qu __attribute__((__vector_size__(16)));
* appear in the interface though. */
typedef signed char __v16qs __attribute__((__vector_size__(16)));
+#ifdef __SSE2__
+/* Both _Float16 and __bf16 require SSE2 being enabled. */
+typedef _Float16 __v8hf __attribute__((__vector_size__(16), __aligned__(16)));
+typedef _Float16 __m128h __attribute__((__vector_size__(16), __aligned__(16)));
+typedef _Float16 __m128h_u __attribute__((__vector_size__(16), __aligned__(1)));
+
+typedef __bf16 __v8bf __attribute__((__vector_size__(16), __aligned__(16)));
+typedef __bf16 __m128bh __attribute__((__vector_size__(16), __aligned__(16)));
+#endif
+
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS \
__attribute__((__always_inline__, __nodebug__, __target__("sse2"), \
@@ -1809,7 +1819,7 @@ static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_setr_pd(double __w,
/// \returns An initialized 128-bit floating-point vector of [2 x double] with
/// all elements set to zero.
static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_setzero_pd(void) {
- return __extension__(__m128d){0, 0};
+ return __extension__(__m128d){0.0, 0.0};
}
/// Constructs a 128-bit floating-point vector of [2 x double]. The lower
diff --git a/clang/lib/Headers/float.h b/clang/lib/Headers/float.h
index c6a6cc08462d..0e73bca0a2d6 100644
--- a/clang/lib/Headers/float.h
+++ b/clang/lib/Headers/float.h
@@ -38,9 +38,10 @@
# undef FLT_MANT_DIG
# undef DBL_MANT_DIG
# undef LDBL_MANT_DIG
-# if __STDC_VERSION__ >= 199901L || !defined(__STRICT_ANSI__) || \
- __cplusplus >= 201103L || \
- (__STDC_HOSTED__ && defined(_AIX) && defined(_ALL_SOURCE))
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
+ !defined(__STRICT_ANSI__) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ (__STDC_HOSTED__ && defined(_AIX) && defined(_ALL_SOURCE))
# undef DECIMAL_DIG
# endif
# undef FLT_DIG
@@ -67,9 +68,10 @@
# undef FLT_MIN
# undef DBL_MIN
# undef LDBL_MIN
-# if __STDC_VERSION__ >= 201112L || !defined(__STRICT_ANSI__) || \
- __cplusplus >= 201703L || \
- (__STDC_HOSTED__ && defined(_AIX) && defined(_ALL_SOURCE))
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
+ !defined(__STRICT_ANSI__) || \
+ (defined(__cplusplus) && __cplusplus >= 201703L) || \
+ (__STDC_HOSTED__ && defined(_AIX) && defined(_ALL_SOURCE))
# undef FLT_TRUE_MIN
# undef DBL_TRUE_MIN
# undef LDBL_TRUE_MIN
@@ -84,7 +86,10 @@
/* Characteristics of floating point types, C99 5.2.4.2.2 */
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L)
#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
+#endif
#define FLT_ROUNDS (__builtin_flt_rounds())
#define FLT_RADIX __FLT_RADIX__
@@ -92,8 +97,9 @@
#define DBL_MANT_DIG __DBL_MANT_DIG__
#define LDBL_MANT_DIG __LDBL_MANT_DIG__
-#if __STDC_VERSION__ >= 199901L || !defined(__STRICT_ANSI__) || \
- __cplusplus >= 201103L || \
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
+ !defined(__STRICT_ANSI__) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L) || \
(__STDC_HOSTED__ && defined(_AIX) && defined(_ALL_SOURCE))
# define DECIMAL_DIG __DECIMAL_DIG__
#endif
@@ -130,8 +136,9 @@
#define DBL_MIN __DBL_MIN__
#define LDBL_MIN __LDBL_MIN__
-#if __STDC_VERSION__ >= 201112L || !defined(__STRICT_ANSI__) || \
- __cplusplus >= 201703L || \
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
+ !defined(__STRICT_ANSI__) || \
+ (defined(__cplusplus) && __cplusplus >= 201703L) || \
(__STDC_HOSTED__ && defined(_AIX) && defined(_ALL_SOURCE))
# define FLT_TRUE_MIN __FLT_DENORM_MIN__
# define DBL_TRUE_MIN __DBL_DENORM_MIN__
diff --git a/clang/lib/Headers/gfniintrin.h b/clang/lib/Headers/gfniintrin.h
index a59238b0b131..5ec53c54fc4e 100644
--- a/clang/lib/Headers/gfniintrin.h
+++ b/clang/lib/Headers/gfniintrin.h
@@ -20,10 +20,12 @@
/* Default attributes for YMM unmasked form. */
#define __DEFAULT_FN_ATTRS_Y __attribute__((__always_inline__, __nodebug__, __target__("avx,gfni"), __min_vector_width__(256)))
-/* Default attributes for ZMM forms. */
-#define __DEFAULT_FN_ATTRS_Z __attribute__((__always_inline__, __nodebug__, __target__("avx512bw,gfni"), __min_vector_width__(512)))
+/* Default attributes for ZMM unmasked forms. */
+#define __DEFAULT_FN_ATTRS_Z __attribute__((__always_inline__, __nodebug__, __target__("avx512f,gfni"), __min_vector_width__(512)))
+/* Default attributes for ZMM masked forms. */
+#define __DEFAULT_FN_ATTRS_Z_MASK __attribute__((__always_inline__, __nodebug__, __target__("avx512bw,gfni"), __min_vector_width__(512)))
-/* Default attributes for VLX forms. */
+/* Default attributes for VLX masked forms. */
#define __DEFAULT_FN_ATTRS_VL128 __attribute__((__always_inline__, __nodebug__, __target__("avx512bw,avx512vl,gfni"), __min_vector_width__(128)))
#define __DEFAULT_FN_ATTRS_VL256 __attribute__((__always_inline__, __nodebug__, __target__("avx512bw,avx512vl,gfni"), __min_vector_width__(256)))
@@ -99,7 +101,7 @@ _mm512_gf2p8mul_epi8(__m512i __A, __m512i __B)
(__v64qi) __B);
}
-static __inline__ __m512i __DEFAULT_FN_ATTRS_Z
+static __inline__ __m512i __DEFAULT_FN_ATTRS_Z_MASK
_mm512_mask_gf2p8mul_epi8(__m512i __S, __mmask64 __U, __m512i __A, __m512i __B)
{
return (__m512i) __builtin_ia32_selectb_512(__U,
@@ -107,7 +109,7 @@ _mm512_mask_gf2p8mul_epi8(__m512i __S, __mmask64 __U, __m512i __A, __m512i __B)
(__v64qi) __S);
}
-static __inline__ __m512i __DEFAULT_FN_ATTRS_Z
+static __inline__ __m512i __DEFAULT_FN_ATTRS_Z_MASK
_mm512_maskz_gf2p8mul_epi8(__mmask64 __U, __m512i __A, __m512i __B)
{
return _mm512_mask_gf2p8mul_epi8((__m512i)_mm512_setzero_si512(),
diff --git a/clang/lib/Headers/hlsl/hlsl_basic_types.h b/clang/lib/Headers/hlsl/hlsl_basic_types.h
index e68715f1a6a4..9ea605cfa840 100644
--- a/clang/lib/Headers/hlsl/hlsl_basic_types.h
+++ b/clang/lib/Headers/hlsl/hlsl_basic_types.h
@@ -9,6 +9,7 @@
#ifndef _HLSL_HLSL_BASIC_TYPES_H_
#define _HLSL_HLSL_BASIC_TYPES_H_
+namespace hlsl {
// built-in scalar data types:
#ifdef __HLSL_ENABLE_16_BIT
@@ -61,4 +62,6 @@ typedef vector<double, 2> double2;
typedef vector<double, 3> double3;
typedef vector<double, 4> double4;
+} // namespace hlsl
+
#endif //_HLSL_HLSL_BASIC_TYPES_H_
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index b5cdb8b44970..d811a28a4335 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -9,7 +9,215 @@
#ifndef _HLSL_HLSL_INTRINSICS_H_
#define _HLSL_HLSL_INTRINSICS_H_
+namespace hlsl {
+
+__attribute__((availability(shadermodel, introduced = 6.0)))
__attribute__((clang_builtin_alias(__builtin_hlsl_wave_active_count_bits))) uint
WaveActiveCountBits(bool bBit);
+// abs builtins
+#ifdef __HLSL_ENABLE_16_BIT
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+int16_t abs(int16_t);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+int16_t2 abs(int16_t2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+int16_t3 abs(int16_t3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+int16_t4 abs(int16_t4);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs))) half abs(half);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+half2 abs(half2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+half3 abs(half3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+half4 abs(half4);
+#endif
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs))) int abs(int);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs))) int2 abs(int2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs))) int3 abs(int3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs))) int4 abs(int4);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs))) float
+abs(float);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+float2 abs(float2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+float3 abs(float3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+float4 abs(float4);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+int64_t abs(int64_t);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+int64_t2 abs(int64_t2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+int64_t3 abs(int64_t3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+int64_t4 abs(int64_t4);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs))) double
+abs(double);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+double2 abs(double2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+double3 abs(double3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_abs)))
+double4 abs(double4);
+
+// sqrt builtins
+__attribute__((clang_builtin_alias(__builtin_sqrt))) double sqrt(double In);
+__attribute__((clang_builtin_alias(__builtin_sqrtf))) float sqrt(float In);
+
+#ifdef __HLSL_ENABLE_16_BIT
+__attribute__((clang_builtin_alias(__builtin_sqrtf16))) half sqrt(half In);
+#endif
+
+// ceil builtins
+#ifdef __HLSL_ENABLE_16_BIT
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+half ceil(half);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+half2 ceil(half2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+half3 ceil(half3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+half4 ceil(half4);
+#endif
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil))) float
+ceil(float);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+float2 ceil(float2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+float3 ceil(float3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+float4 ceil(float4);
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil))) double
+ceil(double);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+double2 ceil(double2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+double3 ceil(double3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_ceil)))
+double4 ceil(double4);
+
+// floor builtins
+#ifdef __HLSL_ENABLE_16_BIT
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+half floor(half);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+half2 floor(half2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+half3 floor(half3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+half4 floor(half4);
+#endif
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor))) float
+floor(float);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+float2 floor(float2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+float3 floor(float3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+float4 floor(float4);
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor))) double
+floor(double);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+double2 floor(double2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+double3 floor(double3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_floor)))
+double4 floor(double4);
+
+// cos builtins
+#ifdef __HLSL_ENABLE_16_BIT
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos))) half cos(half);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+half2 cos(half2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+half3 cos(half3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+half4 cos(half4);
+#endif
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos))) float
+cos(float);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+float2 cos(float2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+float3 cos(float3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+float4 cos(float4);
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos))) double
+cos(double);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+double2 cos(double2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+double3 cos(double3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_cos)))
+double4 cos(double4);
+
+// sin builtins
+#ifdef __HLSL_ENABLE_16_BIT
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin))) half sin(half);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+half2 sin(half2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+half3 sin(half3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+half4 sin(half4);
+#endif
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin))) float
+sin(float);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+float2 sin(float2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+float3 sin(float3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+float4 sin(float4);
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin))) double
+sin(double);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+double2 sin(double2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+double3 sin(double3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_sin)))
+double4 sin(double4);
+
+// trunc builtins
+#ifdef __HLSL_ENABLE_16_BIT
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+half trunc(half);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+half2 trunc(half2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+half3 trunc(half3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+half4 trunc(half4);
+#endif
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc))) float
+trunc(float);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+float2 trunc(float2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+float3 trunc(float3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+float4 trunc(float4);
+
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc))) double
+trunc(double);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+double2 trunc(double2);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+double3 trunc(double3);
+__attribute__((clang_builtin_alias(__builtin_elementwise_trunc)))
+double4 trunc(double4);
+
+} // namespace hlsl
#endif //_HLSL_HLSL_INTRINSICS_H_
diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h
index e4d7a799b1ca..6967b46fdb24 100644
--- a/clang/lib/Headers/immintrin.h
+++ b/clang/lib/Headers/immintrin.h
@@ -190,6 +190,11 @@
#endif
#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__AVXIFMA__)
+#include <avxifmaintrin.h>
+#endif
+
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
defined(__AVX512VBMI__)
#include <avx512vbmiintrin.h>
#endif
@@ -214,17 +219,13 @@
#include <avx512pfintrin.h>
#endif
-/*
- * FIXME: _Float16 type is legal only when HW support float16 operation.
- * We use __AVX512FP16__ to identify if float16 is supported or not, so
- * when float16 is not supported, the related header is not included.
- *
- */
-#if defined(__AVX512FP16__)
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__AVX512FP16__)
#include <avx512fp16intrin.h>
#endif
-#if defined(__AVX512FP16__) && defined(__AVX512VL__)
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ (defined(__AVX512VL__) && defined(__AVX512FP16__))
#include <avx512vlfp16intrin.h>
#endif
@@ -259,6 +260,16 @@
#endif
#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__AVXVNNIINT8__)
+#include <avxvnniint8intrin.h>
+#endif
+
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__AVXNECONVERT__)
+#include <avxneconvertintrin.h>
+#endif
+
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
defined(__RDPID__)
/// Returns the value of the IA32_TSC_AUX MSR (0xc0000103).
///
@@ -291,6 +302,23 @@ _rdrand64_step(unsigned long long *__p)
{
return (int)__builtin_ia32_rdrand64_step(__p);
}
+#else
+// We need to emulate the functionality of 64-bit rdrand with 2 32-bit
+// rdrand instructions.
+static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd")))
+_rdrand64_step(unsigned long long *__p)
+{
+ unsigned int __lo, __hi;
+ unsigned int __res_lo = __builtin_ia32_rdrand32_step(&__lo);
+ unsigned int __res_hi = __builtin_ia32_rdrand32_step(&__hi);
+ if (__res_lo && __res_hi) {
+ *__p = ((unsigned long long)__hi << 32) | (unsigned long long)__lo;
+ return 1;
+ } else {
+ *__p = 0;
+ return 0;
+ }
+}
#endif
#endif /* __RDRND__ */
@@ -495,6 +523,10 @@ _storebe_i64(void * __P, long long __D) {
defined(__INVPCID__)
#include <invpcidintrin.h>
#endif
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__AMXFP16__)
+#include <amxfp16intrin.h>
+#endif
#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
defined(__KL__) || defined(__WIDEKL__)
diff --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h
new file mode 100644
index 000000000000..c5c533ee0b8c
--- /dev/null
+++ b/clang/lib/Headers/larchintrin.h
@@ -0,0 +1,234 @@
+/*===------------ larchintrin.h - LoongArch intrinsics ---------------------===
+ *
+ * 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 _LOONGARCH_BASE_INTRIN_H
+#define _LOONGARCH_BASE_INTRIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct rdtime {
+ unsigned int value;
+ unsigned int timeid;
+} __rdtime_t;
+
+#if __loongarch_grlen == 64
+typedef struct drdtime {
+ unsigned long dvalue;
+ unsigned long dtimeid;
+} __drdtime_t;
+
+extern __inline __drdtime_t
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __rdtime_d(void) {
+ __drdtime_t __drdtime;
+ __asm__ volatile(
+ "rdtime.d %[val], %[tid]\n\t"
+ : [val] "=&r"(__drdtime.dvalue), [tid] "=&r"(__drdtime.dtimeid));
+ return __drdtime;
+}
+#endif
+
+extern __inline __rdtime_t
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __rdtimeh_w(void) {
+ __rdtime_t __rdtime;
+ __asm__ volatile("rdtimeh.w %[val], %[tid]\n\t"
+ : [val] "=&r"(__rdtime.value), [tid] "=&r"(__rdtime.timeid));
+ return __rdtime;
+}
+
+extern __inline __rdtime_t
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __rdtimel_w(void) {
+ __rdtime_t __rdtime;
+ __asm__ volatile("rdtimel.w %[val], %[tid]\n\t"
+ : [val] "=&r"(__rdtime.value), [tid] "=&r"(__rdtime.timeid));
+ return __rdtime;
+}
+
+#if __loongarch_grlen == 64
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __crc_w_b_w(char _1, int _2) {
+ return (int)__builtin_loongarch_crc_w_b_w((char)_1, (int)_2);
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __crc_w_h_w(short _1, int _2) {
+ return (int)__builtin_loongarch_crc_w_h_w((short)_1, (int)_2);
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __crc_w_w_w(int _1, int _2) {
+ return (int)__builtin_loongarch_crc_w_w_w((int)_1, (int)_2);
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __crc_w_d_w(long int _1, int _2) {
+ return (int)__builtin_loongarch_crc_w_d_w((long int)_1, (int)_2);
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __crcc_w_b_w(char _1, int _2) {
+ return (int)__builtin_loongarch_crcc_w_b_w((char)_1, (int)_2);
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __crcc_w_h_w(short _1, int _2) {
+ return (int)__builtin_loongarch_crcc_w_h_w((short)_1, (int)_2);
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __crcc_w_w_w(int _1, int _2) {
+ return (int)__builtin_loongarch_crcc_w_w_w((int)_1, (int)_2);
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __crcc_w_d_w(long int _1, int _2) {
+ return (int)__builtin_loongarch_crcc_w_d_w((long int)_1, (int)_2);
+}
+#endif
+
+#define __break(/*ui15*/ _1) __builtin_loongarch_break((_1))
+
+#if __loongarch_grlen == 32
+#define __cacop_w(/*uimm5*/ _1, /*unsigned int*/ _2, /*simm12*/ _3) \
+ ((void)__builtin_loongarch_cacop_w((_1), (unsigned int)(_2), (_3)))
+#endif
+
+#if __loongarch_grlen == 64
+#define __cacop_d(/*uimm5*/ _1, /*unsigned long int*/ _2, /*simm12*/ _3) \
+ ((void)__builtin_loongarch_cacop_d((_1), (unsigned long int)(_2), (_3)))
+#endif
+
+#define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar((_1))
+
+#define __ibar(/*ui15*/ _1) __builtin_loongarch_ibar((_1))
+
+#define __movfcsr2gr(/*ui5*/ _1) __builtin_loongarch_movfcsr2gr((_1));
+
+#define __movgr2fcsr(/*ui5*/ _1, _2) \
+ __builtin_loongarch_movgr2fcsr((_1), (unsigned int)_2);
+
+#define __syscall(/*ui15*/ _1) __builtin_loongarch_syscall((_1))
+
+#define __csrrd_w(/*ui14*/ _1) ((unsigned int)__builtin_loongarch_csrrd_w((_1)))
+
+#define __csrwr_w(/*unsigned int*/ _1, /*ui14*/ _2) \
+ ((unsigned int)__builtin_loongarch_csrwr_w((unsigned int)(_1), (_2)))
+
+#define __csrxchg_w(/*unsigned int*/ _1, /*unsigned int*/ _2, /*ui14*/ _3) \
+ ((unsigned int)__builtin_loongarch_csrxchg_w((unsigned int)(_1), \
+ (unsigned int)(_2), (_3)))
+
+#if __loongarch_grlen == 64
+#define __csrrd_d(/*ui14*/ _1) \
+ ((unsigned long int)__builtin_loongarch_csrrd_d((_1)))
+
+#define __csrwr_d(/*unsigned long int*/ _1, /*ui14*/ _2) \
+ ((unsigned long int)__builtin_loongarch_csrwr_d((unsigned long int)(_1), \
+ (_2)))
+
+#define __csrxchg_d(/*unsigned long int*/ _1, /*unsigned long int*/ _2, \
+ /*ui14*/ _3) \
+ ((unsigned long int)__builtin_loongarch_csrxchg_d( \
+ (unsigned long int)(_1), (unsigned long int)(_2), (_3)))
+#endif
+
+extern __inline unsigned char
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __iocsrrd_b(unsigned int _1) {
+ return (unsigned char)__builtin_loongarch_iocsrrd_b((unsigned int)_1);
+}
+
+extern __inline unsigned char
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __iocsrrd_h(unsigned int _1) {
+ return (unsigned short)__builtin_loongarch_iocsrrd_h((unsigned int)_1);
+}
+
+extern __inline unsigned int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __iocsrrd_w(unsigned int _1) {
+ return (unsigned int)__builtin_loongarch_iocsrrd_w((unsigned int)_1);
+}
+
+#if __loongarch_grlen == 64
+extern __inline unsigned long int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __iocsrrd_d(unsigned int _1) {
+ return (unsigned long int)__builtin_loongarch_iocsrrd_d((unsigned int)_1);
+}
+#endif
+
+extern __inline void
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __iocsrwr_b(unsigned char _1, unsigned int _2) {
+ __builtin_loongarch_iocsrwr_b((unsigned char)_1, (unsigned int)_2);
+}
+
+extern __inline void
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __iocsrwr_h(unsigned short _1, unsigned int _2) {
+ __builtin_loongarch_iocsrwr_h((unsigned short)_1, (unsigned int)_2);
+}
+
+extern __inline void
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __iocsrwr_w(unsigned int _1, unsigned int _2) {
+ __builtin_loongarch_iocsrwr_w((unsigned int)_1, (unsigned int)_2);
+}
+
+extern __inline unsigned int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __cpucfg(unsigned int _1) {
+ return (unsigned int)__builtin_loongarch_cpucfg((unsigned int)_1);
+}
+
+#if __loongarch_grlen == 64
+extern __inline void
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __iocsrwr_d(unsigned long int _1, unsigned int _2) {
+ __builtin_loongarch_iocsrwr_d((unsigned long int)_1, (unsigned int)_2);
+}
+
+extern __inline void
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __asrtgt_d(long int _1, long int _2) {
+ __builtin_loongarch_asrtgt_d((long int)_1, (long int)_2);
+}
+
+extern __inline void
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ __asrtle_d(long int _1, long int _2) {
+ __builtin_loongarch_asrtle_d((long int)_1, (long int)_2);
+}
+#endif
+
+#if __loongarch_grlen == 64
+#define __lddir_d(/*long int*/ _1, /*ui5*/ _2) \
+ ((long int)__builtin_loongarch_lddir_d((long int)(_1), (_2)))
+
+#define __ldpte_d(/*long int*/ _1, /*ui5*/ _2) \
+ ((void)__builtin_loongarch_ldpte_d((long int)(_1), (_2)))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LOONGARCH_BASE_INTRIN_H */
diff --git a/clang/lib/Headers/limits.h b/clang/lib/Headers/limits.h
index cfd23a219ee5..32cc901b26be 100644
--- a/clang/lib/Headers/limits.h
+++ b/clang/lib/Headers/limits.h
@@ -65,7 +65,7 @@
/* C2x 5.2.4.2.1 */
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
#define BOOL_WIDTH __BOOL_WIDTH__
#define CHAR_WIDTH CHAR_BIT
#define SCHAR_WIDTH CHAR_BIT
@@ -93,7 +93,8 @@
/* C99 5.2.4.2.1: Added long long.
C++11 18.3.3.2: same contents as the Standard C Library header <limits.h>.
*/
-#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L)
#undef LLONG_MIN
#undef LLONG_MAX
diff --git a/clang/lib/Headers/opencl-c-base.h b/clang/lib/Headers/opencl-c-base.h
index c433b4f7eb1a..fad2f9c0272b 100644
--- a/clang/lib/Headers/opencl-c-base.h
+++ b/clang/lib/Headers/opencl-c-base.h
@@ -74,6 +74,25 @@
#define __opencl_c_atomic_scope_all_devices 1
#define __opencl_c_read_write_images 1
#endif // defined(__SPIR__)
+
+// Undefine any feature macros that have been explicitly disabled using
+// an __undef_<feature> macro.
+#ifdef __undef___opencl_c_work_group_collective_functions
+#undef __opencl_c_work_group_collective_functions
+#endif
+#ifdef __undef___opencl_c_atomic_order_seq_cst
+#undef __opencl_c_atomic_order_seq_cst
+#endif
+#ifdef __undef___opencl_c_atomic_scope_device
+#undef __opencl_c_atomic_scope_device
+#endif
+#ifdef __undef___opencl_c_atomic_scope_all_devices
+#undef __opencl_c_atomic_scope_all_devices
+#endif
+#ifdef __undef___opencl_c_read_write_images
+#undef __opencl_c_read_write_images
+#endif
+
#endif // (__OPENCL_CPP_VERSION__ == 202100 || __OPENCL_C_VERSION__ == 300)
#if !defined(__opencl_c_generic_address_space)
diff --git a/clang/lib/Headers/opencl-c.h b/clang/lib/Headers/opencl-c.h
index 72a6bfeafd6a..288bb18bc654 100644
--- a/clang/lib/Headers/opencl-c.h
+++ b/clang/lib/Headers/opencl-c.h
@@ -12396,11 +12396,11 @@ void __ovld vstorea_half16_rtn(double16, size_t, __private half *);
* image objects and then want to read the updated data.
*/
-void __ovld __conv barrier(cl_mem_fence_flags flags);
+void __ovld __conv barrier(cl_mem_fence_flags);
#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);
-void __ovld __conv work_group_barrier(cl_mem_fence_flags flags);
+void __ovld __conv work_group_barrier(cl_mem_fence_flags, memory_scope);
+void __ovld __conv work_group_barrier(cl_mem_fence_flags);
#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
@@ -12418,7 +12418,7 @@ void __ovld __conv work_group_barrier(cl_mem_fence_flags flags);
* CLK_LOCAL_MEM_FENCE
* CLK_GLOBAL_MEM_FENCE.
*/
-void __ovld mem_fence(cl_mem_fence_flags flags);
+void __ovld mem_fence(cl_mem_fence_flags);
/**
* Read memory barrier that orders only
@@ -12430,7 +12430,7 @@ void __ovld mem_fence(cl_mem_fence_flags flags);
* CLK_LOCAL_MEM_FENCE
* CLK_GLOBAL_MEM_FENCE.
*/
-void __ovld read_mem_fence(cl_mem_fence_flags flags);
+void __ovld read_mem_fence(cl_mem_fence_flags);
/**
* Write memory barrier that orders only
@@ -12442,7 +12442,7 @@ void __ovld read_mem_fence(cl_mem_fence_flags flags);
* CLK_LOCAL_MEM_FENCE
* CLK_GLOBAL_MEM_FENCE.
*/
-void __ovld write_mem_fence(cl_mem_fence_flags flags);
+void __ovld write_mem_fence(cl_mem_fence_flags);
// OpenCL v2.0 s6.13.9 - Address Space Qualifier Functions
@@ -12891,29 +12891,29 @@ void __ovld prefetch(const __global half16 *, size_t);
* (old + val) and store result at location
* pointed by p. The function returns old.
*/
-int __ovld atomic_add(volatile __global int *p, int val);
-uint __ovld atomic_add(volatile __global uint *p, uint val);
-int __ovld atomic_add(volatile __local int *p, int val);
-uint __ovld atomic_add(volatile __local uint *p, uint val);
+int __ovld atomic_add(volatile __global int *, int);
+uint __ovld atomic_add(volatile __global uint *, uint);
+int __ovld atomic_add(volatile __local int *, int);
+uint __ovld atomic_add(volatile __local uint *, uint);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_add(volatile int *p, int val);
-uint __ovld atomic_add(volatile uint *p, uint val);
+int __ovld atomic_add(volatile int *, int);
+uint __ovld atomic_add(volatile uint *, uint);
#endif
#if defined(cl_khr_global_int32_base_atomics)
-int __ovld atom_add(volatile __global int *p, int val);
-uint __ovld atom_add(volatile __global uint *p, uint val);
+int __ovld atom_add(volatile __global int *, int);
+uint __ovld atom_add(volatile __global uint *, uint);
#endif
#if defined(cl_khr_local_int32_base_atomics)
-int __ovld atom_add(volatile __local int *p, int val);
-uint __ovld atom_add(volatile __local uint *p, uint val);
+int __ovld atom_add(volatile __local int *, int);
+uint __ovld atom_add(volatile __local uint *, uint);
#endif
#if defined(cl_khr_int64_base_atomics)
-long __ovld atom_add(volatile __global long *p, long val);
-ulong __ovld atom_add(volatile __global ulong *p, ulong val);
-long __ovld atom_add(volatile __local long *p, long val);
-ulong __ovld atom_add(volatile __local ulong *p, ulong val);
+long __ovld atom_add(volatile __global long *, long);
+ulong __ovld atom_add(volatile __global ulong *, ulong);
+long __ovld atom_add(volatile __local long *, long);
+ulong __ovld atom_add(volatile __local ulong *, ulong);
#endif
/**
@@ -12921,29 +12921,29 @@ ulong __ovld atom_add(volatile __local ulong *p, ulong val);
* Compute (old - val) and store result at location pointed by p. The function
* returns old.
*/
-int __ovld atomic_sub(volatile __global int *p, int val);
-uint __ovld atomic_sub(volatile __global uint *p, uint val);
-int __ovld atomic_sub(volatile __local int *p, int val);
-uint __ovld atomic_sub(volatile __local uint *p, uint val);
+int __ovld atomic_sub(volatile __global int *, int);
+uint __ovld atomic_sub(volatile __global uint *, uint);
+int __ovld atomic_sub(volatile __local int *, int);
+uint __ovld atomic_sub(volatile __local uint *, uint);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_sub(volatile int *p, int val);
-uint __ovld atomic_sub(volatile uint *p, uint val);
+int __ovld atomic_sub(volatile int *, int);
+uint __ovld atomic_sub(volatile uint *, uint);
#endif
#if defined(cl_khr_global_int32_base_atomics)
-int __ovld atom_sub(volatile __global int *p, int val);
-uint __ovld atom_sub(volatile __global uint *p, uint val);
+int __ovld atom_sub(volatile __global int *, int);
+uint __ovld atom_sub(volatile __global uint *, uint);
#endif
#if defined(cl_khr_local_int32_base_atomics)
-int __ovld atom_sub(volatile __local int *p, int val);
-uint __ovld atom_sub(volatile __local uint *p, uint val);
+int __ovld atom_sub(volatile __local int *, int);
+uint __ovld atom_sub(volatile __local uint *, uint);
#endif
#if defined(cl_khr_int64_base_atomics)
-long __ovld atom_sub(volatile __global long *p, long val);
-ulong __ovld atom_sub(volatile __global ulong *p, ulong val);
-long __ovld atom_sub(volatile __local long *p, long val);
-ulong __ovld atom_sub(volatile __local ulong *p, ulong val);
+long __ovld atom_sub(volatile __global long *, long);
+ulong __ovld atom_sub(volatile __global ulong *, ulong);
+long __ovld atom_sub(volatile __local long *, long);
+ulong __ovld atom_sub(volatile __local ulong *, ulong);
#endif
/**
@@ -12951,32 +12951,32 @@ ulong __ovld atom_sub(volatile __local ulong *p, ulong val);
* with new value given by val. Returns old
* value.
*/
-int __ovld atomic_xchg(volatile __global int *p, int val);
-uint __ovld atomic_xchg(volatile __global uint *p, uint val);
-int __ovld atomic_xchg(volatile __local int *p, int val);
-uint __ovld atomic_xchg(volatile __local uint *p, uint val);
-float __ovld atomic_xchg(volatile __global float *p, float val);
-float __ovld atomic_xchg(volatile __local float *p, float val);
+int __ovld atomic_xchg(volatile __global int *, int);
+uint __ovld atomic_xchg(volatile __global uint *, uint);
+int __ovld atomic_xchg(volatile __local int *, int);
+uint __ovld atomic_xchg(volatile __local uint *, uint);
+float __ovld atomic_xchg(volatile __global float *, float);
+float __ovld atomic_xchg(volatile __local float *, float);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_xchg(volatile int *p, int val);
-uint __ovld atomic_xchg(volatile uint *p, uint val);
-float __ovld atomic_xchg(volatile float *p, float val);
+int __ovld atomic_xchg(volatile int *, int);
+uint __ovld atomic_xchg(volatile uint *, uint);
+float __ovld atomic_xchg(volatile float *, float);
#endif
#if defined(cl_khr_global_int32_base_atomics)
-int __ovld atom_xchg(volatile __global int *p, int val);
-uint __ovld atom_xchg(volatile __global uint *p, uint val);
+int __ovld atom_xchg(volatile __global int *, int);
+uint __ovld atom_xchg(volatile __global uint *, uint);
#endif
#if defined(cl_khr_local_int32_base_atomics)
-int __ovld atom_xchg(volatile __local int *p, int val);
-uint __ovld atom_xchg(volatile __local uint *p, uint val);
+int __ovld atom_xchg(volatile __local int *, int);
+uint __ovld atom_xchg(volatile __local uint *, uint);
#endif
#if defined(cl_khr_int64_base_atomics)
-long __ovld atom_xchg(volatile __global long *p, long val);
-long __ovld atom_xchg(volatile __local long *p, long val);
-ulong __ovld atom_xchg(volatile __global ulong *p, ulong val);
-ulong __ovld atom_xchg(volatile __local ulong *p, ulong val);
+long __ovld atom_xchg(volatile __global long *, long);
+long __ovld atom_xchg(volatile __local long *, long);
+ulong __ovld atom_xchg(volatile __global ulong *, ulong);
+ulong __ovld atom_xchg(volatile __local ulong *, ulong);
#endif
/**
@@ -13048,29 +13048,29 @@ ulong __ovld atom_dec(volatile __local ulong *);
* location pointed by p. The function
* returns old.
*/
-int __ovld atomic_cmpxchg(volatile __global int *p, int cmp, int val);
-uint __ovld atomic_cmpxchg(volatile __global uint *p, uint cmp, uint val);
-int __ovld atomic_cmpxchg(volatile __local int *p, int cmp, int val);
-uint __ovld atomic_cmpxchg(volatile __local uint *p, uint cmp, uint val);
+int __ovld atomic_cmpxchg(volatile __global int *, int, int);
+uint __ovld atomic_cmpxchg(volatile __global uint *, uint, uint);
+int __ovld atomic_cmpxchg(volatile __local int *, int, int);
+uint __ovld atomic_cmpxchg(volatile __local uint *, uint, uint);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_cmpxchg(volatile int *p, int cmp, int val);
-uint __ovld atomic_cmpxchg(volatile uint *p, uint cmp, uint val);
+int __ovld atomic_cmpxchg(volatile int *, int, int);
+uint __ovld atomic_cmpxchg(volatile uint *, uint, uint);
#endif
#if defined(cl_khr_global_int32_base_atomics)
-int __ovld atom_cmpxchg(volatile __global int *p, int cmp, int val);
-uint __ovld atom_cmpxchg(volatile __global uint *p, uint cmp, uint val);
+int __ovld atom_cmpxchg(volatile __global int *, int, int);
+uint __ovld atom_cmpxchg(volatile __global uint *, uint, uint);
#endif
#if defined(cl_khr_local_int32_base_atomics)
-int __ovld atom_cmpxchg(volatile __local int *p, int cmp, int val);
-uint __ovld atom_cmpxchg(volatile __local uint *p, uint cmp, uint val);
+int __ovld atom_cmpxchg(volatile __local int *, int, int);
+uint __ovld atom_cmpxchg(volatile __local uint *, uint, uint);
#endif
#if defined(cl_khr_int64_base_atomics)
-long __ovld atom_cmpxchg(volatile __global long *p, long cmp, long val);
-ulong __ovld atom_cmpxchg(volatile __global ulong *p, ulong cmp, ulong val);
-long __ovld atom_cmpxchg(volatile __local long *p, long cmp, long val);
-ulong __ovld atom_cmpxchg(volatile __local ulong *p, ulong cmp, ulong val);
+long __ovld atom_cmpxchg(volatile __global long *, long, long);
+ulong __ovld atom_cmpxchg(volatile __global ulong *, ulong, ulong);
+long __ovld atom_cmpxchg(volatile __local long *, long, long);
+ulong __ovld atom_cmpxchg(volatile __local ulong *, ulong, ulong);
#endif
/**
@@ -13080,29 +13080,29 @@ ulong __ovld atom_cmpxchg(volatile __local ulong *p, ulong cmp, ulong val);
* location pointed by p. The function
* returns old.
*/
-int __ovld atomic_min(volatile __global int *p, int val);
-uint __ovld atomic_min(volatile __global uint *p, uint val);
-int __ovld atomic_min(volatile __local int *p, int val);
-uint __ovld atomic_min(volatile __local uint *p, uint val);
+int __ovld atomic_min(volatile __global int *, int);
+uint __ovld atomic_min(volatile __global uint *, uint);
+int __ovld atomic_min(volatile __local int *, int);
+uint __ovld atomic_min(volatile __local uint *, uint);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_min(volatile int *p, int val);
-uint __ovld atomic_min(volatile uint *p, uint val);
+int __ovld atomic_min(volatile int *, int);
+uint __ovld atomic_min(volatile uint *, uint);
#endif
#if defined(cl_khr_global_int32_extended_atomics)
-int __ovld atom_min(volatile __global int *p, int val);
-uint __ovld atom_min(volatile __global uint *p, uint val);
+int __ovld atom_min(volatile __global int *, int);
+uint __ovld atom_min(volatile __global uint *, uint);
#endif
#if defined(cl_khr_local_int32_extended_atomics)
-int __ovld atom_min(volatile __local int *p, int val);
-uint __ovld atom_min(volatile __local uint *p, uint val);
+int __ovld atom_min(volatile __local int *, int);
+uint __ovld atom_min(volatile __local uint *, uint);
#endif
#if defined(cl_khr_int64_extended_atomics)
-long __ovld atom_min(volatile __global long *p, long val);
-ulong __ovld atom_min(volatile __global ulong *p, ulong val);
-long __ovld atom_min(volatile __local long *p, long val);
-ulong __ovld atom_min(volatile __local ulong *p, ulong val);
+long __ovld atom_min(volatile __global long *, long);
+ulong __ovld atom_min(volatile __global ulong *, ulong);
+long __ovld atom_min(volatile __local long *, long);
+ulong __ovld atom_min(volatile __local ulong *, ulong);
#endif
/**
@@ -13112,29 +13112,29 @@ ulong __ovld atom_min(volatile __local ulong *p, ulong val);
* location pointed by p. The function
* returns old.
*/
-int __ovld atomic_max(volatile __global int *p, int val);
-uint __ovld atomic_max(volatile __global uint *p, uint val);
-int __ovld atomic_max(volatile __local int *p, int val);
-uint __ovld atomic_max(volatile __local uint *p, uint val);
+int __ovld atomic_max(volatile __global int *, int);
+uint __ovld atomic_max(volatile __global uint *, uint);
+int __ovld atomic_max(volatile __local int *, int);
+uint __ovld atomic_max(volatile __local uint *, uint);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_max(volatile int *p, int val);
-uint __ovld atomic_max(volatile uint *p, uint val);
+int __ovld atomic_max(volatile int *, int);
+uint __ovld atomic_max(volatile uint *, uint);
#endif
#if defined(cl_khr_global_int32_extended_atomics)
-int __ovld atom_max(volatile __global int *p, int val);
-uint __ovld atom_max(volatile __global uint *p, uint val);
+int __ovld atom_max(volatile __global int *, int);
+uint __ovld atom_max(volatile __global uint *, uint);
#endif
#if defined(cl_khr_local_int32_extended_atomics)
-int __ovld atom_max(volatile __local int *p, int val);
-uint __ovld atom_max(volatile __local uint *p, uint val);
+int __ovld atom_max(volatile __local int *, int);
+uint __ovld atom_max(volatile __local uint *, uint);
#endif
#if defined(cl_khr_int64_extended_atomics)
-long __ovld atom_max(volatile __global long *p, long val);
-ulong __ovld atom_max(volatile __global ulong *p, ulong val);
-long __ovld atom_max(volatile __local long *p, long val);
-ulong __ovld atom_max(volatile __local ulong *p, ulong val);
+long __ovld atom_max(volatile __global long *, long);
+ulong __ovld atom_max(volatile __global ulong *, ulong);
+long __ovld atom_max(volatile __local long *, long);
+ulong __ovld atom_max(volatile __local ulong *, ulong);
#endif
/**
@@ -13143,29 +13143,29 @@ ulong __ovld atom_max(volatile __local ulong *p, ulong val);
* (old & val) and store result at location
* pointed by p. The function returns old.
*/
-int __ovld atomic_and(volatile __global int *p, int val);
-uint __ovld atomic_and(volatile __global uint *p, uint val);
-int __ovld atomic_and(volatile __local int *p, int val);
-uint __ovld atomic_and(volatile __local uint *p, uint val);
+int __ovld atomic_and(volatile __global int *, int);
+uint __ovld atomic_and(volatile __global uint *, uint);
+int __ovld atomic_and(volatile __local int *, int);
+uint __ovld atomic_and(volatile __local uint *, uint);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_and(volatile int *p, int val);
-uint __ovld atomic_and(volatile uint *p, uint val);
+int __ovld atomic_and(volatile int *, int);
+uint __ovld atomic_and(volatile uint *, uint);
#endif
#if defined(cl_khr_global_int32_extended_atomics)
-int __ovld atom_and(volatile __global int *p, int val);
-uint __ovld atom_and(volatile __global uint *p, uint val);
+int __ovld atom_and(volatile __global int *, int);
+uint __ovld atom_and(volatile __global uint *, uint);
#endif
#if defined(cl_khr_local_int32_extended_atomics)
-int __ovld atom_and(volatile __local int *p, int val);
-uint __ovld atom_and(volatile __local uint *p, uint val);
+int __ovld atom_and(volatile __local int *, int);
+uint __ovld atom_and(volatile __local uint *, uint);
#endif
#if defined(cl_khr_int64_extended_atomics)
-long __ovld atom_and(volatile __global long *p, long val);
-ulong __ovld atom_and(volatile __global ulong *p, ulong val);
-long __ovld atom_and(volatile __local long *p, long val);
-ulong __ovld atom_and(volatile __local ulong *p, ulong val);
+long __ovld atom_and(volatile __global long *, long);
+ulong __ovld atom_and(volatile __global ulong *, ulong);
+long __ovld atom_and(volatile __local long *, long);
+ulong __ovld atom_and(volatile __local ulong *, ulong);
#endif
/**
@@ -13174,29 +13174,29 @@ ulong __ovld atom_and(volatile __local ulong *p, ulong val);
* (old | val) and store result at location
* pointed by p. The function returns old.
*/
-int __ovld atomic_or(volatile __global int *p, int val);
-uint __ovld atomic_or(volatile __global uint *p, uint val);
-int __ovld atomic_or(volatile __local int *p, int val);
-uint __ovld atomic_or(volatile __local uint *p, uint val);
+int __ovld atomic_or(volatile __global int *, int);
+uint __ovld atomic_or(volatile __global uint *, uint);
+int __ovld atomic_or(volatile __local int *, int);
+uint __ovld atomic_or(volatile __local uint *, uint);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_or(volatile int *p, int val);
-uint __ovld atomic_or(volatile uint *p, uint val);
+int __ovld atomic_or(volatile int *, int);
+uint __ovld atomic_or(volatile uint *, uint);
#endif
#if defined(cl_khr_global_int32_extended_atomics)
-int __ovld atom_or(volatile __global int *p, int val);
-uint __ovld atom_or(volatile __global uint *p, uint val);
+int __ovld atom_or(volatile __global int *, int);
+uint __ovld atom_or(volatile __global uint *, uint);
#endif
#if defined(cl_khr_local_int32_extended_atomics)
-int __ovld atom_or(volatile __local int *p, int val);
-uint __ovld atom_or(volatile __local uint *p, uint val);
+int __ovld atom_or(volatile __local int *, int);
+uint __ovld atom_or(volatile __local uint *, uint);
#endif
#if defined(cl_khr_int64_extended_atomics)
-long __ovld atom_or(volatile __global long *p, long val);
-ulong __ovld atom_or(volatile __global ulong *p, ulong val);
-long __ovld atom_or(volatile __local long *p, long val);
-ulong __ovld atom_or(volatile __local ulong *p, ulong val);
+long __ovld atom_or(volatile __global long *, long);
+ulong __ovld atom_or(volatile __global ulong *, ulong);
+long __ovld atom_or(volatile __local long *, long);
+ulong __ovld atom_or(volatile __local ulong *, ulong);
#endif
/**
@@ -13205,29 +13205,29 @@ ulong __ovld atom_or(volatile __local ulong *p, ulong val);
* (old ^ val) and store result at location
* pointed by p. The function returns old.
*/
-int __ovld atomic_xor(volatile __global int *p, int val);
-uint __ovld atomic_xor(volatile __global uint *p, uint val);
-int __ovld atomic_xor(volatile __local int *p, int val);
-uint __ovld atomic_xor(volatile __local uint *p, uint val);
+int __ovld atomic_xor(volatile __global int *, int);
+uint __ovld atomic_xor(volatile __global uint *, uint);
+int __ovld atomic_xor(volatile __local int *, int);
+uint __ovld atomic_xor(volatile __local uint *, uint);
#ifdef __OPENCL_CPP_VERSION__
-int __ovld atomic_xor(volatile int *p, int val);
-uint __ovld atomic_xor(volatile uint *p, uint val);
+int __ovld atomic_xor(volatile int *, int);
+uint __ovld atomic_xor(volatile uint *, uint);
#endif
#if defined(cl_khr_global_int32_extended_atomics)
-int __ovld atom_xor(volatile __global int *p, int val);
-uint __ovld atom_xor(volatile __global uint *p, uint val);
+int __ovld atom_xor(volatile __global int *, int);
+uint __ovld atom_xor(volatile __global uint *, uint);
#endif
#if defined(cl_khr_local_int32_extended_atomics)
-int __ovld atom_xor(volatile __local int *p, int val);
-uint __ovld atom_xor(volatile __local uint *p, uint val);
+int __ovld atom_xor(volatile __local int *, int);
+uint __ovld atom_xor(volatile __local uint *, uint);
#endif
#if defined(cl_khr_int64_extended_atomics)
-long __ovld atom_xor(volatile __global long *p, long val);
-ulong __ovld atom_xor(volatile __global ulong *p, ulong val);
-long __ovld atom_xor(volatile __local long *p, long val);
-ulong __ovld atom_xor(volatile __local ulong *p, ulong val);
+long __ovld atom_xor(volatile __global long *, long);
+ulong __ovld atom_xor(volatile __global ulong *, ulong);
+long __ovld atom_xor(volatile __local long *, long);
+ulong __ovld atom_xor(volatile __local ulong *, ulong);
#endif
#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics)
@@ -15257,13 +15257,17 @@ float4 __ovld __purefn read_imagef(read_only image2d_t, sampler_t, float2, float
int4 __ovld __purefn read_imagei(read_only image2d_t, sampler_t, float2, float);
uint4 __ovld __purefn read_imageui(read_only image2d_t, sampler_t, float2, float);
+#ifdef cl_khr_depth_images
float __ovld __purefn read_imagef(read_only image2d_depth_t, sampler_t, float2, float);
+#endif // cl_khr_depth_images
float4 __ovld __purefn read_imagef(read_only image2d_array_t, sampler_t, float4, float);
int4 __ovld __purefn read_imagei(read_only image2d_array_t, sampler_t, float4, float);
uint4 __ovld __purefn read_imageui(read_only image2d_array_t, sampler_t, float4, float);
+#ifdef cl_khr_depth_images
float __ovld __purefn read_imagef(read_only image2d_array_depth_t, sampler_t, float4, float);
+#endif // cl_khr_depth_images
float4 __ovld __purefn read_imagef(read_only image3d_t, sampler_t, float4, float);
int4 __ovld __purefn read_imagei(read_only image3d_t, sampler_t, float4, float);
@@ -15281,13 +15285,17 @@ float4 __ovld __purefn read_imagef(read_only image2d_t, sampler_t, float2, float
int4 __ovld __purefn read_imagei(read_only image2d_t, sampler_t, float2, float2, float2);
uint4 __ovld __purefn read_imageui(read_only image2d_t, sampler_t, float2, float2, float2);
+#ifdef cl_khr_depth_images
float __ovld __purefn read_imagef(read_only image2d_depth_t, sampler_t, float2, float2, float2);
+#endif // cl_khr_depth_images
float4 __ovld __purefn read_imagef(read_only image2d_array_t, sampler_t, float4, float2, float2);
int4 __ovld __purefn read_imagei(read_only image2d_array_t, sampler_t, float4, float2, float2);
uint4 __ovld __purefn read_imageui(read_only image2d_array_t, sampler_t, float4, float2, float2);
+#ifdef cl_khr_depth_images
float __ovld __purefn read_imagef(read_only image2d_array_depth_t, sampler_t, float4, float2, float2);
+#endif // cl_khr_depth_images
float4 __ovld __purefn read_imagef(read_only image3d_t, sampler_t, float4, float4, float4);
int4 __ovld __purefn read_imagei(read_only image3d_t, sampler_t, float4, float4, float4);
@@ -15380,9 +15388,11 @@ float4 __ovld __purefn read_imagef(read_write image2d_array_t, int4);
int4 __ovld __purefn read_imagei(read_write image2d_array_t, int4);
uint4 __ovld __purefn read_imageui(read_write image2d_array_t, int4);
+#ifdef cl_khr_3d_image_writes
float4 __ovld __purefn read_imagef(read_write image3d_t, int4);
int4 __ovld __purefn read_imagei(read_write image3d_t, int4);
uint4 __ovld __purefn read_imageui(read_write image3d_t, int4);
+#endif // cl_khr_3d_image_writes
#ifdef cl_khr_depth_images
float __ovld __purefn read_imagef(read_write image2d_depth_t, int2);
@@ -15423,9 +15433,11 @@ uint4 __ovld __purefn read_imageui(read_write image2d_array_t, sampler_t, float4
float __ovld __purefn read_imagef(read_write image2d_array_depth_t, sampler_t, float4, float);
+#ifdef cl_khr_3d_image_writes
float4 __ovld __purefn read_imagef(read_write image3d_t, sampler_t, float4, float);
int4 __ovld __purefn read_imagei(read_write image3d_t, sampler_t, float4, float);
uint4 __ovld __purefn read_imageui(read_write image3d_t, sampler_t, float4, float);
+#endif // cl_khr_3d_image_writes
float4 __ovld __purefn read_imagef(read_write image1d_t, sampler_t, float, float, float);
int4 __ovld __purefn read_imagei(read_write image1d_t, sampler_t, float, float, float);
@@ -15447,9 +15459,11 @@ uint4 __ovld __purefn read_imageui(read_write image2d_array_t, sampler_t, float4
float __ovld __purefn read_imagef(read_write image2d_array_depth_t, sampler_t, float4, float2, float2);
+#ifdef cl_khr_3d_image_writes
float4 __ovld __purefn read_imagef(read_write image3d_t, sampler_t, float4, float4, float4);
int4 __ovld __purefn read_imagei(read_write image3d_t, sampler_t, float4, float4, float4);
uint4 __ovld __purefn read_imageui(read_write image3d_t, sampler_t, float4, float4, float4);
+#endif // cl_khr_3d_image_writes
#endif //cl_khr_mipmap_image
@@ -15457,7 +15471,9 @@ uint4 __ovld __purefn read_imageui(read_write image3d_t, sampler_t, float4, floa
#ifdef cl_khr_fp16
half4 __ovld __purefn read_imageh(read_write image1d_t, int);
half4 __ovld __purefn read_imageh(read_write image2d_t, int2);
+#ifdef cl_khr_3d_image_writes
half4 __ovld __purefn read_imageh(read_write image3d_t, int4);
+#endif // cl_khr_3d_image_writes
half4 __ovld __purefn read_imageh(read_write image1d_array_t, int2);
half4 __ovld __purefn read_imageh(read_write image2d_array_t, int4);
half4 __ovld __purefn read_imageh(read_write image1d_buffer_t, int);
@@ -15727,7 +15743,9 @@ int __ovld __cnfn get_image_width(write_only image2d_array_msaa_depth_t);
int __ovld __cnfn get_image_width(read_write image1d_t);
int __ovld __cnfn get_image_width(read_write image1d_buffer_t);
int __ovld __cnfn get_image_width(read_write image2d_t);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_width(read_write image3d_t);
+#endif // cl_khr_3d_image_writes
int __ovld __cnfn get_image_width(read_write image1d_array_t);
int __ovld __cnfn get_image_width(read_write image2d_array_t);
#ifdef cl_khr_depth_images
@@ -15777,7 +15795,9 @@ int __ovld __cnfn get_image_height(write_only image2d_array_msaa_depth_t);
#if defined(__opencl_c_read_write_images)
int __ovld __cnfn get_image_height(read_write image2d_t);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_height(read_write image3d_t);
+#endif // cl_khr_3d_image_writes
int __ovld __cnfn get_image_height(read_write image2d_array_t);
#ifdef cl_khr_depth_images
int __ovld __cnfn get_image_height(read_write image2d_depth_t);
@@ -15798,11 +15818,11 @@ int __ovld __cnfn get_image_depth(read_only image3d_t);
#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_depth(write_only image3d_t);
-#endif
#if defined(__opencl_c_read_write_images)
int __ovld __cnfn get_image_depth(read_write image3d_t);
#endif //defined(__opencl_c_read_write_images)
+#endif // cl_khr_3d_image_writes
// OpenCL Extension v2.0 s9.18 - Mipmaps
#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
@@ -15824,24 +15844,32 @@ int __ovld get_image_num_mip_levels(write_only image3d_t);
#if defined(__opencl_c_read_write_images)
int __ovld get_image_num_mip_levels(read_write image1d_t);
int __ovld get_image_num_mip_levels(read_write image2d_t);
+#ifdef cl_khr_3d_image_writes
int __ovld get_image_num_mip_levels(read_write image3d_t);
+#endif // cl_khr_3d_image_writes
#endif //defined(__opencl_c_read_write_images)
int __ovld get_image_num_mip_levels(read_only image1d_array_t);
int __ovld get_image_num_mip_levels(read_only image2d_array_t);
+#ifdef cl_khr_depth_images
int __ovld get_image_num_mip_levels(read_only image2d_array_depth_t);
int __ovld get_image_num_mip_levels(read_only image2d_depth_t);
+#endif // cl_khr_depth_images
int __ovld get_image_num_mip_levels(write_only image1d_array_t);
int __ovld get_image_num_mip_levels(write_only image2d_array_t);
+#ifdef cl_khr_depth_images
int __ovld get_image_num_mip_levels(write_only image2d_array_depth_t);
int __ovld get_image_num_mip_levels(write_only image2d_depth_t);
+#endif // cl_khr_depth_images
#if defined(__opencl_c_read_write_images)
int __ovld get_image_num_mip_levels(read_write image1d_array_t);
int __ovld get_image_num_mip_levels(read_write image2d_array_t);
+#ifdef cl_khr_depth_images
int __ovld get_image_num_mip_levels(read_write image2d_array_depth_t);
int __ovld get_image_num_mip_levels(read_write image2d_depth_t);
+#endif // cl_khr_depth_images
#endif //defined(__opencl_c_read_write_images)
#endif //cl_khr_mipmap_image
@@ -15906,7 +15934,9 @@ int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_dept
int __ovld __cnfn get_image_channel_data_type(read_write image1d_t);
int __ovld __cnfn get_image_channel_data_type(read_write image1d_buffer_t);
int __ovld __cnfn get_image_channel_data_type(read_write image2d_t);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_channel_data_type(read_write image3d_t);
+#endif // cl_khr_3d_image_writes
int __ovld __cnfn get_image_channel_data_type(read_write image1d_array_t);
int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_t);
#ifdef cl_khr_depth_images
@@ -15978,7 +16008,9 @@ int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_depth_t)
int __ovld __cnfn get_image_channel_order(read_write image1d_t);
int __ovld __cnfn get_image_channel_order(read_write image1d_buffer_t);
int __ovld __cnfn get_image_channel_order(read_write image2d_t);
+#ifdef cl_khr_3d_image_writes
int __ovld __cnfn get_image_channel_order(read_write image3d_t);
+#endif // cl_khr_3d_image_writes
int __ovld __cnfn get_image_channel_order(read_write image1d_array_t);
int __ovld __cnfn get_image_channel_order(read_write image2d_array_t);
#ifdef cl_khr_depth_images
@@ -16048,10 +16080,10 @@ int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_depth_t);
int4 __ovld __cnfn get_image_dim(read_only image3d_t);
#ifdef cl_khr_3d_image_writes
int4 __ovld __cnfn get_image_dim(write_only image3d_t);
-#endif
#if defined(__opencl_c_read_write_images)
int4 __ovld __cnfn get_image_dim(read_write image3d_t);
#endif //defined(__opencl_c_read_write_images)
+#endif // cl_khr_3d_image_writes
/**
* Return the image array size.
@@ -16266,9 +16298,9 @@ uint __ovld get_enqueued_num_sub_groups(void);
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);
+void __ovld __conv sub_group_barrier(cl_mem_fence_flags);
#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);
+void __ovld __conv sub_group_barrier(cl_mem_fence_flags, memory_scope);
#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld __conv sub_group_all(int predicate);
@@ -17847,15 +17879,13 @@ intel_sub_group_avc_sic_configure_skc(
uint skip_block_partition_type, uint skip_motion_vector_mask,
ulong motion_vectors, uchar bidirectional_weight, uchar skip_sad_adjustment,
intel_sub_group_avc_sic_payload_t payload);
-intel_sub_group_avc_sic_payload_t __ovld
-intel_sub_group_avc_sic_configure_ipe(
- uchar luma_intra_partition_mask, uchar intra_neighbour_availabilty,
+intel_sub_group_avc_sic_payload_t __ovld intel_sub_group_avc_sic_configure_ipe(
+ uchar luma_intra_partition_mask, uchar intra_neighbour_availability,
uchar left_edge_luma_pixels, uchar upper_left_corner_luma_pixel,
uchar upper_edge_luma_pixels, uchar upper_right_edge_luma_pixels,
uchar intra_sad_adjustment, intel_sub_group_avc_sic_payload_t payload);
-intel_sub_group_avc_sic_payload_t __ovld
-intel_sub_group_avc_sic_configure_ipe(
- uchar luma_intra_partition_mask, uchar intra_neighbour_availabilty,
+intel_sub_group_avc_sic_payload_t __ovld intel_sub_group_avc_sic_configure_ipe(
+ uchar luma_intra_partition_mask, uchar intra_neighbour_availability,
uchar left_edge_luma_pixels, uchar upper_left_corner_luma_pixel,
uchar upper_edge_luma_pixels, uchar upper_right_edge_luma_pixels,
ushort left_edge_chroma_pixels, ushort upper_left_corner_chroma_pixel,
diff --git a/clang/lib/Headers/openmp_wrappers/stdlib.h b/clang/lib/Headers/openmp_wrappers/stdlib.h
new file mode 100644
index 000000000000..d607469e04f7
--- /dev/null
+++ b/clang/lib/Headers/openmp_wrappers/stdlib.h
@@ -0,0 +1,29 @@
+/*===---- openmp_wrapper/stdlib.h ------ OpenMP math.h intercept ----- 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 __CLANG_OPENMP_STDLIB_H__
+#define __CLANG_OPENMP_STDLIB_H__
+
+#ifndef _OPENMP
+#error "This file is for OpenMP compilation only."
+#endif
+
+#include_next <stdlib.h>
+
+#ifdef __AMDGCN__
+#pragma omp begin declare variant match(device = {arch(amdgcn)})
+
+#define __OPENMP_AMDGCN__
+#include <__clang_hip_stdlib.h>
+#undef __OPENMP_AMDGCN__
+
+#pragma omp end declare variant
+#endif
+
+#endif // __CLANG_OPENMP_STDLIB_H__
diff --git a/clang/lib/Headers/ppc_wrappers/emmintrin.h b/clang/lib/Headers/ppc_wrappers/emmintrin.h
index a4c458a41bcf..0814ea5593ba 100644
--- a/clang/lib/Headers/ppc_wrappers/emmintrin.h
+++ b/clang/lib/Headers/ppc_wrappers/emmintrin.h
@@ -36,7 +36,7 @@
#ifndef EMMINTRIN_H_
#define EMMINTRIN_H_
-#if defined(__ppc64__) && \
+#if defined(__powerpc64__) && \
(defined(__linux__) || defined(__FreeBSD__) || defined(_AIX))
#include <altivec.h>
@@ -2262,7 +2262,7 @@ extern __inline __m128d
#else
#include_next <emmintrin.h>
-#endif /* defined(__ppc64__) &&
+#endif /* defined(__powerpc64__) && \
* (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */
#endif /* EMMINTRIN_H_ */
diff --git a/clang/lib/Headers/ppc_wrappers/mm_malloc.h b/clang/lib/Headers/ppc_wrappers/mm_malloc.h
index 65920917f3bd..7c1e625e44d5 100644
--- a/clang/lib/Headers/ppc_wrappers/mm_malloc.h
+++ b/clang/lib/Headers/ppc_wrappers/mm_malloc.h
@@ -10,7 +10,7 @@
#ifndef _MM_MALLOC_H_INCLUDED
#define _MM_MALLOC_H_INCLUDED
-#if defined(__ppc64__) && \
+#if defined(__powerpc64__) && \
(defined(__linux__) || defined(__FreeBSD__) || defined(_AIX))
#include <stdlib.h>
diff --git a/clang/lib/Headers/ppc_wrappers/mmintrin.h b/clang/lib/Headers/ppc_wrappers/mmintrin.h
index 70e8b81e11ee..0be3af2b0bd7 100644
--- a/clang/lib/Headers/ppc_wrappers/mmintrin.h
+++ b/clang/lib/Headers/ppc_wrappers/mmintrin.h
@@ -35,7 +35,7 @@
#ifndef _MMINTRIN_H_INCLUDED
#define _MMINTRIN_H_INCLUDED
-#if defined(__ppc64__) && \
+#if defined(__powerpc64__) && \
(defined(__linux__) || defined(__FreeBSD__) || defined(_AIX))
#include <altivec.h>
@@ -1447,7 +1447,7 @@ extern __inline __m64
#else
#include_next <mmintrin.h>
-#endif /* defined(__ppc64__) &&
+#endif /* defined(__powerpc64__) && \
* (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */
#endif /* _MMINTRIN_H_INCLUDED */
diff --git a/clang/lib/Headers/ppc_wrappers/pmmintrin.h b/clang/lib/Headers/ppc_wrappers/pmmintrin.h
index fda39edbaa22..db128192abfb 100644
--- a/clang/lib/Headers/ppc_wrappers/pmmintrin.h
+++ b/clang/lib/Headers/ppc_wrappers/pmmintrin.h
@@ -39,7 +39,7 @@
#ifndef PMMINTRIN_H_
#define PMMINTRIN_H_
-#if defined(__ppc64__) && \
+#if defined(__powerpc64__) && \
(defined(__linux__) || defined(__FreeBSD__) || defined(_AIX))
/* We need definitions from the SSE2 and SSE header files*/
@@ -139,7 +139,7 @@ extern __inline __m128i
#else
#include_next <pmmintrin.h>
-#endif /* defined(__ppc64__) &&
+#endif /* defined(__powerpc64__) && \
* (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */
#endif /* PMMINTRIN_H_ */
diff --git a/clang/lib/Headers/ppc_wrappers/smmintrin.h b/clang/lib/Headers/ppc_wrappers/smmintrin.h
index 6fe6c8a93d9b..6fe6d2a157a5 100644
--- a/clang/lib/Headers/ppc_wrappers/smmintrin.h
+++ b/clang/lib/Headers/ppc_wrappers/smmintrin.h
@@ -29,7 +29,7 @@
#ifndef SMMINTRIN_H_
#define SMMINTRIN_H_
-#if defined(__ppc64__) && \
+#if defined(__powerpc64__) && \
(defined(__linux__) || defined(__FreeBSD__) || defined(_AIX))
#include <altivec.h>
@@ -657,7 +657,7 @@ extern __inline __m128i
#else
#include_next <smmintrin.h>
-#endif /* defined(__ppc64__) &&
+#endif /* defined(__powerpc64__) && \
* (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */
#endif /* SMMINTRIN_H_ */
diff --git a/clang/lib/Headers/ppc_wrappers/tmmintrin.h b/clang/lib/Headers/ppc_wrappers/tmmintrin.h
index 6185ca1e7e71..92f08676d2df 100644
--- a/clang/lib/Headers/ppc_wrappers/tmmintrin.h
+++ b/clang/lib/Headers/ppc_wrappers/tmmintrin.h
@@ -25,7 +25,7 @@
#ifndef TMMINTRIN_H_
#define TMMINTRIN_H_
-#if defined(__ppc64__) && \
+#if defined(__powerpc64__) && \
(defined(__linux__) || defined(__FreeBSD__) || defined(_AIX))
#include <altivec.h>
@@ -447,7 +447,7 @@ extern __inline __m64
#else
#include_next <tmmintrin.h>
-#endif /* defined(__ppc64__) &&
+#endif /* defined(__powerpc64__) && \
* (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */
#endif /* TMMINTRIN_H_ */
diff --git a/clang/lib/Headers/ppc_wrappers/xmmintrin.h b/clang/lib/Headers/ppc_wrappers/xmmintrin.h
index ee0032ca159c..9dd21b65c2f7 100644
--- a/clang/lib/Headers/ppc_wrappers/xmmintrin.h
+++ b/clang/lib/Headers/ppc_wrappers/xmmintrin.h
@@ -35,7 +35,7 @@
#ifndef XMMINTRIN_H_
#define XMMINTRIN_H_
-#if defined(__ppc64__) && \
+#if defined(__powerpc64__) && \
(defined(__linux__) || defined(__FreeBSD__) || defined(_AIX))
/* Define four value permute mask */
@@ -1821,7 +1821,7 @@ extern __inline void
#else
#include_next <xmmintrin.h>
-#endif /* defined(__ppc64__) &&
+#endif /* defined(__powerpc64__) && \
* (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */
#endif /* XMMINTRIN_H_ */
diff --git a/clang/lib/Headers/prfchiintrin.h b/clang/lib/Headers/prfchiintrin.h
new file mode 100644
index 000000000000..36600b25aa1d
--- /dev/null
+++ b/clang/lib/Headers/prfchiintrin.h
@@ -0,0 +1,61 @@
+/*===---- prfchiintrin.h - PREFETCHI intrinsic -----------------------------===
+ *
+ * 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 __PRFCHIINTRIN_H
+#define __PRFCHIINTRIN_H
+
+#ifdef __x86_64__
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS \
+ __attribute__((__always_inline__, __nodebug__, __target__("prefetchi")))
+
+/// Loads an instruction sequence containing the specified memory address into
+/// all level cache.
+///
+/// Note that the effect of this intrinsic is dependent on the processor
+/// implementation.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c PREFETCHIT0 instruction.
+///
+/// \param __P
+/// A pointer specifying the memory address to be prefetched.
+static __inline__ void __DEFAULT_FN_ATTRS
+_m_prefetchit0(volatile const void *__P) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wcast-qual"
+ __builtin_ia32_prefetchi((const void *)__P, 3 /* _MM_HINT_T0 */);
+#pragma clang diagnostic pop
+}
+
+/// Loads an instruction sequence containing the specified memory address into
+/// all but the first-level cache.
+///
+/// Note that the effect of this intrinsic is dependent on the processor
+/// implementation.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c PREFETCHIT1 instruction.
+///
+/// \param __P
+/// A pointer specifying the memory address to be prefetched.
+static __inline__ void __DEFAULT_FN_ATTRS
+_m_prefetchit1(volatile const void *__P) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wcast-qual"
+ __builtin_ia32_prefetchi((const void *)__P, 2 /* _MM_HINT_T1 */);
+#pragma clang diagnostic pop
+}
+#endif /* __x86_64__ */
+#undef __DEFAULT_FN_ATTRS
+
+#endif /* __PRFCHWINTRIN_H */
diff --git a/clang/lib/Headers/raointintrin.h b/clang/lib/Headers/raointintrin.h
new file mode 100644
index 000000000000..d3290eb62abf
--- /dev/null
+++ b/clang/lib/Headers/raointintrin.h
@@ -0,0 +1,203 @@
+/*===----------------------- raointintrin.h - RAOINT ------------------------===
+ *
+ * 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 __X86GPRINTRIN_H
+#error "Never use <raointintrin.h> directly; include <x86gprintrin.h> instead."
+#endif // __X86GPRINTRIN_H
+
+#ifndef __RAOINTINTRIN_H
+#define __RAOINTINTRIN_H
+
+#define __DEFAULT_FN_ATTRS \
+ __attribute__((__always_inline__, __nodebug__, __target__("raoint")))
+
+/// Atomically add a 32-bit value at memory operand \a __A and a 32-bit \a __B,
+/// and store the result to the same memory location.
+///
+/// This intrinsic should be used for contention or weak ordering. It may
+/// result in bad performance for hot data used by single thread only.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c AADD instruction.
+///
+/// \param __A
+/// A pointer to a 32-bit memory location.
+/// \param __B
+/// A 32-bit integer value.
+///
+/// \code{.operation}
+/// MEM[__A+31:__A] := MEM[__A+31:__A] + __B[31:0]
+/// \endcode
+static __inline__ void __DEFAULT_FN_ATTRS _aadd_i32(int *__A, int __B) {
+ __builtin_ia32_aadd32((int *)__A, __B);
+}
+
+/// Atomically and a 32-bit value at memory operand \a __A and a 32-bit \a __B,
+/// and store the result to the same memory location.
+///
+/// This intrinsic should be used for contention or weak ordering. It may
+/// result in bad performance for hot data used by single thread only.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c AAND instruction.
+///
+/// \param __A
+/// A pointer to a 32-bit memory location.
+/// \param __B
+/// A 32-bit integer value.
+///
+/// \code{.operation}
+/// MEM[__A+31:__A] := MEM[__A+31:__A] AND __B[31:0]
+/// \endcode
+static __inline__ void __DEFAULT_FN_ATTRS _aand_i32(int *__A, int __B) {
+ __builtin_ia32_aand32((int *)__A, __B);
+}
+
+/// Atomically or a 32-bit value at memory operand \a __A and a 32-bit \a __B,
+/// and store the result to the same memory location.
+///
+/// This intrinsic should be used for contention or weak ordering. It may
+/// result in bad performance for hot data used by single thread only.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c AOR instruction.
+///
+/// \param __A
+/// A pointer to a 32-bit memory location.
+/// \param __B
+/// A 32-bit integer value.
+///
+/// \code{.operation}
+/// MEM[__A+31:__A] := MEM[__A+31:__A] OR __B[31:0]
+/// \endcode
+static __inline__ void __DEFAULT_FN_ATTRS _aor_i32(int *__A, int __B) {
+ __builtin_ia32_aor32((int *)__A, __B);
+}
+
+/// Atomically xor a 32-bit value at memory operand \a __A and a 32-bit \a __B,
+/// and store the result to the same memory location.
+///
+/// This intrinsic should be used for contention or weak ordering. It may
+/// result in bad performance for hot data used by single thread only.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c AXOR instruction.
+///
+/// \param __A
+/// A pointer to a 32-bit memory location.
+/// \param __B
+/// A 32-bit integer value.
+///
+/// \code{.operation}
+/// MEM[__A+31:__A] := MEM[__A+31:__A] XOR __B[31:0]
+/// \endcode
+static __inline__ void __DEFAULT_FN_ATTRS _axor_i32(int *__A, int __B) {
+ __builtin_ia32_axor32((int *)__A, __B);
+}
+
+#ifdef __x86_64__
+/// Atomically add a 64-bit value at memory operand \a __A and a 64-bit \a __B,
+/// and store the result to the same memory location.
+///
+/// This intrinsic should be used for contention or weak ordering. It may
+/// result in bad performance for hot data used by single thread only.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c AADD instruction.
+///
+/// \param __A
+/// A pointer to a 64-bit memory location.
+/// \param __B
+/// A 64-bit integer value.
+///
+/// \code{.operation}
+/// MEM[__A+63:__A] := MEM[__A+63:__A] + __B[63:0]
+/// \endcode
+static __inline__ void __DEFAULT_FN_ATTRS _aadd_i64(long long *__A,
+ long long __B) {
+ __builtin_ia32_aadd64((long long *)__A, __B);
+}
+
+/// Atomically and a 64-bit value at memory operand \a __A and a 64-bit \a __B,
+/// and store the result to the same memory location.
+///
+/// This intrinsic should be used for contention or weak ordering. It may
+/// result in bad performance for hot data used by single thread only.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c AAND instruction.
+///
+/// \param __A
+/// A pointer to a 64-bit memory location.
+/// \param __B
+/// A 64-bit integer value.
+///
+/// \code{.operation}
+/// MEM[__A+63:__A] := MEM[__A+63:__A] AND __B[63:0]
+/// \endcode
+static __inline__ void __DEFAULT_FN_ATTRS _aand_i64(long long *__A,
+ long long __B) {
+ __builtin_ia32_aand64((long long *)__A, __B);
+}
+
+/// Atomically or a 64-bit value at memory operand \a __A and a 64-bit \a __B,
+/// and store the result to the same memory location.
+///
+/// This intrinsic should be used for contention or weak ordering. It may
+/// result in bad performance for hot data used by single thread only.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c AOR instruction.
+///
+/// \param __A
+/// A pointer to a 64-bit memory location.
+/// \param __B
+/// A 64-bit integer value.
+///
+/// \code{.operation}
+/// MEM[__A+63:__A] := MEM[__A+63:__A] OR __B[63:0]
+/// \endcode
+static __inline__ void __DEFAULT_FN_ATTRS _aor_i64(long long *__A,
+ long long __B) {
+ __builtin_ia32_aor64((long long *)__A, __B);
+}
+
+/// Atomically xor a 64-bit value at memory operand \a __A and a 64-bit \a __B,
+/// and store the result to the same memory location.
+///
+/// This intrinsic should be used for contention or weak ordering. It may
+/// result in bad performance for hot data used by single thread only.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the \c AXOR instruction.
+///
+/// \param __A
+/// A pointer to a 64-bit memory location.
+/// \param __B
+/// A 64-bit integer value.
+///
+/// \code{.operation}
+/// MEM[__A+63:__A] := MEM[__A+63:__A] XOR __B[63:0]
+/// \endcode
+static __inline__ void __DEFAULT_FN_ATTRS _axor_i64(long long *__A,
+ long long __B) {
+ __builtin_ia32_axor64((long long *)__A, __B);
+}
+#endif // __x86_64__
+
+#undef __DEFAULT_FN_ATTRS
+#endif // __RAOINTINTRIN_H
diff --git a/clang/lib/Headers/smmintrin.h b/clang/lib/Headers/smmintrin.h
index 46fb7bcd4e09..2111c24f31a6 100644
--- a/clang/lib/Headers/smmintrin.h
+++ b/clang/lib/Headers/smmintrin.h
@@ -818,7 +818,7 @@ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_max_epu32(__m128i __V1,
/// parameter, is copied to the result.
/// \param N
/// Specifies which bits from operand \a Y will be copied, which bits in the
-/// result they will be be copied to, and which bits in the result will be
+/// result they will be copied to, and which bits in the result will be
/// cleared. The following assignments are made: \n
/// Bits [7:6] specify the bits to copy from operand \a Y: \n
/// 00: Selects bits [31:0] from operand \a Y. \n
diff --git a/clang/lib/Headers/stdarg.h b/clang/lib/Headers/stdarg.h
index 0bc39408c1e5..ba978721f1f3 100644
--- a/clang/lib/Headers/stdarg.h
+++ b/clang/lib/Headers/stdarg.h
@@ -8,13 +8,30 @@
*/
#ifndef __STDARG_H
-#define __STDARG_H
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+typedef __builtin_va_list __gnuc_va_list;
+#endif
+
+#ifdef __need___va_list
+#undef __need___va_list
+#else
+#define __STDARG_H
#ifndef _VA_LIST
typedef __builtin_va_list va_list;
#define _VA_LIST
#endif
+
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
+/* C2x does not require the second parameter for va_start. */
+#define va_start(ap, ...) __builtin_va_start(ap, 0)
+#else
+/* Versions before C2x do require the second parameter. */
#define va_start(ap, param) __builtin_va_start(ap, param)
+#endif
#define va_end(ap) __builtin_va_end(ap)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
@@ -23,13 +40,12 @@ typedef __builtin_va_list va_list;
*/
#define __va_copy(d,s) __builtin_va_copy(d,s)
-#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L || !defined(__STRICT_ANSI__)
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L) || \
+ !defined(__STRICT_ANSI__)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#endif
-#ifndef __GNUC_VA_LIST
-#define __GNUC_VA_LIST 1
-typedef __builtin_va_list __gnuc_va_list;
-#endif
-
#endif /* __STDARG_H */
+
+#endif /* not __STDARG_H */
diff --git a/clang/lib/Headers/stdatomic.h b/clang/lib/Headers/stdatomic.h
index 318c7ca56e41..0f893beea6ca 100644
--- a/clang/lib/Headers/stdatomic.h
+++ b/clang/lib/Headers/stdatomic.h
@@ -15,10 +15,12 @@
*
* Exclude the MSVC path as well as the MSVC header as of the 14.31.30818
* explicitly disallows `stdatomic.h` in the C mode via an `#error`. Fallback
- * to the clang resource header until that is fully supported.
+ * to the clang resource header until that is fully supported. The
+ * `stdatomic.h` header requires C++ 23 or newer.
*/
#if __STDC_HOSTED__ && \
- __has_include_next(<stdatomic.h>) && !(defined(_MSC_VER) && !defined(__cplusplus))
+ __has_include_next(<stdatomic.h>) && \
+ (!defined(_MSC_VER) || (defined(__cplusplus) && __cplusplus >= 202002L))
# include_next <stdatomic.h>
#else
@@ -45,7 +47,8 @@ extern "C" {
/* 7.17.2 Initialization */
#define ATOMIC_VAR_INIT(value) (value)
-#if (__STDC_VERSION__ >= 201710L || __cplusplus >= 202002L) && \
+#if ((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201710L) || \
+ (defined(__cplusplus) && __cplusplus >= 202002L)) && \
!defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS)
/* ATOMIC_VAR_INIT was deprecated in C17 and C++20. */
#pragma clang deprecated(ATOMIC_VAR_INIT)
diff --git a/clang/lib/Headers/stdbool.h b/clang/lib/Headers/stdbool.h
index f0e588532e16..9406aab0ca72 100644
--- a/clang/lib/Headers/stdbool.h
+++ b/clang/lib/Headers/stdbool.h
@@ -12,7 +12,7 @@
#define __bool_true_false_are_defined 1
-#if __STDC_VERSION__ > 201710L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L
/* FIXME: We should be issuing a deprecation warning here, but cannot yet due
* to system headers which include this header file unconditionally.
*/
@@ -23,7 +23,7 @@
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* Define _Bool as a GNU extension. */
#define _Bool bool
-#if __cplusplus < 201103L
+#if defined(__cplusplus) && __cplusplus < 201103L
/* For C++98, define bool, false, true as a GNU extension. */
#define bool bool
#define false false
diff --git a/clang/lib/Headers/stddef.h b/clang/lib/Headers/stddef.h
index a15d21b55317..42815176dcd0 100644
--- a/clang/lib/Headers/stddef.h
+++ b/clang/lib/Headers/stddef.h
@@ -97,8 +97,15 @@ using ::std::nullptr_t;
#undef __need_NULL
#endif /* defined(__need_NULL) */
+/* FIXME: This is using the placeholder dates Clang produces for these macros
+ in C2x mode; switch to the correct values once they've been published. */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
+typedef typeof(nullptr) nullptr_t;
+#endif /* defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L */
+
#if defined(__need_STDDEF_H_misc)
-#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
+ (defined(__cplusplus) && __cplusplus >= 201103L)
#include "__stddef_max_align_t.h"
#endif
#define offsetof(t, d) __builtin_offsetof(t, d)
diff --git a/clang/lib/Headers/stdint.h b/clang/lib/Headers/stdint.h
index 4790c25a2774..a47e91be1889 100644
--- a/clang/lib/Headers/stdint.h
+++ b/clang/lib/Headers/stdint.h
@@ -96,13 +96,21 @@
typedef __INT64_TYPE__ int64_t;
# endif /* __int8_t_defined */
typedef __UINT64_TYPE__ uint64_t;
+# undef __int_least64_t
# define __int_least64_t int64_t
+# undef __uint_least64_t
# define __uint_least64_t uint64_t
+# undef __int_least32_t
# define __int_least32_t int64_t
+# undef __uint_least32_t
# define __uint_least32_t uint64_t
+# undef __int_least16_t
# define __int_least16_t int64_t
+# undef __uint_least16_t
# define __uint_least16_t uint64_t
+# undef __int_least8_t
# define __int_least8_t int64_t
+# undef __uint_least8_t
# define __uint_least8_t uint64_t
#endif /* __INT64_TYPE__ */
@@ -120,11 +128,17 @@ typedef int56_t int_least56_t;
typedef uint56_t uint_least56_t;
typedef int56_t int_fast56_t;
typedef uint56_t uint_fast56_t;
+# undef __int_least32_t
# define __int_least32_t int56_t
+# undef __uint_least32_t
# define __uint_least32_t uint56_t
+# undef __int_least16_t
# define __int_least16_t int56_t
+# undef __uint_least16_t
# define __uint_least16_t uint56_t
+# undef __int_least8_t
# define __int_least8_t int56_t
+# undef __uint_least8_t
# define __uint_least8_t uint56_t
#endif /* __INT56_TYPE__ */
@@ -136,11 +150,17 @@ typedef int48_t int_least48_t;
typedef uint48_t uint_least48_t;
typedef int48_t int_fast48_t;
typedef uint48_t uint_fast48_t;
+# undef __int_least32_t
# define __int_least32_t int48_t
+# undef __uint_least32_t
# define __uint_least32_t uint48_t
+# undef __int_least16_t
# define __int_least16_t int48_t
+# undef __uint_least16_t
# define __uint_least16_t uint48_t
+# undef __int_least8_t
# define __int_least8_t int48_t
+# undef __uint_least8_t
# define __uint_least8_t uint48_t
#endif /* __INT48_TYPE__ */
@@ -152,11 +172,17 @@ typedef int40_t int_least40_t;
typedef uint40_t uint_least40_t;
typedef int40_t int_fast40_t;
typedef uint40_t uint_fast40_t;
+# undef __int_least32_t
# define __int_least32_t int40_t
+# undef __uint_least32_t
# define __uint_least32_t uint40_t
+# undef __int_least16_t
# define __int_least16_t int40_t
+# undef __uint_least16_t
# define __uint_least16_t uint40_t
+# undef __int_least8_t
# define __int_least8_t int40_t
+# undef __uint_least8_t
# define __uint_least8_t uint40_t
#endif /* __INT40_TYPE__ */
@@ -172,11 +198,17 @@ typedef __INT32_TYPE__ int32_t;
typedef __UINT32_TYPE__ uint32_t;
# endif /* __uint32_t_defined */
+# undef __int_least32_t
# define __int_least32_t int32_t
+# undef __uint_least32_t
# define __uint_least32_t uint32_t
+# undef __int_least16_t
# define __int_least16_t int32_t
+# undef __uint_least16_t
# define __uint_least16_t uint32_t
+# undef __int_least8_t
# define __int_least8_t int32_t
+# undef __uint_least8_t
# define __uint_least8_t uint32_t
#endif /* __INT32_TYPE__ */
@@ -194,9 +226,13 @@ typedef int24_t int_least24_t;
typedef uint24_t uint_least24_t;
typedef int24_t int_fast24_t;
typedef uint24_t uint_fast24_t;
+# undef __int_least16_t
# define __int_least16_t int24_t
+# undef __uint_least16_t
# define __uint_least16_t uint24_t
+# undef __int_least8_t
# define __int_least8_t int24_t
+# undef __uint_least8_t
# define __uint_least8_t uint24_t
#endif /* __INT24_TYPE__ */
@@ -205,9 +241,13 @@ typedef uint24_t uint_fast24_t;
typedef __INT16_TYPE__ int16_t;
#endif /* __int8_t_defined */
typedef __UINT16_TYPE__ uint16_t;
+# undef __int_least16_t
# define __int_least16_t int16_t
+# undef __uint_least16_t
# define __uint_least16_t uint16_t
+# undef __int_least8_t
# define __int_least8_t int16_t
+# undef __uint_least8_t
# define __uint_least8_t uint16_t
#endif /* __INT16_TYPE__ */
@@ -224,7 +264,9 @@ typedef __uint_least16_t uint_fast16_t;
typedef __INT8_TYPE__ int8_t;
#endif /* __int8_t_defined */
typedef __UINT8_TYPE__ uint8_t;
+# undef __int_least8_t
# define __int_least8_t int8_t
+# undef __uint_least8_t
# define __uint_least8_t uint8_t
#endif /* __INT8_TYPE__ */
@@ -285,16 +327,15 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#ifdef __INT64_TYPE__
+# undef __int64_c_suffix
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
# ifdef __INT64_C_SUFFIX__
# define __int64_c_suffix __INT64_C_SUFFIX__
# define __int32_c_suffix __INT64_C_SUFFIX__
# define __int16_c_suffix __INT64_C_SUFFIX__
# define __int8_c_suffix __INT64_C_SUFFIX__
-# else
-# undef __int64_c_suffix
-# undef __int32_c_suffix
-# undef __int16_c_suffix
-# undef __int8_c_suffix
# endif /* __INT64_C_SUFFIX__ */
#endif /* __INT64_TYPE__ */
@@ -310,6 +351,9 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#ifdef __INT56_TYPE__
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
# ifdef __INT56_C_SUFFIX__
# define INT56_C(v) __int_c(v, __INT56_C_SUFFIX__)
# define UINT56_C(v) __uint_c(v, __INT56_C_SUFFIX__)
@@ -319,14 +363,14 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# else
# define INT56_C(v) v
# define UINT56_C(v) v ## U
-# undef __int32_c_suffix
-# undef __int16_c_suffix
-# undef __int8_c_suffix
# endif /* __INT56_C_SUFFIX__ */
#endif /* __INT56_TYPE__ */
#ifdef __INT48_TYPE__
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
# ifdef __INT48_C_SUFFIX__
# define INT48_C(v) __int_c(v, __INT48_C_SUFFIX__)
# define UINT48_C(v) __uint_c(v, __INT48_C_SUFFIX__)
@@ -336,14 +380,14 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# else
# define INT48_C(v) v
# define UINT48_C(v) v ## U
-# undef __int32_c_suffix
-# undef __int16_c_suffix
-# undef __int8_c_suffix
# endif /* __INT48_C_SUFFIX__ */
#endif /* __INT48_TYPE__ */
#ifdef __INT40_TYPE__
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
# ifdef __INT40_C_SUFFIX__
# define INT40_C(v) __int_c(v, __INT40_C_SUFFIX__)
# define UINT40_C(v) __uint_c(v, __INT40_C_SUFFIX__)
@@ -353,22 +397,18 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# else
# define INT40_C(v) v
# define UINT40_C(v) v ## U
-# undef __int32_c_suffix
-# undef __int16_c_suffix
-# undef __int8_c_suffix
# endif /* __INT40_C_SUFFIX__ */
#endif /* __INT40_TYPE__ */
#ifdef __INT32_TYPE__
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef __int8_c_suffix
# ifdef __INT32_C_SUFFIX__
# define __int32_c_suffix __INT32_C_SUFFIX__
# define __int16_c_suffix __INT32_C_SUFFIX__
# define __int8_c_suffix __INT32_C_SUFFIX__
-#else
-# undef __int32_c_suffix
-# undef __int16_c_suffix
-# undef __int8_c_suffix
# endif /* __INT32_C_SUFFIX__ */
#endif /* __INT32_TYPE__ */
@@ -384,6 +424,8 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#ifdef __INT24_TYPE__
+# undef __int16_c_suffix
+# undef __int8_c_suffix
# ifdef __INT24_C_SUFFIX__
# define INT24_C(v) __int_c(v, __INT24_C_SUFFIX__)
# define UINT24_C(v) __uint_c(v, __INT24_C_SUFFIX__)
@@ -392,19 +434,16 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# else
# define INT24_C(v) v
# define UINT24_C(v) v ## U
-# undef __int16_c_suffix
-# undef __int8_c_suffix
# endif /* __INT24_C_SUFFIX__ */
#endif /* __INT24_TYPE__ */
#ifdef __INT16_TYPE__
+# undef __int16_c_suffix
+# undef __int8_c_suffix
# ifdef __INT16_C_SUFFIX__
# define __int16_c_suffix __INT16_C_SUFFIX__
# define __int8_c_suffix __INT16_C_SUFFIX__
-#else
-# undef __int16_c_suffix
-# undef __int8_c_suffix
# endif /* __INT16_C_SUFFIX__ */
#endif /* __INT16_TYPE__ */
@@ -420,10 +459,9 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#ifdef __INT8_TYPE__
+# undef __int8_c_suffix
# ifdef __INT8_C_SUFFIX__
# define __int8_c_suffix __INT8_C_SUFFIX__
-#else
-# undef __int8_c_suffix
# endif /* __INT8_C_SUFFIX__ */
#endif /* __INT8_TYPE__ */
@@ -463,27 +501,39 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define UINT64_MAX UINT64_C(18446744073709551615)
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT64_WIDTH 64
# define INT64_WIDTH UINT64_WIDTH
# define __UINT_LEAST64_WIDTH UINT64_WIDTH
+# undef __UINT_LEAST32_WIDTH
# define __UINT_LEAST32_WIDTH UINT64_WIDTH
+# undef __UINT_LEAST16_WIDTH
# define __UINT_LEAST16_WIDTH UINT64_WIDTH
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT64_MAX
#endif /* __STDC_VERSION__ */
# define __INT_LEAST64_MIN INT64_MIN
# define __INT_LEAST64_MAX INT64_MAX
# define __UINT_LEAST64_MAX UINT64_MAX
+# undef __INT_LEAST32_MIN
# define __INT_LEAST32_MIN INT64_MIN
+# undef __INT_LEAST32_MAX
# define __INT_LEAST32_MAX INT64_MAX
+# undef __UINT_LEAST32_MAX
# define __UINT_LEAST32_MAX UINT64_MAX
+# undef __INT_LEAST16_MIN
# define __INT_LEAST16_MIN INT64_MIN
+# undef __INT_LEAST16_MAX
# define __INT_LEAST16_MAX INT64_MAX
+# undef __UINT_LEAST16_MAX
# define __UINT_LEAST16_MAX UINT64_MAX
+# undef __INT_LEAST8_MIN
# define __INT_LEAST8_MIN INT64_MIN
+# undef __INT_LEAST8_MAX
# define __INT_LEAST8_MAX INT64_MAX
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT64_MAX
#endif /* __INT64_TYPE__ */
@@ -497,7 +547,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT_LEAST64_WIDTH __UINT_LEAST64_WIDTH
# define INT_LEAST64_WIDTH UINT_LEAST64_WIDTH
# define UINT_FAST64_WIDTH __UINT_LEAST64_WIDTH
@@ -517,27 +567,39 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST56_MAX INT56_MAX
# define UINT_FAST56_MAX UINT56_MAX
+# undef __INT_LEAST32_MIN
# define __INT_LEAST32_MIN INT56_MIN
+# undef __INT_LEAST32_MAX
# define __INT_LEAST32_MAX INT56_MAX
+# undef __UINT_LEAST32_MAX
# define __UINT_LEAST32_MAX UINT56_MAX
+# undef __INT_LEAST16_MIN
# define __INT_LEAST16_MIN INT56_MIN
+# undef __INT_LEAST16_MAX
# define __INT_LEAST16_MAX INT56_MAX
+# undef __UINT_LEAST16_MAX
# define __UINT_LEAST16_MAX UINT56_MAX
+# undef __INT_LEAST8_MIN
# define __INT_LEAST8_MIN INT56_MIN
+# undef __INT_LEAST8_MAX
# define __INT_LEAST8_MAX INT56_MAX
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT56_MAX
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT56_WIDTH 56
# define INT56_WIDTH UINT56_WIDTH
# define UINT_LEAST56_WIDTH UINT56_WIDTH
# define INT_LEAST56_WIDTH UINT_LEAST56_WIDTH
# define UINT_FAST56_WIDTH UINT56_WIDTH
# define INT_FAST56_WIDTH UINT_FAST56_WIDTH
+# undef __UINT_LEAST32_WIDTH
# define __UINT_LEAST32_WIDTH UINT56_WIDTH
+# undef __UINT_LEAST16_WIDTH
# define __UINT_LEAST16_WIDTH UINT56_WIDTH
+# undef __UINT_LEAST8_WIDTH
# define __UINT_LEAST8_WIDTH UINT56_WIDTH
#endif /* __STDC_VERSION__ */
#endif /* __INT56_TYPE__ */
@@ -554,27 +616,39 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST48_MAX INT48_MAX
# define UINT_FAST48_MAX UINT48_MAX
+# undef __INT_LEAST32_MIN
# define __INT_LEAST32_MIN INT48_MIN
+# undef __INT_LEAST32_MAX
# define __INT_LEAST32_MAX INT48_MAX
+# undef __UINT_LEAST32_MAX
# define __UINT_LEAST32_MAX UINT48_MAX
+# undef __INT_LEAST16_MIN
# define __INT_LEAST16_MIN INT48_MIN
+# undef __INT_LEAST16_MAX
# define __INT_LEAST16_MAX INT48_MAX
+# undef __UINT_LEAST16_MAX
# define __UINT_LEAST16_MAX UINT48_MAX
+# undef __INT_LEAST8_MIN
# define __INT_LEAST8_MIN INT48_MIN
+# undef __INT_LEAST8_MAX
# define __INT_LEAST8_MAX INT48_MAX
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT48_MAX
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
#define UINT48_WIDTH 48
#define INT48_WIDTH UINT48_WIDTH
#define UINT_LEAST48_WIDTH UINT48_WIDTH
#define INT_LEAST48_WIDTH UINT_LEAST48_WIDTH
#define UINT_FAST48_WIDTH UINT48_WIDTH
#define INT_FAST48_WIDTH UINT_FAST48_WIDTH
+#undef __UINT_LEAST32_WIDTH
#define __UINT_LEAST32_WIDTH UINT48_WIDTH
+# undef __UINT_LEAST16_WIDTH
#define __UINT_LEAST16_WIDTH UINT48_WIDTH
+# undef __UINT_LEAST8_WIDTH
#define __UINT_LEAST8_WIDTH UINT48_WIDTH
#endif /* __STDC_VERSION__ */
#endif /* __INT48_TYPE__ */
@@ -591,27 +665,39 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST40_MAX INT40_MAX
# define UINT_FAST40_MAX UINT40_MAX
+# undef __INT_LEAST32_MIN
# define __INT_LEAST32_MIN INT40_MIN
+# undef __INT_LEAST32_MAX
# define __INT_LEAST32_MAX INT40_MAX
+# undef __UINT_LEAST32_MAX
# define __UINT_LEAST32_MAX UINT40_MAX
+# undef __INT_LEAST16_MIN
# define __INT_LEAST16_MIN INT40_MIN
+# undef __INT_LEAST16_MAX
# define __INT_LEAST16_MAX INT40_MAX
+# undef __UINT_LEAST16_MAX
# define __UINT_LEAST16_MAX UINT40_MAX
+# undef __INT_LEAST8_MIN
# define __INT_LEAST8_MIN INT40_MIN
+# undef __INT_LEAST8_MAX
# define __INT_LEAST8_MAX INT40_MAX
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT40_MAX
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT40_WIDTH 40
# define INT40_WIDTH UINT40_WIDTH
# define UINT_LEAST40_WIDTH UINT40_WIDTH
# define INT_LEAST40_WIDTH UINT_LEAST40_WIDTH
# define UINT_FAST40_WIDTH UINT40_WIDTH
# define INT_FAST40_WIDTH UINT_FAST40_WIDTH
+# undef __UINT_LEAST32_WIDTH
# define __UINT_LEAST32_WIDTH UINT40_WIDTH
+# undef __UINT_LEAST16_WIDTH
# define __UINT_LEAST16_WIDTH UINT40_WIDTH
+# undef __UINT_LEAST8_WIDTH
# define __UINT_LEAST8_WIDTH UINT40_WIDTH
#endif /* __STDC_VERSION__ */
#endif /* __INT40_TYPE__ */
@@ -622,23 +708,35 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT32_MIN (-INT32_C(2147483647)-1)
# define UINT32_MAX UINT32_C(4294967295)
+# undef __INT_LEAST32_MIN
# define __INT_LEAST32_MIN INT32_MIN
+# undef __INT_LEAST32_MAX
# define __INT_LEAST32_MAX INT32_MAX
+# undef __UINT_LEAST32_MAX
# define __UINT_LEAST32_MAX UINT32_MAX
+# undef __INT_LEAST16_MIN
# define __INT_LEAST16_MIN INT32_MIN
+# undef __INT_LEAST16_MAX
# define __INT_LEAST16_MAX INT32_MAX
+# undef __UINT_LEAST16_MAX
# define __UINT_LEAST16_MAX UINT32_MAX
+# undef __INT_LEAST8_MIN
# define __INT_LEAST8_MIN INT32_MIN
+# undef __INT_LEAST8_MAX
# define __INT_LEAST8_MAX INT32_MAX
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT32_MAX
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT32_WIDTH 32
# define INT32_WIDTH UINT32_WIDTH
+# undef __UINT_LEAST32_WIDTH
# define __UINT_LEAST32_WIDTH UINT32_WIDTH
+# undef __UINT_LEAST16_WIDTH
# define __UINT_LEAST16_WIDTH UINT32_WIDTH
+# undef __UINT_LEAST8_WIDTH
# define __UINT_LEAST8_WIDTH UINT32_WIDTH
#endif /* __STDC_VERSION__ */
#endif /* __INT32_TYPE__ */
@@ -653,7 +751,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT_LEAST32_WIDTH __UINT_LEAST32_WIDTH
# define INT_LEAST32_WIDTH UINT_LEAST32_WIDTH
# define UINT_FAST32_WIDTH __UINT_LEAST32_WIDTH
@@ -673,23 +771,31 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT_FAST24_MAX INT24_MAX
# define UINT_FAST24_MAX UINT24_MAX
+# undef __INT_LEAST16_MIN
# define __INT_LEAST16_MIN INT24_MIN
+# undef __INT_LEAST16_MAX
# define __INT_LEAST16_MAX INT24_MAX
+# undef __UINT_LEAST16_MAX
# define __UINT_LEAST16_MAX UINT24_MAX
+# undef __INT_LEAST8_MIN
# define __INT_LEAST8_MIN INT24_MIN
+# undef __INT_LEAST8_MAX
# define __INT_LEAST8_MAX INT24_MAX
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT24_MAX
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT24_WIDTH 24
# define INT24_WIDTH UINT24_WIDTH
# define UINT_LEAST24_WIDTH UINT24_WIDTH
# define INT_LEAST24_WIDTH UINT_LEAST24_WIDTH
# define UINT_FAST24_WIDTH UINT24_WIDTH
# define INT_FAST24_WIDTH UINT_FAST24_WIDTH
+# undef __UINT_LEAST16_WIDTH
# define __UINT_LEAST16_WIDTH UINT24_WIDTH
+# undef __UINT_LEAST8_WIDTH
# define __UINT_LEAST8_WIDTH UINT24_WIDTH
#endif /* __STDC_VERSION__ */
#endif /* __INT24_TYPE__ */
@@ -700,19 +806,27 @@ typedef __UINTMAX_TYPE__ uintmax_t;
#define INT16_MIN (-INT16_C(32767)-1)
#define UINT16_MAX UINT16_C(65535)
+# undef __INT_LEAST16_MIN
# define __INT_LEAST16_MIN INT16_MIN
+# undef __INT_LEAST16_MAX
# define __INT_LEAST16_MAX INT16_MAX
+# undef __UINT_LEAST16_MAX
# define __UINT_LEAST16_MAX UINT16_MAX
+# undef __INT_LEAST8_MIN
# define __INT_LEAST8_MIN INT16_MIN
+# undef __INT_LEAST8_MAX
# define __INT_LEAST8_MAX INT16_MAX
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT16_MAX
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT16_WIDTH 16
# define INT16_WIDTH UINT16_WIDTH
+# undef __UINT_LEAST16_WIDTH
# define __UINT_LEAST16_WIDTH UINT16_WIDTH
+# undef __UINT_LEAST8_WIDTH
# define __UINT_LEAST8_WIDTH UINT16_WIDTH
#endif /* __STDC_VERSION__ */
#endif /* __INT16_TYPE__ */
@@ -727,7 +841,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT_LEAST16_WIDTH __UINT_LEAST16_WIDTH
# define INT_LEAST16_WIDTH UINT_LEAST16_WIDTH
# define UINT_FAST16_WIDTH __UINT_LEAST16_WIDTH
@@ -741,15 +855,19 @@ typedef __UINTMAX_TYPE__ uintmax_t;
# define INT8_MIN (-INT8_C(127)-1)
# define UINT8_MAX UINT8_C(255)
+# undef __INT_LEAST8_MIN
# define __INT_LEAST8_MIN INT8_MIN
+# undef __INT_LEAST8_MAX
# define __INT_LEAST8_MAX INT8_MAX
+# undef __UINT_LEAST8_MAX
# define __UINT_LEAST8_MAX UINT8_MAX
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT8_WIDTH 8
# define INT8_WIDTH UINT8_WIDTH
+# undef __UINT_LEAST8_WIDTH
# define __UINT_LEAST8_WIDTH UINT8_WIDTH
#endif /* __STDC_VERSION__ */
#endif /* __INT8_TYPE__ */
@@ -764,7 +882,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
# define UINT_LEAST8_WIDTH __UINT_LEAST8_WIDTH
# define INT_LEAST8_WIDTH UINT_LEAST8_WIDTH
# define UINT_FAST8_WIDTH __UINT_LEAST8_WIDTH
@@ -792,7 +910,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* C2x 7.20.2.4 Width of integer types capable of holding object pointers. */
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
/* NB: The C standard requires that these be the same value, but the compiler
exposes separate internal width macros. */
#define INTPTR_WIDTH __INTPTR_WIDTH__
@@ -813,7 +931,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* C2x 7.20.2.5 Width of greatest-width integer types. */
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
/* NB: The C standard requires that these be the same value, but the compiler
exposes separate internal width macros. */
#define INTMAX_WIDTH __INTMAX_WIDTH__
@@ -849,7 +967,7 @@ typedef __UINTMAX_TYPE__ uintmax_t;
/* C2x 7.20.3.x Width of other integer types. */
/* FIXME: This is using the placeholder dates Clang produces for these macros
in C2x mode; switch to the correct values once they've been published. */
-#if __STDC_VERSION__ >= 202000L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
#define PTRDIFF_WIDTH __PTRDIFF_WIDTH__
#define SIG_ATOMIC_WIDTH __SIG_ATOMIC_WIDTH__
#define SIZE_WIDTH __SIZE_WIDTH__
diff --git a/clang/lib/Headers/stdnoreturn.h b/clang/lib/Headers/stdnoreturn.h
index 7d19fa7b2f2b..967be947627a 100644
--- a/clang/lib/Headers/stdnoreturn.h
+++ b/clang/lib/Headers/stdnoreturn.h
@@ -13,7 +13,7 @@
#define noreturn _Noreturn
#define __noreturn_is_defined 1
-#if __STDC_VERSION__ > 201710L && \
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L) && \
!defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS)
/* The noreturn macro is deprecated in C2x. We do not mark it as such because
including the header file in C2x is also deprecated and we do not want to
diff --git a/clang/lib/Headers/unwind.h b/clang/lib/Headers/unwind.h
index 971a62da0d21..33e1792cd1fb 100644
--- a/clang/lib/Headers/unwind.h
+++ b/clang/lib/Headers/unwind.h
@@ -65,7 +65,8 @@ struct _Unwind_Context;
#if defined(__arm__) && !(defined(__USING_SJLJ_EXCEPTIONS__) || \
defined(__ARM_DWARF_EH__) || defined(__SEH__))
struct _Unwind_Control_Block;
-typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */
+typedef struct _Unwind_Control_Block _Unwind_Control_Block;
+#define _Unwind_Exception _Unwind_Control_Block /* Alias */
#else
struct _Unwind_Exception;
typedef struct _Unwind_Exception _Unwind_Exception;
diff --git a/clang/lib/Headers/velintrin.h b/clang/lib/Headers/velintrin.h
index 69b1fba296d4..3f2bc00442e7 100644
--- a/clang/lib/Headers/velintrin.h
+++ b/clang/lib/Headers/velintrin.h
@@ -13,7 +13,7 @@
typedef double __vr __attribute__((__vector_size__(2048)));
// Vector mask registers
-#if __STDC_VERSION__ >= 199901L
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
// For C99
typedef _Bool __vm __attribute__((ext_vector_type(256)));
typedef _Bool __vm256 __attribute__((ext_vector_type(256)));
diff --git a/clang/lib/Headers/x86gprintrin.h b/clang/lib/Headers/x86gprintrin.h
index 2c2fbb97c9ac..f9a765be4322 100644
--- a/clang/lib/Headers/x86gprintrin.h
+++ b/clang/lib/Headers/x86gprintrin.h
@@ -25,23 +25,35 @@
#include <crc32intrin.h>
#endif
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__PRFCHI__)
+#include <prfchiintrin.h>
+#endif
+
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__RAOINT__)
+#include <raointintrin.h>
+#endif
+
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__CMPCCXADD__)
+#include <cmpccxaddintrin.h>
+#endif
+
#if defined(__i386__)
-#define __FULLBX "ebx"
+#define __SAVE_GPRBX "mov {%%ebx, %%eax |eax, ebx};"
+#define __RESTORE_GPRBX "mov {%%eax, %%ebx |ebx, eax};"
#define __TMPGPR "eax"
#else
// When in 64-bit target, the 32-bit operands generate a 32-bit result,
// zero-extended to a 64-bit result in the destination general-purpose,
// It means "mov x %ebx" will clobber the higher 32 bits of rbx, so we
// should preserve the 64-bit register rbx.
-#define __FULLBX "rbx"
+#define __SAVE_GPRBX "mov {%%rbx, %%rax |rax, rbx};"
+#define __RESTORE_GPRBX "mov {%%rax, %%rbx |rbx, rax};"
#define __TMPGPR "rax"
#endif
-#define __MOVEGPR(__r1, __r2) "mov {%%"__r1 ", %%"__r2 "|"__r2 ", "__r1"};"
-
-#define __SAVE_GPRBX __MOVEGPR(__FULLBX, __TMPGPR)
-#define __RESTORE_GPRBX __MOVEGPR(__TMPGPR, __FULLBX)
-
#define __SSC_MARK(__Tag) \
__asm__ __volatile__( __SAVE_GPRBX \
"mov {%0, %%ebx|ebx, %0}; " \
diff --git a/clang/lib/Headers/xmmintrin.h b/clang/lib/Headers/xmmintrin.h
index 4aa70d6e55a6..80aa2a817f6a 100644
--- a/clang/lib/Headers/xmmintrin.h
+++ b/clang/lib/Headers/xmmintrin.h
@@ -1906,7 +1906,7 @@ _mm_setr_ps(float __z, float __y, float __x, float __w)
static __inline__ __m128 __DEFAULT_FN_ATTRS
_mm_setzero_ps(void)
{
- return __extension__ (__m128){ 0, 0, 0, 0 };
+ return __extension__ (__m128){ 0.0f, 0.0f, 0.0f, 0.0f };
}
/// Stores the upper 64 bits of a 128-bit vector of [4 x float] to a
@@ -3005,7 +3005,6 @@ do { \
#define _m_pavgw _mm_avg_pu16
#define _m_psadbw _mm_sad_pu8
#define _m_ _mm_
-#define _m_ _mm_
#undef __DEFAULT_FN_ATTRS
#undef __DEFAULT_FN_ATTRS_MMX
diff --git a/clang/lib/Index/FileIndexRecord.cpp b/clang/lib/Index/FileIndexRecord.cpp
index d4d1d2f70a9a..f3a5e6b63bbc 100644
--- a/clang/lib/Index/FileIndexRecord.cpp
+++ b/clang/lib/Index/FileIndexRecord.cpp
@@ -45,13 +45,11 @@ void FileIndexRecord::addMacroOccurence(SymbolRoleSet Roles, unsigned Offset,
}
void FileIndexRecord::removeHeaderGuardMacros() {
- auto It =
- std::remove_if(Decls.begin(), Decls.end(), [](const DeclOccurrence &D) {
- if (const auto *MI = D.DeclOrMacro.dyn_cast<const MacroInfo *>())
- return MI->isUsedForHeaderGuard();
- return false;
- });
- Decls.erase(It, Decls.end());
+ llvm::erase_if(Decls, [](const DeclOccurrence &D) {
+ if (const auto *MI = D.DeclOrMacro.dyn_cast<const MacroInfo *>())
+ return MI->isUsedForHeaderGuard();
+ return false;
+ });
}
void FileIndexRecord::print(llvm::raw_ostream &OS, SourceManager &SM) const {
diff --git a/clang/lib/Index/IndexBody.cpp b/clang/lib/Index/IndexBody.cpp
index eb8905a7459c..8b8235c13302 100644
--- a/clang/lib/Index/IndexBody.cpp
+++ b/clang/lib/Index/IndexBody.cpp
@@ -468,7 +468,7 @@ public:
return true;
}
- bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
+ bool VisitOverloadExpr(OverloadExpr *E) {
SmallVector<SymbolRelation, 4> Relations;
SymbolRoleSet Roles = getRolesForRef(E, Relations);
for (auto *D : E->decls())
diff --git a/clang/lib/Index/IndexingContext.h b/clang/lib/Index/IndexingContext.h
index 626d81f003e9..da6ec74b6e74 100644
--- a/clang/lib/Index/IndexingContext.h
+++ b/clang/lib/Index/IndexingContext.h
@@ -68,20 +68,18 @@ public:
static bool isTemplateImplicitInstantiation(const Decl *D);
bool handleDecl(const Decl *D, SymbolRoleSet Roles = SymbolRoleSet(),
- ArrayRef<SymbolRelation> Relations = None);
+ ArrayRef<SymbolRelation> Relations = std::nullopt);
bool handleDecl(const Decl *D, SourceLocation Loc,
SymbolRoleSet Roles = SymbolRoleSet(),
- ArrayRef<SymbolRelation> Relations = None,
+ ArrayRef<SymbolRelation> Relations = std::nullopt,
const DeclContext *DC = nullptr);
bool handleReference(const NamedDecl *D, SourceLocation Loc,
- const NamedDecl *Parent,
- const DeclContext *DC,
+ const NamedDecl *Parent, const DeclContext *DC,
SymbolRoleSet Roles = SymbolRoleSet(),
- ArrayRef<SymbolRelation> Relations = None,
- const Expr *RefE = nullptr,
- const Decl *RefD = nullptr);
+ ArrayRef<SymbolRelation> Relations = std::nullopt,
+ const Expr *RefE = nullptr, const Decl *RefD = nullptr);
void handleMacroDefined(const IdentifierInfo &Name, SourceLocation Loc,
const MacroInfo &MI);
@@ -97,7 +95,7 @@ public:
bool indexDecl(const Decl *D);
void indexTagDecl(const TagDecl *D,
- ArrayRef<SymbolRelation> Relations = None);
+ ArrayRef<SymbolRelation> Relations = std::nullopt);
void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent,
const DeclContext *DC = nullptr,
diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp
index c606d8521bee..d41c54348ac8 100644
--- a/clang/lib/Index/USRGeneration.cpp
+++ b/clang/lib/Index/USRGeneration.cpp
@@ -168,6 +168,8 @@ public:
void VisitTemplateName(TemplateName Name);
void VisitTemplateArgument(const TemplateArgument &Arg);
+ void VisitMSGuidDecl(const MSGuidDecl *D);
+
/// Emit a Decl's name using NamedDecl::printName() and return true if
/// the decl had no name.
bool EmitDeclName(const NamedDecl *D);
@@ -179,10 +181,11 @@ public:
//===----------------------------------------------------------------------===//
bool USRGenerator::EmitDeclName(const NamedDecl *D) {
- const unsigned startSize = Buf.size();
- D->printName(Out);
- const unsigned endSize = Buf.size();
- return startSize == endSize;
+ DeclarationName N = D->getDeclName();
+ if (N.isEmpty())
+ return true;
+ Out << N;
+ return false;
}
bool USRGenerator::ShouldGenerateLocation(const NamedDecl *D) {
@@ -258,7 +261,7 @@ void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
}
// Mangle in type information for the arguments.
- for (auto PD : D->parameters()) {
+ for (auto *PD : D->parameters()) {
Out << '#';
VisitType(PD->getType());
}
@@ -657,120 +660,157 @@ void USRGenerator::VisitType(QualType T) {
}
if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
- unsigned char c = '\0';
switch (BT->getKind()) {
case BuiltinType::Void:
- c = 'v'; break;
+ Out << 'v'; break;
case BuiltinType::Bool:
- c = 'b'; break;
+ Out << 'b'; break;
case BuiltinType::UChar:
- c = 'c'; break;
+ Out << 'c'; break;
case BuiltinType::Char8:
- c = 'u'; break; // FIXME: Check this doesn't collide
+ Out << 'u'; break;
case BuiltinType::Char16:
- c = 'q'; break;
+ Out << 'q'; break;
case BuiltinType::Char32:
- c = 'w'; break;
+ Out << 'w'; break;
case BuiltinType::UShort:
- c = 's'; break;
+ Out << 's'; break;
case BuiltinType::UInt:
- c = 'i'; break;
+ Out << 'i'; break;
case BuiltinType::ULong:
- c = 'l'; break;
+ Out << 'l'; break;
case BuiltinType::ULongLong:
- c = 'k'; break;
+ Out << 'k'; break;
case BuiltinType::UInt128:
- c = 'j'; break;
+ Out << 'j'; break;
case BuiltinType::Char_U:
case BuiltinType::Char_S:
- c = 'C'; break;
+ Out << 'C'; break;
case BuiltinType::SChar:
- c = 'r'; break;
+ Out << 'r'; break;
case BuiltinType::WChar_S:
case BuiltinType::WChar_U:
- c = 'W'; break;
+ Out << 'W'; break;
case BuiltinType::Short:
- c = 'S'; break;
+ Out << 'S'; break;
case BuiltinType::Int:
- c = 'I'; break;
+ Out << 'I'; break;
case BuiltinType::Long:
- c = 'L'; break;
+ Out << 'L'; break;
case BuiltinType::LongLong:
- c = 'K'; break;
+ Out << 'K'; break;
case BuiltinType::Int128:
- c = 'J'; break;
+ Out << 'J'; break;
case BuiltinType::Float16:
case BuiltinType::Half:
- c = 'h'; break;
+ Out << 'h'; break;
case BuiltinType::Float:
- c = 'f'; break;
+ Out << 'f'; break;
case BuiltinType::Double:
- c = 'd'; break;
- case BuiltinType::Ibm128: // FIXME: Need separate tag
+ Out << 'd'; break;
case BuiltinType::LongDouble:
- c = 'D'; break;
+ Out << 'D'; break;
case BuiltinType::Float128:
- c = 'Q'; break;
+ Out << 'Q'; break;
case BuiltinType::NullPtr:
- c = 'n'; break;
-#define BUILTIN_TYPE(Id, SingletonId)
-#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
-#include "clang/AST/BuiltinTypes.def"
- case BuiltinType::Dependent:
+ Out << 'n'; break;
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- case BuiltinType::Id:
+ case BuiltinType::Id: \
+ Out << "@BT@" << #Suffix << "_" << #ImgType; break;
#include "clang/Basic/OpenCLImageTypes.def"
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- case BuiltinType::Id:
+ case BuiltinType::Id: \
+ Out << "@BT@" << #ExtType; break;
#include "clang/Basic/OpenCLExtensionTypes.def"
case BuiltinType::OCLEvent:
+ Out << "@BT@OCLEvent"; break;
case BuiltinType::OCLClkEvent:
+ Out << "@BT@OCLClkEvent"; break;
case BuiltinType::OCLQueue:
+ Out << "@BT@OCLQueue"; break;
case BuiltinType::OCLReserveID:
+ Out << "@BT@OCLReserveID"; break;
case BuiltinType::OCLSampler:
+ Out << "@BT@OCLSampler"; break;
#define SVE_TYPE(Name, Id, SingletonId) \
- case BuiltinType::Id:
+ case BuiltinType::Id: \
+ Out << "@BT@" << Name; break;
#include "clang/Basic/AArch64SVEACLETypes.def"
#define PPC_VECTOR_TYPE(Name, Id, Size) \
- case BuiltinType::Id:
+ case BuiltinType::Id: \
+ Out << "@BT@" << #Name; break;
#include "clang/Basic/PPCTypes.def"
-#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#define RVV_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id: \
+ Out << "@BT@" << Name; break;
#include "clang/Basic/RISCVVTypes.def"
case BuiltinType::ShortAccum:
+ Out << "@BT@ShortAccum"; break;
case BuiltinType::Accum:
+ Out << "@BT@Accum"; break;
case BuiltinType::LongAccum:
+ Out << "@BT@LongAccum"; break;
case BuiltinType::UShortAccum:
+ Out << "@BT@UShortAccum"; break;
case BuiltinType::UAccum:
+ Out << "@BT@UAccum"; break;
case BuiltinType::ULongAccum:
+ Out << "@BT@ULongAccum"; break;
case BuiltinType::ShortFract:
+ Out << "@BT@ShortFract"; break;
case BuiltinType::Fract:
+ Out << "@BT@Fract"; break;
case BuiltinType::LongFract:
+ Out << "@BT@LongFract"; break;
case BuiltinType::UShortFract:
+ Out << "@BT@UShortFract"; break;
case BuiltinType::UFract:
+ Out << "@BT@UFract"; break;
case BuiltinType::ULongFract:
+ Out << "@BT@ULongFract"; break;
case BuiltinType::SatShortAccum:
+ Out << "@BT@SatShortAccum"; break;
case BuiltinType::SatAccum:
+ Out << "@BT@SatAccum"; break;
case BuiltinType::SatLongAccum:
+ Out << "@BT@SatLongAccum"; break;
case BuiltinType::SatUShortAccum:
+ Out << "@BT@SatUShortAccum"; break;
case BuiltinType::SatUAccum:
+ Out << "@BT@SatUAccum"; break;
case BuiltinType::SatULongAccum:
+ Out << "@BT@SatULongAccum"; break;
case BuiltinType::SatShortFract:
+ Out << "@BT@SatShortFract"; break;
case BuiltinType::SatFract:
+ Out << "@BT@SatFract"; break;
case BuiltinType::SatLongFract:
+ Out << "@BT@SatLongFract"; break;
case BuiltinType::SatUShortFract:
+ Out << "@BT@SatUShortFract"; break;
case BuiltinType::SatUFract:
+ Out << "@BT@SatUFract"; break;
case BuiltinType::SatULongFract:
+ Out << "@BT@SatULongFract"; break;
case BuiltinType::BFloat16:
- IgnoreResults = true;
- return;
+ Out << "@BT@__bf16"; break;
+ case BuiltinType::Ibm128:
+ Out << "@BT@__ibm128"; break;
case BuiltinType::ObjCId:
- c = 'o'; break;
+ Out << 'o'; break;
case BuiltinType::ObjCClass:
- c = 'O'; break;
+ Out << 'O'; break;
case BuiltinType::ObjCSel:
- c = 'e'; break;
+ Out << 'e'; break;
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ case BuiltinType::Dependent:
+ // If you're adding a new builtin type, please add its name prefixed
+ // with "@BT@" to `Out` (see cases above).
+ IgnoreResults = true;
+ break;
}
- Out << c;
return;
}
@@ -855,9 +895,9 @@ void USRGenerator::VisitType(QualType T) {
= T->getAs<TemplateSpecializationType>()) {
Out << '>';
VisitTemplateName(Spec->getTemplateName());
- Out << Spec->getNumArgs();
- for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- VisitTemplateArgument(Spec->getArg(I));
+ Out << Spec->template_arguments().size();
+ for (const auto &Arg : Spec->template_arguments())
+ VisitTemplateArgument(Arg);
return;
}
if (const DependentNameType *DNT = T->getAs<DependentNameType>()) {
@@ -963,7 +1003,7 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
case TemplateArgument::TemplateExpansion:
Out << 'P'; // pack expansion of...
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case TemplateArgument::Template:
VisitTemplateName(Arg.getAsTemplateOrTemplatePattern());
break;
@@ -1016,6 +1056,12 @@ void USRGenerator::VisitConceptDecl(const ConceptDecl *D) {
EmitDeclName(D);
}
+void USRGenerator::VisitMSGuidDecl(const MSGuidDecl *D) {
+ VisitDeclContext(D->getDeclContext());
+ Out << "@MG@";
+ D->NamedDecl::printName(Out);
+}
+
//===----------------------------------------------------------------------===//
// USR generation functions.
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp
index 227ab9703dc7..37d230b61f76 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.cpp
+++ b/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -76,6 +76,12 @@ llvm::Error IncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {
return llvm::Error::success();
}
+// Clean up the JIT instance.
+llvm::Error IncrementalExecutor::cleanUp() {
+ // This calls the global dtors of registered modules.
+ return Jit->deinitialize(Jit->getMainJITDylib());
+}
+
llvm::Error IncrementalExecutor::runCtors() const {
return Jit->initialize(Jit->getMainJITDylib());
}
diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h
index 5b0f982b62dd..54d37c76326b 100644
--- a/clang/lib/Interpreter/IncrementalExecutor.h
+++ b/clang/lib/Interpreter/IncrementalExecutor.h
@@ -50,6 +50,7 @@ public:
llvm::Error addModule(PartialTranslationUnit &PTU);
llvm::Error removeModule(PartialTranslationUnit &PTU);
llvm::Error runCtors() const;
+ llvm::Error cleanUp();
llvm::Expected<llvm::JITTargetAddress>
getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const;
llvm::orc::LLJIT *getExecutionEngine() const { return Jit.get(); }
diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp
index db854c4161b4..373e2844b4e4 100644
--- a/clang/lib/Interpreter/IncrementalParser.cpp
+++ b/clang/lib/Interpreter/IncrementalParser.cpp
@@ -59,18 +59,22 @@ public:
CI.getFrontendOpts().ProgramAction);
return Act;
case frontend::ASTDump:
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case frontend::ASTPrint:
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case frontend::ParseSyntaxOnly:
Act = CreateFrontendAction(CI);
break;
case frontend::PluginAction:
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case frontend::EmitAssembly:
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
+ case frontend::EmitBC:
+ [[fallthrough]];
case frontend::EmitObj:
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
+ case frontend::PrintPreprocessedInput:
+ [[fallthrough]];
case frontend::EmitLLVMOnly:
Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
break;
@@ -97,7 +101,6 @@ public:
CompletionConsumer = &CI.getCodeCompletionConsumer();
Preprocessor &PP = CI.getPreprocessor();
- PP.enableIncrementalProcessing();
PP.EnterMainSourceFile();
if (!CI.hasSema())
@@ -170,9 +173,6 @@ IncrementalParser::ParseOrWrapTopLevelDecl() {
Sema::ModuleImportState ImportState;
for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
- // If we got a null return and something *was* parsed, ignore it. This
- // is due to a top-level semicolon, an action override, or a parse error
- // skipping something.
if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
return llvm::make_error<llvm::StringError>("Parsing failed. "
"The consumer rejected a decl",
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 0191ad78581d..a6f5fdc6eefc 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -77,8 +77,7 @@ CreateCI(const llvm::opt::ArgStringList &Argv) {
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
bool Success = CompilerInvocation::CreateFromArgs(
- Clang->getInvocation(), llvm::makeArrayRef(Argv.begin(), Argv.size()),
- Diags);
+ Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
// Infer the builtin include path if unspecified.
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
@@ -138,13 +137,11 @@ IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
// specified. By prepending we allow users to override the default
// action and use other actions in incremental mode.
// FIXME: Print proper driver diagnostics if the driver flags are wrong.
- ClangArgv.insert(ClangArgv.begin() + 1, "-c");
-
- if (!llvm::is_contained(ClangArgv, " -x")) {
- // We do C++ by default; append right after argv[0] if no "-x" given
- ClangArgv.push_back("-x");
- ClangArgv.push_back("c++");
- }
+ // We do C++ by default; append right after argv[0] if no "-x" given
+ ClangArgv.insert(ClangArgv.end(), "-xc++");
+ ClangArgv.insert(ClangArgv.end(), "-Xclang");
+ ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");
+ ClangArgv.insert(ClangArgv.end(), "-c");
// Put a dummy C++ file on to ensure there's at least one compile job for the
// driver to construct.
@@ -161,7 +158,7 @@ IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0],
llvm::sys::getProcessTriple(), Diags);
Driver.setCheckInputsExist(false); // the input comes from mem buffers
- llvm::ArrayRef<const char *> RF = llvm::makeArrayRef(ClangArgv);
+ llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
if (Compilation->getArgs().hasArg(driver::options::OPT_v))
@@ -183,7 +180,14 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
*TSCtx->getContext(), Err);
}
-Interpreter::~Interpreter() {}
+Interpreter::~Interpreter() {
+ if (IncrExecutor) {
+ if (llvm::Error Err = IncrExecutor->cleanUp())
+ llvm::report_fatal_error(
+ llvm::Twine("Failed to clean up IncrementalExecutor: ") +
+ toString(std::move(Err)));
+ }
+}
llvm::Expected<std::unique_ptr<Interpreter>>
Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp
index 567ca81f6ac2..0adbaa36bf7c 100644
--- a/clang/lib/Lex/DependencyDirectivesScanner.cpp
+++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp
@@ -23,6 +23,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
+#include <optional>
using namespace clang;
using namespace clang::dependency_directives_scan;
@@ -81,46 +82,49 @@ struct Scanner {
private:
/// Lexes next token and advances \p First and the \p Lexer.
- LLVM_NODISCARD dependency_directives_scan::Token &
+ [[nodiscard]] dependency_directives_scan::Token &
lexToken(const char *&First, const char *const End);
dependency_directives_scan::Token &lexIncludeFilename(const char *&First,
const char *const End);
+ void skipLine(const char *&First, const char *const End);
+ void skipDirective(StringRef Name, const char *&First, const char *const End);
+
/// Lexes next token and if it is identifier returns its string, otherwise
- /// it skips the current line and returns \p None.
+ /// it skips the current line and returns \p std::nullopt.
///
/// In any case (whatever the token kind) \p First and the \p Lexer will
/// advance beyond the token.
- LLVM_NODISCARD Optional<StringRef>
+ [[nodiscard]] std::optional<StringRef>
tryLexIdentifierOrSkipLine(const char *&First, const char *const End);
/// Used when it is certain that next token is an identifier.
- LLVM_NODISCARD StringRef lexIdentifier(const char *&First,
- const char *const End);
+ [[nodiscard]] StringRef lexIdentifier(const char *&First,
+ const char *const End);
/// Lexes next token and returns true iff it is an identifier that matches \p
/// Id, otherwise it skips the current line and returns false.
///
/// In any case (whatever the token kind) \p First and the \p Lexer will
/// advance beyond the token.
- LLVM_NODISCARD bool isNextIdentifierOrSkipLine(StringRef Id,
- const char *&First,
- const char *const End);
-
- LLVM_NODISCARD bool scanImpl(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 *HashLoc, const char *&First,
+ [[nodiscard]] bool isNextIdentifierOrSkipLine(StringRef Id,
+ const char *&First,
+ const char *const End);
+
+ [[nodiscard]] bool scanImpl(const char *First, const char *const End);
+ [[nodiscard]] bool lexPPLine(const char *&First, const char *const End);
+ [[nodiscard]] bool lexAt(const char *&First, const char *const End);
+ [[nodiscard]] bool lexModule(const char *&First, const char *const End);
+ [[nodiscard]] bool lexDefine(const char *HashLoc, const char *&First,
+ const char *const End);
+ [[nodiscard]] bool lexPragma(const char *&First, const char *const End);
+ [[nodiscard]] bool lexEndif(const char *&First, const char *const End);
+ [[nodiscard]] bool lexDefault(DirectiveKind Kind, 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);
- LLVM_NODISCARD bool lexDefault(DirectiveKind Kind, const char *&First,
- const char *const End);
- LLVM_NODISCARD bool lexModuleDirectiveBody(DirectiveKind Kind,
- const char *&First,
- const char *const End);
+ [[nodiscard]] bool lexModuleDirectiveBody(DirectiveKind Kind,
+ const char *&First,
+ const char *const End);
void lexPPDirectiveBody(const char *&First, const char *const End);
DirectiveWithTokens &pushDirective(DirectiveKind Kind) {
@@ -150,6 +154,7 @@ private:
DiagnosticsEngine *Diags;
SourceLocation InputSourceLoc;
+ const char *LastTokenPtr = nullptr;
/// Keeps track of the tokens for the currently lexed directive. Once a
/// directive is fully lexed and "committed" then the tokens get appended to
/// \p Tokens and \p CurDirToks is cleared for the next directive.
@@ -177,8 +182,8 @@ static void skipOverSpaces(const char *&First, const char *const End) {
++First;
}
-LLVM_NODISCARD static bool isRawStringLiteral(const char *First,
- const char *Current) {
+[[nodiscard]] static bool isRawStringLiteral(const char *First,
+ const char *Current) {
assert(First <= Current);
// Check if we can even back up.
@@ -364,7 +369,7 @@ static bool isQuoteCppDigitSeparator(const char *const Start,
return (Cur + 1) < End && isAsciiIdentifierContinue(*(Cur + 1));
}
-static void skipLine(const char *&First, const char *const End) {
+void Scanner::skipLine(const char *&First, const char *const End) {
for (;;) {
assert(First <= End);
if (First == End)
@@ -379,6 +384,7 @@ static void skipLine(const char *&First, const char *const End) {
// Iterate over strings correctly to avoid comments and newlines.
if (*First == '"' ||
(*First == '\'' && !isQuoteCppDigitSeparator(Start, First, End))) {
+ LastTokenPtr = First;
if (isRawStringLiteral(Start, First))
skipRawString(First, End);
else
@@ -388,6 +394,7 @@ static void skipLine(const char *&First, const char *const End) {
// Iterate over comments correctly.
if (*First != '/' || End - First < 2) {
+ LastTokenPtr = First;
++First;
continue;
}
@@ -399,6 +406,7 @@ static void skipLine(const char *&First, const char *const End) {
}
if (First[1] != '*') {
+ LastTokenPtr = First;
++First;
continue;
}
@@ -416,8 +424,8 @@ static void skipLine(const char *&First, const char *const End) {
}
}
-static void skipDirective(StringRef Name, const char *&First,
- const char *const End) {
+void Scanner::skipDirective(StringRef Name, const char *&First,
+ const char *const End) {
if (llvm::StringSwitch<bool>(Name)
.Case("warning", true)
.Case("error", true)
@@ -517,13 +525,13 @@ void Scanner::lexPPDirectiveBody(const char *&First, const char *const End) {
}
}
-LLVM_NODISCARD Optional<StringRef>
+[[nodiscard]] std::optional<StringRef>
Scanner::tryLexIdentifierOrSkipLine(const char *&First, const char *const End) {
const dependency_directives_scan::Token &Tok = lexToken(First, End);
if (Tok.isNot(tok::raw_identifier)) {
if (!Tok.is(tok::eod))
skipLine(First, End);
- return None;
+ return std::nullopt;
}
bool NeedsCleaning = Tok.Flags & clang::Token::NeedsCleaning;
@@ -548,14 +556,15 @@ Scanner::tryLexIdentifierOrSkipLine(const char *&First, const char *const End) {
}
StringRef Scanner::lexIdentifier(const char *&First, const char *const End) {
- Optional<StringRef> Id = tryLexIdentifierOrSkipLine(First, End);
+ std::optional<StringRef> Id = tryLexIdentifierOrSkipLine(First, End);
assert(Id && "expected identifier token");
- return Id.value();
+ return *Id;
}
bool Scanner::isNextIdentifierOrSkipLine(StringRef Id, const char *&First,
const char *const End) {
- if (Optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(First, End)) {
+ if (std::optional<StringRef> FoundId =
+ tryLexIdentifierOrSkipLine(First, End)) {
if (*FoundId == Id)
return true;
skipLine(First, End);
@@ -581,7 +590,7 @@ bool Scanner::lexModule(const char *&First, const char *const End) {
bool Export = false;
if (Id == "export") {
Export = true;
- Optional<StringRef> NextId = tryLexIdentifierOrSkipLine(First, End);
+ std::optional<StringRef> NextId = tryLexIdentifierOrSkipLine(First, End);
if (!NextId)
return false;
Id = *NextId;
@@ -621,7 +630,7 @@ bool Scanner::lexModule(const char *&First, const char *const End) {
}
bool Scanner::lexPragma(const char *&First, const char *const End) {
- Optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(First, End);
+ std::optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(First, End);
if (!FoundId)
return false;
@@ -710,6 +719,8 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) {
return false;
}
+ LastTokenPtr = First;
+
TheLexer.seek(getOffsetAt(First), /*IsAtStartOfLine*/ true);
auto ScEx1 = make_scope_exit([&]() {
@@ -733,10 +744,18 @@ bool Scanner::lexPPLine(const char *&First, const char *const End) {
// Lex '#'.
const dependency_directives_scan::Token &HashTok = lexToken(First, End);
+ if (HashTok.is(tok::hashhash)) {
+ // A \p tok::hashhash at this location is passed by the preprocessor to the
+ // parser to interpret, like any other token. So for dependency scanning
+ // skip it like a normal token not affecting the preprocessor.
+ skipLine(First, End);
+ assert(First <= End);
+ return false;
+ }
assert(HashTok.is(tok::hash));
(void)HashTok;
- Optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(First, End);
+ std::optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(First, End);
if (!FoundId)
return false;
@@ -803,6 +822,9 @@ bool Scanner::scan(SmallVectorImpl<Directive> &Directives) {
if (!Error) {
// Add an EOF on success.
+ if (LastTokenPtr &&
+ (Tokens.empty() || LastTokenPtr > Input.begin() + Tokens.back().Offset))
+ pushDirective(tokens_present_before_eof);
pushDirective(pp_eof);
}
@@ -851,7 +873,9 @@ void clang::printDependencyDirectivesAsSource(
};
for (const dependency_directives_scan::Directive &Directive : Directives) {
- Optional<tok::TokenKind> PrevTokenKind;
+ if (Directive.Kind == tokens_present_before_eof)
+ OS << "<TokBeforeEOF>";
+ std::optional<tok::TokenKind> PrevTokenKind;
for (const dependency_directives_scan::Token &Tok : Directive.Tokens) {
if (PrevTokenKind && needsSpaceSeparator(*PrevTokenKind, Tok))
OS << ' ';
diff --git a/clang/lib/Lex/HeaderMap.cpp b/clang/lib/Lex/HeaderMap.cpp
index 0001fc348eda..bb50a4eef65c 100644
--- a/clang/lib/Lex/HeaderMap.cpp
+++ b/clang/lib/Lex/HeaderMap.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/Debug.h"
#include <cstring>
#include <memory>
+#include <optional>
using namespace clang;
/// HashHMapKey - This is the 'well known' hash function required by the file
@@ -145,13 +146,13 @@ HMapBucket HeaderMapImpl::getBucket(unsigned BucketNo) const {
return Result;
}
-Optional<StringRef> HeaderMapImpl::getString(unsigned StrTabIdx) const {
+std::optional<StringRef> HeaderMapImpl::getString(unsigned StrTabIdx) const {
// Add the start of the string table to the idx.
StrTabIdx += getEndianAdjustedWord(getHeader().StringsOffset);
// Check for invalid index.
if (StrTabIdx >= FileBuffer->getBufferSize())
- return None;
+ return std::nullopt;
const char *Data = FileBuffer->getBufferStart() + StrTabIdx;
unsigned MaxLen = FileBuffer->getBufferSize() - StrTabIdx;
@@ -159,7 +160,7 @@ Optional<StringRef> HeaderMapImpl::getString(unsigned StrTabIdx) const {
// Check whether the buffer is null-terminated.
if (Len == MaxLen && Data[Len - 1])
- return None;
+ return std::nullopt;
return StringRef(Data, Len);
}
@@ -177,7 +178,7 @@ LLVM_DUMP_METHOD void HeaderMapImpl::dump() const {
<< ", " << getEndianAdjustedWord(Hdr.NumEntries) << "\n";
auto getStringOrInvalid = [this](unsigned Id) -> StringRef {
- if (Optional<StringRef> S = getString(Id))
+ if (std::optional<StringRef> S = getString(Id))
return *S;
return "<invalid>";
};
@@ -208,7 +209,7 @@ StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
if (B.Key == HMAP_EmptyBucketKey) return StringRef(); // Hash miss.
// See if the key matches. If not, probe on.
- Optional<StringRef> Key = getString(B.Key);
+ std::optional<StringRef> Key = getString(B.Key);
if (LLVM_UNLIKELY(!Key))
continue;
if (!Filename.equals_insensitive(*Key))
@@ -216,8 +217,8 @@ StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
// If so, we have a match in the hash table. Construct the destination
// path.
- Optional<StringRef> Prefix = getString(B.Prefix);
- Optional<StringRef> Suffix = getString(B.Suffix);
+ std::optional<StringRef> Prefix = getString(B.Prefix);
+ std::optional<StringRef> Suffix = getString(B.Suffix);
DestPath.clear();
if (LLVM_LIKELY(Prefix && Suffix)) {
@@ -240,9 +241,9 @@ StringRef HeaderMapImpl::reverseLookupFilename(StringRef DestPath) const {
if (B.Key == HMAP_EmptyBucketKey)
continue;
- Optional<StringRef> Key = getString(B.Key);
- Optional<StringRef> Prefix = getString(B.Prefix);
- Optional<StringRef> Suffix = getString(B.Suffix);
+ std::optional<StringRef> Key = getString(B.Key);
+ std::optional<StringRef> Prefix = getString(B.Prefix);
+ std::optional<StringRef> Suffix = getString(B.Suffix);
if (LLVM_LIKELY(Key && Prefix && Suffix)) {
SmallVector<char, 1024> Buf;
Buf.append(Prefix->begin(), Prefix->end());
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 60fd42bc1127..074c147ba3c5 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -116,6 +116,7 @@ void HeaderSearch::SetSearchPaths(
NoCurDirSearch = noCurDirSearch;
SearchDirToHSEntry = std::move(searchDirToHSEntry);
//LookupFileCache.clear();
+ indexInitialHeaderMaps();
}
void HeaderSearch::AddSearchPath(const DirectoryLookup &dir, bool isAngled) {
@@ -170,11 +171,11 @@ void HeaderSearch::getHeaderMapFileNames(
}
std::string HeaderSearch::getCachedModuleFileName(Module *Module) {
- const FileEntry *ModuleMap =
+ OptionalFileEntryRef ModuleMap =
getModuleMap().getModuleMapFileForUniquing(Module);
// The ModuleMap maybe a nullptr, when we load a cached C++ module without
// *.modulemap file. In this case, just return an empty string.
- if (ModuleMap == nullptr)
+ if (!ModuleMap)
return {};
return getCachedModuleFileName(Module->Name, ModuleMap->getName());
}
@@ -211,7 +212,7 @@ std::string HeaderSearch::getPrebuiltModuleFileName(StringRef ModuleName,
}
std::string HeaderSearch::getPrebuiltImplicitModuleFileName(Module *Module) {
- const FileEntry *ModuleMap =
+ OptionalFileEntryRef ModuleMap =
getModuleMap().getModuleMapFileForUniquing(Module);
StringRef ModuleName = Module->Name;
StringRef ModuleMapPath = ModuleMap->getName();
@@ -255,18 +256,11 @@ std::string HeaderSearch::getCachedModuleFileNameImpl(StringRef ModuleName,
//
// To avoid false-negatives, we form as canonical a path as we can, and map
// to lower-case in case we're on a case-insensitive file system.
- std::string Parent =
- std::string(llvm::sys::path::parent_path(ModuleMapPath));
- if (Parent.empty())
- Parent = ".";
- auto Dir = FileMgr.getDirectory(Parent);
- if (!Dir)
+ SmallString<128> CanonicalPath(ModuleMapPath);
+ if (getModuleMap().canonicalizeModuleMapPath(CanonicalPath))
return {};
- auto DirName = FileMgr.getCanonicalName(*Dir);
- auto FileName = llvm::sys::path::filename(ModuleMapPath);
- llvm::hash_code Hash =
- llvm::hash_combine(DirName.lower(), FileName.lower());
+ llvm::hash_code Hash = llvm::hash_combine(CanonicalPath.str().lower());
SmallString<128> HashStr;
llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
@@ -311,7 +305,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
// Look through the various header search paths to load any available module
// maps, searching for a module map that describes this module.
- for (DirectoryLookup Dir : search_dir_range()) {
+ for (DirectoryLookup &Dir : search_dir_range()) {
if (Dir.isFramework()) {
// Search for or infer a module map for a framework. Here we use
// SearchName rather than ModuleName, to permit finding private modules
@@ -335,7 +329,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
continue;
bool IsSystem = Dir.isSystemHeaderDirectory();
- // Only returns None if not a normal directory, which we just checked
+ // Only returns std::nullopt if not a normal directory, which we just
+ // checked
DirectoryEntryRef NormalDir = *Dir.getDirRef();
// Search for a module map file in this directory.
if (loadModuleMapFile(NormalDir, IsSystem,
@@ -379,6 +374,31 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
return Module;
}
+void HeaderSearch::indexInitialHeaderMaps() {
+ llvm::StringMap<unsigned, llvm::BumpPtrAllocator> Index(SearchDirs.size());
+
+ // Iterate over all filename keys and associate them with the index i.
+ unsigned i = 0;
+ for (; i != SearchDirs.size(); ++i) {
+ auto &Dir = SearchDirs[i];
+
+ // We're concerned with only the initial contiguous run of header
+ // maps within SearchDirs, which can be 99% of SearchDirs when
+ // SearchDirs.size() is ~10000.
+ if (!Dir.isHeaderMap())
+ break;
+
+ // Give earlier keys precedence over identical later keys.
+ auto Callback = [&](StringRef Filename) {
+ Index.try_emplace(Filename.lower(), i);
+ };
+ Dir.getHeaderMap()->forEachKey(Callback);
+ }
+
+ SearchDirHeaderMapIndex = std::move(Index);
+ FirstNonHeaderMapSearchDirIdx = i;
+}
+
//===----------------------------------------------------------------------===//
// File lookup within a DirectoryLookup scope
//===----------------------------------------------------------------------===//
@@ -395,13 +415,14 @@ StringRef DirectoryLookup::getName() const {
return getHeaderMap()->getFileName();
}
-Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
+OptionalFileEntryRef HeaderSearch::getFileAndSuggestModule(
StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
bool IsSystemHeaderDir, Module *RequestingModule,
- ModuleMap::KnownHeader *SuggestedModule) {
+ ModuleMap::KnownHeader *SuggestedModule, bool OpenFile /*=true*/,
+ bool CacheFailures /*=true*/) {
// If we have a module map that might map this header, load it and
// check whether we'll have a suggestion for a module.
- auto File = getFileMgr().getFileRef(FileName, /*OpenFile=*/true);
+ auto File = getFileMgr().getFileRef(FileName, OpenFile, CacheFailures);
if (!File) {
// For rare, surprising errors (e.g. "out of file handles"), diag the EC
// message.
@@ -412,26 +433,27 @@ Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
Diags.Report(IncludeLoc, diag::err_cannot_open_file)
<< FileName << EC.message();
}
- return None;
+ return std::nullopt;
}
// If there is a module that corresponds to this header, suggest it.
if (!findUsableModuleForHeader(
&File->getFileEntry(), Dir ? Dir : File->getFileEntry().getDir(),
RequestingModule, SuggestedModule, IsSystemHeaderDir))
- return None;
+ return std::nullopt;
return *File;
}
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
-Optional<FileEntryRef> DirectoryLookup::LookupFile(
+OptionalFileEntryRef 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 {
+ bool &IsInHeaderMap, SmallVectorImpl<char> &MappedName,
+ bool OpenFile) const {
InUserSpecifiedSystemFramework = false;
IsInHeaderMap = false;
MappedName.clear();
@@ -451,9 +473,9 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
RelativePath->append(Filename.begin(), Filename.end());
}
- return HS.getFileAndSuggestModule(TmpDir, IncludeLoc, getDir(),
- isSystemHeaderDirectory(),
- RequestingModule, SuggestedModule);
+ return HS.getFileAndSuggestModule(
+ TmpDir, IncludeLoc, getDir(), isSystemHeaderDirectory(),
+ RequestingModule, SuggestedModule, OpenFile);
}
if (isFramework())
@@ -466,7 +488,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
SmallString<1024> Path;
StringRef Dest = HM->lookupFilename(Filename, Path);
if (Dest.empty())
- return None;
+ return std::nullopt;
IsInHeaderMap = true;
@@ -491,7 +513,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
Dest = HM->lookupFilename(Filename, Path);
}
- if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest)) {
+ if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest, OpenFile)) {
FixupSearchPath();
return *Res;
}
@@ -501,7 +523,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
// function as part of the regular logic that applies to include search paths.
// The case where the target file **does not exist** is handled here:
HS.noteLookupUsage(HS.searchDirIdx(*this), IncludeLoc);
- return None;
+ return std::nullopt;
}
/// Given a framework directory, find the top-most framework directory.
@@ -510,7 +532,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
/// \param DirName The name of the framework directory.
/// \param SubmodulePath Will be populated with the submodule path from the
/// returned top-level module to the originally named framework.
-static Optional<DirectoryEntryRef>
+static OptionalDirectoryEntryRef
getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
SmallVectorImpl<std::string> &SubmodulePath) {
assert(llvm::sys::path::extension(DirName) == ".framework" &&
@@ -564,7 +586,7 @@ static bool needModuleLookup(Module *RequestingModule,
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
-Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
+OptionalFileEntryRef DirectoryLookup::DoFrameworkLookup(
StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule,
@@ -574,7 +596,7 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
// Framework names must have a '/' in the filename.
size_t SlashPos = Filename.find('/');
if (SlashPos == StringRef::npos)
- return None;
+ return std::nullopt;
// Find out if this is the home for the specified framework, by checking
// HeaderSearch. Possible answers are yes/no and unknown.
@@ -583,7 +605,7 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
// If it is known and in some other directory, fail.
if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDirRef())
- return None;
+ return std::nullopt;
// Otherwise, construct the path to this framework dir.
@@ -607,7 +629,7 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
// If the framework dir doesn't exist, we fail.
auto Dir = FileMgr.getDirectory(FrameworkName);
if (!Dir)
- return None;
+ return std::nullopt;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
@@ -690,17 +712,17 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
if (!HS.findUsableModuleForFrameworkHeader(
&File->getFileEntry(), FrameworkPath, RequestingModule,
SuggestedModule, IsSystem))
- return None;
+ return std::nullopt;
} else {
if (!HS.findUsableModuleForHeader(&File->getFileEntry(), getDir(),
RequestingModule, SuggestedModule,
IsSystem))
- return None;
+ return std::nullopt;
}
}
if (File)
return *File;
- return None;
+ return std::nullopt;
}
void HeaderSearch::cacheLookupSuccess(LookupFileCacheInfo &CacheLookup,
@@ -833,14 +855,14 @@ 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.
-Optional<FileEntryRef> HeaderSearch::LookupFile(
+OptionalFileEntryRef HeaderSearch::LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
ConstSearchDirIterator FromDir, ConstSearchDirIterator *CurDirArg,
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
bool *IsMapped, bool *IsFrameworkFound, bool SkipCache,
- bool BuildSystemModule) {
+ bool BuildSystemModule, bool OpenFile, bool CacheFailures) {
ConstSearchDirIterator CurDirLocal = nullptr;
ConstSearchDirIterator &CurDir = CurDirArg ? *CurDirArg : CurDirLocal;
@@ -859,7 +881,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
// If this was an #include_next "/absolute/file", fail.
if (FromDir)
- return None;
+ return std::nullopt;
if (SearchPath)
SearchPath->clear();
@@ -869,13 +891,14 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
}
// Otherwise, just return the file.
return getFileAndSuggestModule(Filename, IncludeLoc, nullptr,
- /*IsSystemHeaderDir*/false,
- RequestingModule, SuggestedModule);
+ /*IsSystemHeaderDir*/ false,
+ RequestingModule, SuggestedModule, OpenFile,
+ CacheFailures);
}
// This is the header that MSVC's header search would have found.
ModuleMap::KnownHeader MSSuggestedModule;
- Optional<FileEntryRef> MSFE;
+ OptionalFileEntryRef MSFE;
// 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
@@ -904,7 +927,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
bool IncluderIsSystemHeader =
Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
BuildSystemModule;
- if (Optional<FileEntryRef> FE = getFileAndSuggestModule(
+ if (OptionalFileEntryRef FE = getFileAndSuggestModule(
TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
RequestingModule, SuggestedModule)) {
if (!Includer) {
@@ -981,24 +1004,37 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
ConstSearchDirIterator NextIt = std::next(It);
- // If the entry has been previously looked up, the first value will be
- // non-zero. If the value is equal to i (the start point of our search), then
- // this is a matching hit.
- if (!SkipCache && CacheLookup.StartIt == NextIt) {
- // Skip querying potentially lots of directories for this lookup.
- if (CacheLookup.HitIt)
- It = CacheLookup.HitIt;
- if (CacheLookup.MappedName) {
- Filename = CacheLookup.MappedName;
- if (IsMapped)
- *IsMapped = true;
+ if (!SkipCache) {
+ if (CacheLookup.StartIt == NextIt) {
+ // HIT: Skip querying potentially lots of directories for this lookup.
+ if (CacheLookup.HitIt)
+ It = CacheLookup.HitIt;
+ if (CacheLookup.MappedName) {
+ Filename = CacheLookup.MappedName;
+ if (IsMapped)
+ *IsMapped = true;
+ }
+ } else {
+ // MISS: This is the first query, or the previous query didn't match
+ // our search start. We will fill in our found location below, so prime
+ // the start point value.
+ CacheLookup.reset(/*NewStartIt=*/NextIt);
+
+ if (It == search_dir_begin() && FirstNonHeaderMapSearchDirIdx > 0) {
+ // Handle cold misses of user includes in the presence of many header
+ // maps. We avoid searching perhaps thousands of header maps by
+ // jumping directly to the correct one or jumping beyond all of them.
+ auto Iter = SearchDirHeaderMapIndex.find(Filename.lower());
+ if (Iter == SearchDirHeaderMapIndex.end())
+ // Not in index => Skip to first SearchDir after initial header maps
+ It = search_dir_nth(FirstNonHeaderMapSearchDirIdx);
+ else
+ // In index => Start with a specific header map
+ It = search_dir_nth(Iter->second);
+ }
}
- } else {
- // Otherwise, this is the first query, or the previous query didn't match
- // our search start. We will fill in our found location below, so prime the
- // start point value.
+ } else
CacheLookup.reset(/*NewStartIt=*/NextIt);
- }
SmallString<64> MappedName;
@@ -1007,10 +1043,10 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
bool InUserSpecifiedSystemFramework = false;
bool IsInHeaderMap = false;
bool IsFrameworkFoundInDir = false;
- Optional<FileEntryRef> File = It->LookupFile(
+ OptionalFileEntryRef File = It->LookupFile(
Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir,
- IsInHeaderMap, MappedName);
+ IsInHeaderMap, MappedName, OpenFile);
if (!MappedName.empty()) {
assert(IsInHeaderMap && "MappedName should come from a header map");
CacheLookup.MappedName =
@@ -1102,7 +1138,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
ScratchFilename += '/';
ScratchFilename += Filename;
- Optional<FileEntryRef> File = LookupFile(
+ OptionalFileEntryRef File = LookupFile(
ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, &CurDir,
Includers.front(), SearchPath, RelativePath, RequestingModule,
SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);
@@ -1131,7 +1167,7 @@ Optional<FileEntryRef> HeaderSearch::LookupFile(
// Otherwise, didn't find it. Remember we didn't find this.
CacheLookup.HitIt = search_dir_end();
- return None;
+ return std::nullopt;
}
/// LookupSubframeworkHeader - Look up a subframework for the specified
@@ -1139,7 +1175,7 @@ Optional<FileEntryRef> 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.
-Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
+OptionalFileEntryRef HeaderSearch::LookupSubframeworkHeader(
StringRef Filename, const FileEntry *ContextFileEnt,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
@@ -1149,7 +1185,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
// FIXME: Should we permit '\' on Windows?
size_t SlashPos = Filename.find('/');
if (SlashPos == StringRef::npos)
- return None;
+ return std::nullopt;
// Look up the base framework name of the ContextFileEnt.
StringRef ContextName = ContextFileEnt->getName();
@@ -1160,7 +1196,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
if (FrameworkPos == StringRef::npos ||
(ContextName[FrameworkPos + DotFrameworkLen] != '/' &&
ContextName[FrameworkPos + DotFrameworkLen] != '\\'))
- return None;
+ return std::nullopt;
SmallString<1024> FrameworkName(ContextName.data(), ContextName.data() +
FrameworkPos +
@@ -1180,7 +1216,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
CacheLookup.first().size() == FrameworkName.size() &&
memcmp(CacheLookup.first().data(), &FrameworkName[0],
CacheLookup.first().size()) != 0)
- return None;
+ return std::nullopt;
// Cache subframework.
if (!CacheLookup.second.Directory) {
@@ -1189,7 +1225,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
// If the framework dir doesn't exist, we fail.
auto Dir = FileMgr.getOptionalDirectoryRef(FrameworkName);
if (!Dir)
- return None;
+ return std::nullopt;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
@@ -1227,7 +1263,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
File = FileMgr.getOptionalFileRef(HeadersFilename, /*OpenFile=*/true);
if (!File)
- return None;
+ return std::nullopt;
}
// This file is a system header or C++ unfriendly if the old file is.
@@ -1242,7 +1278,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
if (!findUsableModuleForFrameworkHeader(&File->getFileEntry(), FrameworkName,
RequestingModule, SuggestedModule,
/*IsSystem*/ false))
- return None;
+ return std::nullopt;
return *File;
}
@@ -1348,7 +1384,7 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE,
ModuleMap::ModuleHeaderRole Role,
bool isCompilingModuleHeader) {
- bool isModularHeader = !(Role & ModuleMap::TextualHeader);
+ bool isModularHeader = ModuleMap::isModular(Role);
// Don't mark the file info as non-external if there's nothing to change.
if (!isCompilingModuleHeader) {
@@ -1519,14 +1555,14 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
}
ModuleMap::KnownHeader
-HeaderSearch::findModuleForHeader(const FileEntry *File,
- bool AllowTextual) const {
+HeaderSearch::findModuleForHeader(const FileEntry *File, bool AllowTextual,
+ bool AllowExcluded) const {
if (ExternalSource) {
// Make sure the external source has handled header info about this file,
// which includes whether the file is part of a module.
(void)getExistingFileInfo(File);
}
- return ModMap.findModuleForHeader(File, AllowTextual);
+ return ModMap.findModuleForHeader(File, AllowTextual, AllowExcluded);
}
ArrayRef<ModuleMap::KnownHeader>
@@ -1560,6 +1596,8 @@ static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
*SuggestedModule = ModuleMap::KnownHeader();
return true;
}
+ // TODO: Add this module (or just its module map file) into something like
+ // `RequestingModule->AffectingClangModules`.
return false;
}
}
@@ -1590,7 +1628,7 @@ bool HeaderSearch::findUsableModuleForFrameworkHeader(
if (needModuleLookup(RequestingModule, SuggestedModule)) {
// Find the top-level framework based on this framework.
SmallVector<std::string, 4> SubmodulePath;
- Optional<DirectoryEntryRef> TopFrameworkDir =
+ OptionalDirectoryEntryRef TopFrameworkDir =
::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
assert(TopFrameworkDir && "Could not find the top-most framework dir");
@@ -1630,7 +1668,7 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem,
StringRef OriginalModuleMapFile) {
// Find the directory for the module. For frameworks, that may require going
// up from the 'Modules' directory.
- Optional<DirectoryEntryRef> Dir;
+ OptionalDirectoryEntryRef Dir;
if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd) {
Dir = FileMgr.getOptionalDirectoryRef(".");
} else {
@@ -1891,32 +1929,28 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics(
llvm::StringRef File, llvm::StringRef WorkingDir, llvm::StringRef MainFile,
bool *IsSystem) {
using namespace llvm::sys;
+
+ llvm::SmallString<32> FilePath = File;
+ // remove_dots switches to backslashes on windows as a side-effect!
+ // We always want to suggest forward slashes for includes.
+ // (not remove_dots(..., posix) as that misparses windows paths).
+ path::remove_dots(FilePath, /*remove_dot_dot=*/true);
+ path::native(FilePath, path::Style::posix);
+ File = FilePath;
unsigned BestPrefixLength = 0;
// Checks whether `Dir` is a strict path prefix of `File`. If so and that's
// the longest prefix we've seen so for it, returns true and updates the
// `BestPrefixLength` accordingly.
- auto CheckDir = [&](llvm::StringRef Dir) -> bool {
- llvm::SmallString<32> DirPath(Dir.begin(), Dir.end());
+ auto CheckDir = [&](llvm::SmallString<32> Dir) -> bool {
if (!WorkingDir.empty() && !path::is_absolute(Dir))
- fs::make_absolute(WorkingDir, DirPath);
- path::remove_dots(DirPath, /*remove_dot_dot=*/true);
- Dir = DirPath;
+ fs::make_absolute(WorkingDir, Dir);
+ path::remove_dots(Dir, /*remove_dot_dot=*/true);
for (auto NI = path::begin(File), NE = path::end(File),
DI = path::begin(Dir), DE = path::end(Dir);
- /*termination condition in loop*/; ++NI, ++DI) {
- // '.' components in File are ignored.
- while (NI != NE && *NI == ".")
- ++NI;
- if (NI == NE)
- break;
-
- // '.' components in Dir are ignored.
- while (DI != DE && *DI == ".")
- ++DI;
+ NI != NE; ++NI, ++DI) {
if (DI == DE) {
- // Dir is a prefix of File, up to '.' components and choice of path
- // separators.
+ // Dir is a prefix of File, up to choice of path separators.
unsigned PrefixLength = NI - path::begin(File);
if (PrefixLength > BestPrefixLength) {
BestPrefixLength = PrefixLength;
diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp
index 158b5667151f..d4465565718e 100644
--- a/clang/lib/Lex/InitHeaderSearch.cpp
+++ b/clang/lib/Lex/InitHeaderSearch.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace clang::frontend;
@@ -35,16 +36,16 @@ namespace {
struct DirectoryLookupInfo {
IncludeDirGroup Group;
DirectoryLookup Lookup;
- Optional<unsigned> UserEntryIdx;
+ std::optional<unsigned> UserEntryIdx;
DirectoryLookupInfo(IncludeDirGroup Group, DirectoryLookup Lookup,
- Optional<unsigned> UserEntryIdx)
+ std::optional<unsigned> UserEntryIdx)
: Group(Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {}
};
-/// InitHeaderSearch - This class makes it easier to set the search paths of
-/// a HeaderSearch object. InitHeaderSearch stores several search path lists
-/// internally, which can be sent to a HeaderSearch object in one swoop.
+/// This class makes it easier to set the search paths of a HeaderSearch object.
+/// InitHeaderSearch stores several search path lists internally, which can be
+/// sent to a HeaderSearch object in one swoop.
class InitHeaderSearch {
std::vector<DirectoryLookupInfo> IncludePath;
std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes;
@@ -58,56 +59,54 @@ public:
: Headers(HS), Verbose(verbose), IncludeSysroot(std::string(sysroot)),
HasSysroot(!(sysroot.empty() || sysroot == "/")) {}
- /// AddPath - Add the specified path to the specified group list, prefixing
- /// the sysroot if used.
+ /// Add the specified path to the specified group list, prefixing the sysroot
+ /// if used.
/// Returns true if the path exists, false if it was ignored.
bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework,
- Optional<unsigned> UserEntryIdx = None);
+ std::optional<unsigned> UserEntryIdx = std::nullopt);
- /// AddUnmappedPath - Add the specified path to the specified group list,
- /// without performing any sysroot remapping.
+ /// Add the specified path to the specified group list, without performing any
+ /// sysroot remapping.
/// Returns true if the path exists, false if it was ignored.
bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
bool isFramework,
- Optional<unsigned> UserEntryIdx = None);
+ std::optional<unsigned> UserEntryIdx = std::nullopt);
- /// AddSystemHeaderPrefix - Add the specified prefix to the system header
- /// prefix list.
+ /// Add the specified prefix to the system header prefix list.
void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) {
SystemHeaderPrefixes.emplace_back(std::string(Prefix), IsSystemHeader);
}
- /// AddGnuCPlusPlusIncludePaths - Add the necessary paths to support a gnu
- /// libstdc++.
+ /// Add the necessary paths to support a gnu libstdc++.
/// Returns true if the \p Base path was found, false if it does not exist.
bool AddGnuCPlusPlusIncludePaths(StringRef Base, StringRef ArchDir,
StringRef Dir32, StringRef Dir64,
const llvm::Triple &triple);
- /// AddMinGWCPlusPlusIncludePaths - Add the necessary paths to support a MinGW
- /// libstdc++.
+ /// Add the necessary paths to support a MinGW libstdc++.
void AddMinGWCPlusPlusIncludePaths(StringRef Base,
StringRef Arch,
StringRef Version);
- // AddDefaultCIncludePaths - Add paths that should always be searched.
+ /// Add paths that should always be searched.
void AddDefaultCIncludePaths(const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts);
- // AddDefaultCPlusPlusIncludePaths - Add paths that should be searched when
- // compiling c++.
+ /// Add paths that should be searched when compiling c++.
void AddDefaultCPlusPlusIncludePaths(const LangOptions &LangOpts,
const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts);
- /// AddDefaultSystemIncludePaths - Adds the default system include paths so
- /// that e.g. stdio.h is found.
+ /// Returns true iff AddDefaultIncludePaths should do anything. If this
+ /// returns false, include paths should instead be handled in the driver.
+ bool ShouldAddDefaultIncludePaths(const llvm::Triple &triple);
+
+ /// Adds the default system include paths so that e.g. stdio.h is found.
void AddDefaultIncludePaths(const LangOptions &Lang,
const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts);
- /// Realize - Merges all search path lists into one list and send it to
- /// HeaderSearch.
+ /// Merges all search path lists into one list and send it to HeaderSearch.
void Realize(const LangOptions &Lang);
};
@@ -123,7 +122,7 @@ static bool CanPrefixSysroot(StringRef Path) {
bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group,
bool isFramework,
- Optional<unsigned> UserEntryIdx) {
+ std::optional<unsigned> UserEntryIdx) {
// Add the path with sysroot prepended, if desired and this is a system header
// group.
if (HasSysroot) {
@@ -140,7 +139,7 @@ bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group,
bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
bool isFramework,
- Optional<unsigned> UserEntryIdx) {
+ std::optional<unsigned> UserEntryIdx) {
assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
FileManager &FM = Headers.getFileMgr();
@@ -225,28 +224,23 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base,
void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
- llvm::Triple::OSType os = triple.getOS();
-
- if (triple.isOSDarwin()) {
+ if (!ShouldAddDefaultIncludePaths(triple))
llvm_unreachable("Include management is handled in the driver.");
- }
+
+ llvm::Triple::OSType os = triple.getOS();
if (HSOpts.UseStandardSystemIncludes) {
switch (os) {
case llvm::Triple::CloudABI:
- case llvm::Triple::FreeBSD:
- case llvm::Triple::NetBSD:
- case llvm::Triple::OpenBSD:
case llvm::Triple::NaCl:
case llvm::Triple::PS4:
case llvm::Triple::PS5:
case llvm::Triple::ELFIAMCU:
- case llvm::Triple::Fuchsia:
break;
case llvm::Triple::Win32:
if (triple.getEnvironment() != llvm::Triple::Cygnus)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
// FIXME: temporary hack: hard-coded paths.
AddPath("/usr/local/include", System, false);
@@ -280,12 +274,6 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
}
switch (os) {
- case llvm::Triple::Linux:
- case llvm::Triple::Hurd:
- case llvm::Triple::Solaris:
- case llvm::Triple::OpenBSD:
- llvm_unreachable("Include management is handled in the driver.");
-
case llvm::Triple::CloudABI: {
// <sysroot>/<triple>/include
SmallString<128> P = StringRef(HSOpts.ResourceDir);
@@ -350,7 +338,6 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
case llvm::Triple::RTEMS:
case llvm::Triple::NaCl:
case llvm::Triple::ELFIAMCU:
- case llvm::Triple::Fuchsia:
break;
case llvm::Triple::PS4:
case llvm::Triple::PS5: {
@@ -386,20 +373,12 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(
const LangOptions &LangOpts, const llvm::Triple &triple,
const HeaderSearchOptions &HSOpts) {
- llvm::Triple::OSType os = triple.getOS();
- // FIXME: temporary hack: hard-coded paths.
-
- if (triple.isOSDarwin()) {
+ if (!ShouldAddDefaultIncludePaths(triple))
llvm_unreachable("Include management is handled in the driver.");
- }
+ // FIXME: temporary hack: hard-coded paths.
+ llvm::Triple::OSType os = triple.getOS();
switch (os) {
- case llvm::Triple::Linux:
- case llvm::Triple::Hurd:
- case llvm::Triple::Solaris:
- case llvm::Triple::AIX:
- llvm_unreachable("Include management is handled in the driver.");
- break;
case llvm::Triple::Win32:
switch (triple.getEnvironment()) {
default: llvm_unreachable("Include management is handled in the driver.");
@@ -425,44 +404,61 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(
}
}
-void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
- const llvm::Triple &triple,
- const HeaderSearchOptions &HSOpts) {
- // NB: This code path is going away. All of the logic is moving into the
- // driver which has the information necessary to do target-specific
- // selections of default include paths. Each target which moves there will be
- // exempted from this logic here until we can delete the entire pile of code.
+bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
+ const llvm::Triple &triple) {
switch (triple.getOS()) {
- default:
- break; // Everything else continues to use this routine's logic.
-
+ case llvm::Triple::AIX:
case llvm::Triple::Emscripten:
- case llvm::Triple::Linux:
- case llvm::Triple::Hurd:
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::NetBSD:
case llvm::Triple::OpenBSD:
+ case llvm::Triple::Fuchsia:
+ case llvm::Triple::Hurd:
+ case llvm::Triple::Linux:
case llvm::Triple::Solaris:
case llvm::Triple::WASI:
- case llvm::Triple::AIX:
- return;
+ return false;
case llvm::Triple::Win32:
if (triple.getEnvironment() != llvm::Triple::Cygnus ||
triple.isOSBinFormatMachO())
- return;
+ return false;
break;
case llvm::Triple::UnknownOS:
if (triple.isWasm())
- return;
+ return false;
+ break;
+
+ default:
break;
}
- // All header search logic is handled in the Driver for Darwin.
+ return true; // Everything else uses AddDefaultIncludePaths().
+}
+
+void InitHeaderSearch::AddDefaultIncludePaths(
+ const LangOptions &Lang, const llvm::Triple &triple,
+ const HeaderSearchOptions &HSOpts) {
+ // NB: This code path is going away. All of the logic is moving into the
+ // driver which has the information necessary to do target-specific
+ // selections of default include paths. Each target which moves there will be
+ // exempted from this logic in ShouldAddDefaultIncludePaths() until we can
+ // delete the entire pile of code.
+ if (!ShouldAddDefaultIncludePaths(triple))
+ return;
+
+ // NOTE: some additional header search logic is handled in the driver for
+ // Darwin.
if (triple.isOSDarwin()) {
if (HSOpts.UseStandardSystemIncludes) {
// Add the default framework include paths on Darwin.
- AddPath("/System/Library/Frameworks", System, true);
- AddPath("/Library/Frameworks", System, true);
+ if (triple.isDriverKit()) {
+ AddPath("/System/DriverKit/System/Library/Frameworks", System, true);
+ } else {
+ AddPath("/System/Library/Frameworks", System, true);
+ AddPath("/Library/Frameworks", System, true);
+ }
}
return;
}
@@ -479,9 +475,9 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
AddDefaultCIncludePaths(triple, HSOpts);
}
-/// RemoveDuplicates - If there are duplicate directory entries in the specified
-/// search list, remove the later (dead) ones. Returns the number of non-system
-/// headers removed, which is used to update NumAngled.
+/// If there are duplicate directory entries in the specified search list,
+/// remove the later (dead) ones. Returns the number of non-system headers
+/// removed, which is used to update NumAngled.
static unsigned RemoveDuplicates(std::vector<DirectoryLookupInfo> &SearchList,
unsigned First, bool Verbose) {
llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index a4cff403e739..d49d9e9e4b14 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -26,8 +26,6 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/Token.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -44,6 +42,7 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -1048,9 +1047,11 @@ StringRef Lexer::getImmediateMacroNameForDiagnostics(
while (SM.isMacroArgExpansion(Loc))
Loc = SM.getImmediateExpansionRange(Loc).getBegin();
- // If the macro's spelling has no FileID, then it's actually a token paste
- // or stringization (or similar) and not a macro at all.
- if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc))))
+ // If the macro's spelling isn't FileID or from scratch space, then it's
+ // actually a token paste or stringization (or similar) and not a macro at
+ // all.
+ SourceLocation SpellLoc = SM.getSpellingLoc(Loc);
+ if (!SpellLoc.isFileID() || SM.isWrittenInScratchSpace(SpellLoc))
return {};
// Find the spelling location of the start of the non-argument expansion
@@ -1195,15 +1196,16 @@ static char GetTrigraphCharForLetter(char Letter) {
/// whether trigraphs are enabled or not.
static char DecodeTrigraphChar(const char *CP, Lexer *L, bool Trigraphs) {
char Res = GetTrigraphCharForLetter(*CP);
- if (!Res || !L) return Res;
+ if (!Res)
+ return Res;
if (!Trigraphs) {
- if (!L->isLexingRawMode())
+ if (L && !L->isLexingRawMode())
L->Diag(CP-2, diag::trigraph_ignored);
return 0;
}
- if (!L->isLexingRawMode())
+ if (L && !L->isLexingRawMode())
L->Diag(CP-2, diag::trigraph_converted) << StringRef(&Res, 1);
return Res;
}
@@ -1256,12 +1258,12 @@ const char *Lexer::SkipEscapedNewLines(const char *P) {
}
}
-Optional<Token> Lexer::findNextToken(SourceLocation Loc,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
+std::optional<Token> Lexer::findNextToken(SourceLocation Loc,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
if (Loc.isMacroID()) {
if (!Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
- return None;
+ return std::nullopt;
}
Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
@@ -1272,7 +1274,7 @@ Optional<Token> Lexer::findNextToken(SourceLocation Loc,
bool InvalidTemp = false;
StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
if (InvalidTemp)
- return None;
+ return std::nullopt;
const char *TokenBegin = File.data() + LocInfo.second;
@@ -1292,7 +1294,7 @@ Optional<Token> Lexer::findNextToken(SourceLocation Loc,
SourceLocation Lexer::findLocationAfterToken(
SourceLocation Loc, tok::TokenKind TKind, const SourceManager &SM,
const LangOptions &LangOpts, bool SkipTrailingWhitespaceAndNewLine) {
- Optional<Token> Tok = findNextToken(Loc, SM, LangOpts);
+ std::optional<Token> Tok = findNextToken(Loc, SM, LangOpts);
if (!Tok || Tok->isNot(TKind))
return {};
SourceLocation TokenLoc = Tok->getLocation();
@@ -1457,7 +1459,35 @@ static bool isUnicodeWhitespace(uint32_t Codepoint) {
return UnicodeWhitespaceChars.contains(Codepoint);
}
-static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
+static llvm::SmallString<5> codepointAsHexString(uint32_t C) {
+ llvm::SmallString<5> CharBuf;
+ llvm::raw_svector_ostream CharOS(CharBuf);
+ llvm::write_hex(CharOS, C, llvm::HexPrintStyle::Upper, 4);
+ return CharBuf;
+}
+
+// To mitigate https://github.com/llvm/llvm-project/issues/54732,
+// we allow "Mathematical Notation Characters" in identifiers.
+// This is a proposed profile that extends the XID_Start/XID_continue
+// with mathematical symbols, superscipts and subscripts digits
+// found in some production software.
+// https://www.unicode.org/L2/L2022/22230-math-profile.pdf
+static bool isMathematicalExtensionID(uint32_t C, const LangOptions &LangOpts,
+ bool IsStart, bool &IsExtension) {
+ static const llvm::sys::UnicodeCharSet MathStartChars(
+ MathematicalNotationProfileIDStartRanges);
+ static const llvm::sys::UnicodeCharSet MathContinueChars(
+ MathematicalNotationProfileIDContinueRanges);
+ if (MathStartChars.contains(C) ||
+ (!IsStart && MathContinueChars.contains(C))) {
+ IsExtension = true;
+ return true;
+ }
+ return false;
+}
+
+static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts,
+ bool &IsExtension) {
if (LangOpts.AsmPreprocessor) {
return false;
} else if (LangOpts.DollarIdents && '$' == C) {
@@ -1469,8 +1499,10 @@ static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
// '_' doesn't have the XID_Continue property but is allowed in C and C++.
static const llvm::sys::UnicodeCharSet XIDStartChars(XIDStartRanges);
static const llvm::sys::UnicodeCharSet XIDContinueChars(XIDContinueRanges);
- return C == '_' || XIDStartChars.contains(C) ||
- XIDContinueChars.contains(C);
+ if (C == '_' || XIDStartChars.contains(C) || XIDContinueChars.contains(C))
+ return true;
+ return isMathematicalExtensionID(C, LangOpts, /*IsStart=*/false,
+ IsExtension);
} else if (LangOpts.C11) {
static const llvm::sys::UnicodeCharSet C11AllowedIDChars(
C11AllowedIDCharRanges);
@@ -1482,16 +1514,21 @@ static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
}
}
-static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) {
+static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts,
+ bool &IsExtension) {
+ assert(C > 0x7F && "isAllowedInitiallyIDChar called with an ASCII codepoint");
+ IsExtension = false;
if (LangOpts.AsmPreprocessor) {
return false;
}
if (LangOpts.CPlusPlus || LangOpts.C2x) {
static const llvm::sys::UnicodeCharSet XIDStartChars(XIDStartRanges);
- // '_' doesn't have the XID_Start property but is allowed in C++.
- return C == '_' || XIDStartChars.contains(C);
+ if (XIDStartChars.contains(C))
+ return true;
+ return isMathematicalExtensionID(C, LangOpts, /*IsStart=*/true,
+ IsExtension);
}
- if (!isAllowedIDChar(C, LangOpts))
+ if (!isAllowedIDChar(C, LangOpts, IsExtension))
return false;
if (LangOpts.C11) {
static const llvm::sys::UnicodeCharSet C11DisallowedInitialIDChars(
@@ -1503,6 +1540,22 @@ static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) {
return !C99DisallowedInitialIDChars.contains(C);
}
+static void diagnoseExtensionInIdentifier(DiagnosticsEngine &Diags, uint32_t C,
+ CharSourceRange Range) {
+
+ static const llvm::sys::UnicodeCharSet MathStartChars(
+ MathematicalNotationProfileIDStartRanges);
+ static const llvm::sys::UnicodeCharSet MathContinueChars(
+ MathematicalNotationProfileIDContinueRanges);
+
+ (void)MathStartChars;
+ (void)MathContinueChars;
+ assert((MathStartChars.contains(C) || MathContinueChars.contains(C)) &&
+ "Unexpected mathematical notation codepoint");
+ Diags.Report(Range.getBegin(), diag::ext_mathematical_notation)
+ << codepointAsHexString(C) << Range;
+}
+
static inline CharSourceRange makeCharRange(Lexer &L, const char *Begin,
const char *End) {
return CharSourceRange::getCharRange(L.getSourceLocation(Begin),
@@ -1602,18 +1655,13 @@ static void maybeDiagnoseUTF8Homoglyph(DiagnosticsEngine &Diags, uint32_t C,
std::lower_bound(std::begin(SortedHomoglyphs),
std::end(SortedHomoglyphs) - 1, HomoglyphPair{C, '\0'});
if (Homoglyph->Character == C) {
- llvm::SmallString<5> CharBuf;
- {
- llvm::raw_svector_ostream CharOS(CharBuf);
- llvm::write_hex(CharOS, C, llvm::HexPrintStyle::Upper, 4);
- }
if (Homoglyph->LooksLike) {
const char LooksLikeStr[] = {Homoglyph->LooksLike, 0};
Diags.Report(Range.getBegin(), diag::warn_utf8_symbol_homoglyph)
- << Range << CharBuf << LooksLikeStr;
+ << Range << codepointAsHexString(C) << LooksLikeStr;
} else {
Diags.Report(Range.getBegin(), diag::warn_utf8_symbol_zero_width)
- << Range << CharBuf;
+ << Range << codepointAsHexString(C);
}
}
}
@@ -1624,25 +1672,24 @@ static void diagnoseInvalidUnicodeCodepointInIdentifier(
if (isASCII(CodePoint))
return;
- bool IsIDStart = isAllowedInitiallyIDChar(CodePoint, LangOpts);
- bool IsIDContinue = IsIDStart || isAllowedIDChar(CodePoint, LangOpts);
+ bool IsExtension;
+ bool IsIDStart = isAllowedInitiallyIDChar(CodePoint, LangOpts, IsExtension);
+ bool IsIDContinue =
+ IsIDStart || isAllowedIDChar(CodePoint, LangOpts, IsExtension);
if ((IsFirst && IsIDStart) || (!IsFirst && IsIDContinue))
return;
bool InvalidOnlyAtStart = IsFirst && !IsIDStart && IsIDContinue;
- llvm::SmallString<5> CharBuf;
- llvm::raw_svector_ostream CharOS(CharBuf);
- llvm::write_hex(CharOS, CodePoint, llvm::HexPrintStyle::Upper, 4);
-
if (!IsFirst || InvalidOnlyAtStart) {
Diags.Report(Range.getBegin(), diag::err_character_not_allowed_identifier)
- << Range << CharBuf << int(InvalidOnlyAtStart)
+ << Range << codepointAsHexString(CodePoint) << int(InvalidOnlyAtStart)
<< FixItHint::CreateRemoval(Range);
} else {
Diags.Report(Range.getBegin(), diag::err_character_not_allowed)
- << Range << CharBuf << FixItHint::CreateRemoval(Range);
+ << Range << codepointAsHexString(CodePoint)
+ << FixItHint::CreateRemoval(Range);
}
}
@@ -1653,8 +1700,8 @@ bool Lexer::tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size,
if (CodePoint == 0) {
return false;
}
-
- if (!isAllowedIDChar(CodePoint, LangOpts)) {
+ bool IsExtension = false;
+ if (!isAllowedIDChar(CodePoint, LangOpts, IsExtension)) {
if (isASCII(CodePoint) || isUnicodeWhitespace(CodePoint))
return false;
if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
@@ -1667,10 +1714,15 @@ bool Lexer::tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size,
// We got a unicode codepoint that is neither a space nor a
// a valid identifier part.
// Carry on as if the codepoint was valid for recovery purposes.
- } else if (!isLexingRawMode())
+ } else if (!isLexingRawMode()) {
+ if (IsExtension)
+ diagnoseExtensionInIdentifier(PP->getDiagnostics(), CodePoint,
+ makeCharRange(*this, CurPtr, UCNPtr));
+
maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
makeCharRange(*this, CurPtr, UCNPtr),
/*IsFirst=*/false);
+ }
Result.setFlag(Token::HasUCN);
if ((UCNPtr - CurPtr == 6 && CurPtr[1] == 'u') ||
@@ -1693,7 +1745,9 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) {
if (Result != llvm::conversionOK)
return false;
- if (!isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts)) {
+ bool IsExtension = false;
+ if (!isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts,
+ IsExtension)) {
if (isASCII(CodePoint) || isUnicodeWhitespace(CodePoint))
return false;
@@ -1706,6 +1760,9 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) {
// a valid identifier part. Carry on as if the codepoint was
// valid for recovery purposes.
} else if (!isLexingRawMode()) {
+ if (IsExtension)
+ diagnoseExtensionInIdentifier(PP->getDiagnostics(), CodePoint,
+ makeCharRange(*this, CurPtr, UnicodePtr));
maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
makeCharRange(*this, CurPtr, UnicodePtr),
/*IsFirst=*/false);
@@ -1719,9 +1776,13 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) {
bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
const char *CurPtr) {
- if (isAllowedInitiallyIDChar(C, LangOpts)) {
+ bool IsExtension = false;
+ if (isAllowedInitiallyIDChar(C, LangOpts, IsExtension)) {
if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
!PP->isPreprocessedOutput()) {
+ if (IsExtension)
+ diagnoseExtensionInIdentifier(PP->getDiagnostics(), C,
+ makeCharRange(*this, BufferPtr, CurPtr));
maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C,
makeCharRange(*this, BufferPtr, CurPtr),
/*IsFirst=*/true);
@@ -1735,7 +1796,7 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
!PP->isPreprocessedOutput() && !isASCII(*BufferPtr) &&
- !isAllowedInitiallyIDChar(C, LangOpts) && !isUnicodeWhitespace(C)) {
+ !isUnicodeWhitespace(C)) {
// Non-ASCII characters tend to creep into source code unintentionally.
// Instead of letting the parser complain about the unknown token,
// just drop the character.
@@ -2905,7 +2966,7 @@ void Lexer::ReadToEndOfLine(SmallVectorImpl<char> *Result) {
break;
}
// FALL THROUGH.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case '\r':
case '\n':
// Okay, we found the end of the line. First, back up past the \0, \r, \n.
@@ -3195,9 +3256,9 @@ bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
return false;
}
-llvm::Optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
- const char *SlashLoc,
- Token *Result) {
+std::optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
+ const char *SlashLoc,
+ Token *Result) {
unsigned CharSize;
char Kind = getCharAndSize(StartPtr, CharSize);
assert((Kind == 'u' || Kind == 'U') && "expected a UCN");
@@ -3216,7 +3277,7 @@ llvm::Optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
if (!LangOpts.CPlusPlus && !LangOpts.C99) {
if (Diagnose)
Diag(SlashLoc, diag::warn_ucn_not_valid_in_c89);
- return llvm::None;
+ return std::nullopt;
}
const char *CurPtr = StartPtr + CharSize;
@@ -3225,7 +3286,7 @@ llvm::Optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
uint32_t CodePoint = 0;
while (Count != NumHexDigits || Delimited) {
char C = getCharAndSize(CurPtr, CharSize);
- if (!Delimited && C == '{') {
+ if (!Delimited && Count == 0 && C == '{') {
Delimited = true;
CurPtr += CharSize;
continue;
@@ -3242,15 +3303,15 @@ llvm::Optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
if (!Delimited)
break;
if (Diagnose)
- Diag(BufferPtr, diag::warn_delimited_ucn_incomplete)
+ Diag(SlashLoc, diag::warn_delimited_ucn_incomplete)
<< StringRef(KindLoc, 1);
- return llvm::None;
+ return std::nullopt;
}
if (CodePoint & 0xF000'0000) {
if (Diagnose)
Diag(KindLoc, diag::err_escape_too_large) << 0;
- return llvm::None;
+ return std::nullopt;
}
CodePoint <<= 4;
@@ -3261,21 +3322,21 @@ llvm::Optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
if (Count == 0) {
if (Diagnose)
- Diag(StartPtr, FoundEndDelimiter ? diag::warn_delimited_ucn_empty
+ Diag(SlashLoc, FoundEndDelimiter ? diag::warn_delimited_ucn_empty
: diag::warn_ucn_escape_no_digits)
<< StringRef(KindLoc, 1);
- return llvm::None;
+ return std::nullopt;
}
if (Delimited && Kind == 'U') {
if (Diagnose)
- Diag(StartPtr, diag::err_hex_escape_no_digits) << StringRef(KindLoc, 1);
- return llvm::None;
+ Diag(SlashLoc, diag::err_hex_escape_no_digits) << StringRef(KindLoc, 1);
+ return std::nullopt;
}
if (!Delimited && Count != NumHexDigits) {
if (Diagnose) {
- Diag(BufferPtr, diag::warn_ucn_escape_incomplete);
+ Diag(SlashLoc, diag::warn_ucn_escape_incomplete);
// If the user wrote \U1234, suggest a fixit to \u.
if (Count == 4 && NumHexDigits == 8) {
CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1);
@@ -3283,19 +3344,22 @@ llvm::Optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
<< FixItHint::CreateReplacement(URange, "u");
}
}
- return llvm::None;
+ return std::nullopt;
}
if (Delimited && PP) {
- Diag(BufferPtr, PP->getLangOpts().CPlusPlus2b
- ? diag::warn_cxx2b_delimited_escape_sequence
- : diag::ext_delimited_escape_sequence)
+ Diag(SlashLoc, PP->getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx2b_delimited_escape_sequence
+ : diag::ext_delimited_escape_sequence)
<< /*delimited*/ 0 << (PP->getLangOpts().CPlusPlus ? 1 : 0);
}
if (Result) {
Result->setFlag(Token::HasUCN);
- if (CurPtr - StartPtr == (ptrdiff_t)(Count + 2 + (Delimited ? 2 : 0)))
+ // If the UCN contains either a trigraph or a line splicing,
+ // we need to call getAndAdvanceChar again to set the appropriate flags
+ // on Result.
+ if (CurPtr - StartPtr == (ptrdiff_t)(Count + 1 + (Delimited ? 2 : 0)))
StartPtr = CurPtr;
else
while (StartPtr != CurPtr)
@@ -3306,8 +3370,9 @@ llvm::Optional<uint32_t> Lexer::tryReadNumericUCN(const char *&StartPtr,
return CodePoint;
}
-llvm::Optional<uint32_t> Lexer::tryReadNamedUCN(const char *&StartPtr,
- Token *Result) {
+std::optional<uint32_t> Lexer::tryReadNamedUCN(const char *&StartPtr,
+ const char *SlashLoc,
+ Token *Result) {
unsigned CharSize;
bool Diagnose = Result && !isLexingRawMode();
@@ -3320,8 +3385,8 @@ llvm::Optional<uint32_t> Lexer::tryReadNamedUCN(const char *&StartPtr,
C = getCharAndSize(CurPtr, CharSize);
if (C != '{') {
if (Diagnose)
- Diag(StartPtr, diag::warn_ucn_escape_incomplete);
- return llvm::None;
+ Diag(SlashLoc, diag::warn_ucn_escape_incomplete);
+ return std::nullopt;
}
CurPtr += CharSize;
const char *StartName = CurPtr;
@@ -3335,28 +3400,29 @@ llvm::Optional<uint32_t> Lexer::tryReadNamedUCN(const char *&StartPtr,
break;
}
- if (!isAlphanumeric(C) && C != '_' && C != '-' && C != ' ')
+ if (isVerticalWhitespace(C))
break;
Buffer.push_back(C);
}
if (!FoundEndDelimiter || Buffer.empty()) {
if (Diagnose)
- Diag(StartPtr, FoundEndDelimiter ? diag::warn_delimited_ucn_empty
+ Diag(SlashLoc, FoundEndDelimiter ? diag::warn_delimited_ucn_empty
: diag::warn_delimited_ucn_incomplete)
<< StringRef(KindLoc, 1);
- return llvm::None;
+ return std::nullopt;
}
StringRef Name(Buffer.data(), Buffer.size());
- llvm::Optional<char32_t> Res =
+ std::optional<char32_t> Match =
llvm::sys::unicode::nameToCodepointStrict(Name);
- llvm::Optional<llvm::sys::unicode::LooseMatchingResult> LooseMatch;
- if (!Res) {
- if (!isLexingRawMode()) {
- Diag(StartPtr, diag::err_invalid_ucn_name)
- << StringRef(Buffer.data(), Buffer.size());
- LooseMatch = llvm::sys::unicode::nameToCodepointLooseMatching(Name);
+ std::optional<llvm::sys::unicode::LooseMatchingResult> LooseMatch;
+ if (!Match) {
+ LooseMatch = llvm::sys::unicode::nameToCodepointLooseMatching(Name);
+ if (Diagnose) {
+ Diag(StartName, diag::err_invalid_ucn_name)
+ << StringRef(Buffer.data(), Buffer.size())
+ << makeCharRange(*this, StartName, CurPtr - CharSize);
if (LooseMatch) {
Diag(StartName, diag::note_invalid_ucn_name_loose_matching)
<< FixItHint::CreateReplacement(
@@ -3364,27 +3430,30 @@ llvm::Optional<uint32_t> Lexer::tryReadNamedUCN(const char *&StartPtr,
LooseMatch->Name);
}
}
- // When finding a match using Unicode loose matching rules
- // recover after having emitted a diagnostic.
- if (!LooseMatch)
- return llvm::None;
- // We do not offer missspelled character names suggestions here
+ // We do not offer misspelled character names suggestions here
// as the set of what would be a valid suggestion depends on context,
// and we should not make invalid suggestions.
}
- if (Diagnose && PP && !LooseMatch)
- Diag(BufferPtr, PP->getLangOpts().CPlusPlus2b
- ? diag::warn_cxx2b_delimited_escape_sequence
- : diag::ext_delimited_escape_sequence)
+ if (Diagnose && Match)
+ Diag(SlashLoc, PP->getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx2b_delimited_escape_sequence
+ : diag::ext_delimited_escape_sequence)
<< /*named*/ 1 << (PP->getLangOpts().CPlusPlus ? 1 : 0);
- if (LooseMatch)
- Res = LooseMatch->CodePoint;
+ // If no diagnostic has been emitted yet, likely because we are doing a
+ // tentative lexing, we do not want to recover here to make sure the token
+ // will not be incorrectly considered valid. This function will be called
+ // again and a diagnostic emitted then.
+ if (LooseMatch && Diagnose)
+ Match = LooseMatch->CodePoint;
if (Result) {
Result->setFlag(Token::HasUCN);
- if (CurPtr - StartPtr == (ptrdiff_t)(Buffer.size() + 4))
+ // If the UCN contains either a trigraph or a line splicing,
+ // we need to call getAndAdvanceChar again to set the appropriate flags
+ // on Result.
+ if (CurPtr - StartPtr == (ptrdiff_t)(Buffer.size() + 3))
StartPtr = CurPtr;
else
while (StartPtr != CurPtr)
@@ -3392,19 +3461,19 @@ llvm::Optional<uint32_t> Lexer::tryReadNamedUCN(const char *&StartPtr,
} else {
StartPtr = CurPtr;
}
- return *Res;
+ return Match ? std::optional<uint32_t>(*Match) : std::nullopt;
}
uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc,
Token *Result) {
unsigned CharSize;
- llvm::Optional<uint32_t> CodePointOpt;
+ std::optional<uint32_t> CodePointOpt;
char Kind = getCharAndSize(StartPtr, CharSize);
if (Kind == 'u' || Kind == 'U')
CodePointOpt = tryReadNumericUCN(StartPtr, SlashLoc, Result);
else if (Kind == 'N')
- CodePointOpt = tryReadNamedUCN(StartPtr, Result);
+ CodePointOpt = tryReadNamedUCN(StartPtr, SlashLoc, Result);
if (!CodePointOpt)
return 0;
@@ -3516,10 +3585,9 @@ bool Lexer::Lex(Token &Result) {
/// token, not a normal token, as such, it is an internal interface. It assumes
/// that the Flags of result have been cleared before calling this.
bool Lexer::LexTokenInternal(Token &Result, bool TokAtPhysicalStartOfLine) {
-LexNextToken:
- // New token, can't need cleaning yet.
- Result.clearFlag(Token::NeedsCleaning);
- Result.setIdentifierInfo(nullptr);
+LexStart:
+ assert(!Result.needsCleaning() && "Result needs cleaning");
+ assert(!Result.hasPtrData() && "Result has not been reset");
// CurPtr - Cache BufferPtr in an automatic variable.
const char *CurPtr = BufferPtr;
@@ -3591,7 +3659,7 @@ LexNextToken:
case '\r':
if (CurPtr[0] == '\n')
(void)getAndAdvanceChar(CurPtr, Result);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case '\n':
// If we are inside a preprocessor directive and we see the end of line,
// we know we are done with the directive, so return an EOD token.
@@ -3788,7 +3856,7 @@ LexNextToken:
return LexCharConstant(Result, ConsumeChar(CurPtr, SizeTmp, Result),
tok::wide_char_constant);
// FALL THROUGH, treating L like the start of an identifier.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// C99 6.4.2: Identifiers.
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
@@ -4301,6 +4369,10 @@ HandleDirective:
// We parsed the directive; lex a token with the new state.
return false;
+
+LexNextToken:
+ Result.clearFlag(Token::NeedsCleaning);
+ goto LexStart;
}
const char *Lexer::convertDependencyDirectiveToken(
@@ -4323,6 +4395,8 @@ bool Lexer::LexDependencyDirectiveToken(Token &Result) {
while (NextDepDirectiveTokenIndex == DepDirectives.front().Tokens.size()) {
if (DepDirectives.front().Kind == pp_eof)
return LexEndOfFile(Result, BufferEnd);
+ if (DepDirectives.front().Kind == tokens_present_before_eof)
+ MIOpt.ReadToken();
NextDepDirectiveTokenIndex = 0;
DepDirectives = DepDirectives.drop_front();
}
@@ -4334,6 +4408,22 @@ bool Lexer::LexDependencyDirectiveToken(Token &Result) {
MIOpt.ReadToken();
}
+ if (ParsingFilename && DDTok.is(tok::less)) {
+ BufferPtr = BufferStart + DDTok.Offset;
+ LexAngledStringLiteral(Result, BufferPtr + 1);
+ if (Result.isNot(tok::header_name))
+ return true;
+ // Advance the index of lexed tokens.
+ while (true) {
+ const dependency_directives_scan::Token &NextTok =
+ DepDirectives.front().Tokens[NextDepDirectiveTokenIndex];
+ if (BufferStart + NextTok.Offset >= BufferPtr)
+ break;
+ ++NextDepDirectiveTokenIndex;
+ }
+ return true;
+ }
+
const char *TokPtr = convertDependencyDirectiveToken(DDTok, Result);
if (Result.is(tok::hash) && Result.isAtStartOfLine()) {
@@ -4398,6 +4488,7 @@ bool Lexer::LexDependencyDirectiveTokenWhileSkipping(Token &Result) {
case cxx_import_decl:
case cxx_export_module_decl:
case cxx_export_import_decl:
+ case tokens_present_before_eof:
break;
case pp_if:
case pp_ifdef:
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index 53635a7385ec..421a85336043 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -358,7 +358,7 @@ void clang::expandUCNs(SmallVectorImpl<char> &Buf, StringRef Input) {
++I;
auto Delim = std::find(I, Input.end(), '}');
assert(Delim != Input.end());
- llvm::Optional<llvm::sys::unicode::LooseMatchingResult> Res =
+ std::optional<llvm::sys::unicode::LooseMatchingResult> Res =
llvm::sys::unicode::nameToCodepointLooseMatching(
StringRef(I, std::distance(I, Delim)));
assert(Res);
@@ -487,7 +487,7 @@ static void DiagnoseInvalidUnicodeCharacterName(
namespace u = llvm::sys::unicode;
- llvm::Optional<u::LooseMatchingResult> Res =
+ std::optional<u::LooseMatchingResult> Res =
u::nameToCodepointLooseMatching(Name);
if (Res) {
Diag(Diags, Features, Loc, TokBegin, TokRangeBegin, TokRangeEnd,
@@ -515,8 +515,9 @@ static void DiagnoseInvalidUnicodeCharacterName(
std::string Str;
llvm::UTF32 V = Match.Value;
- LLVM_ATTRIBUTE_UNUSED bool Converted =
+ bool Converted =
llvm::convertUTF32ToUTF8String(llvm::ArrayRef<llvm::UTF32>(&V, 1), Str);
+ (void)Converted;
assert(Converted && "Found a match wich is not a unicode character");
Diag(Diags, Features, Loc, TokBegin, TokRangeBegin, TokRangeEnd,
@@ -545,15 +546,13 @@ static bool ProcessNamedUCNEscape(const char *ThisTokBegin,
diag::err_delimited_escape_missing_brace)
<< StringRef(&ThisTokBuf[-1], 1);
}
- ThisTokBuf++;
return false;
}
ThisTokBuf++;
- const char *ClosingBrace =
- std::find_if_not(ThisTokBuf, ThisTokEnd, [](char C) {
- return llvm::isAlnum(C) || llvm::isSpace(C) || C == '_' || C == '-';
- });
- bool Incomplete = ClosingBrace == ThisTokEnd || *ClosingBrace != '}';
+ const char *ClosingBrace = std::find_if(ThisTokBuf, ThisTokEnd, [](char C) {
+ return C == '}' || isVerticalWhitespace(C);
+ });
+ bool Incomplete = ClosingBrace == ThisTokEnd;
bool Empty = ClosingBrace == ThisTokBuf;
if (Incomplete || Empty) {
if (Diags) {
@@ -567,8 +566,7 @@ static bool ProcessNamedUCNEscape(const char *ThisTokBegin,
}
StringRef Name(ThisTokBuf, ClosingBrace - ThisTokBuf);
ThisTokBuf = ClosingBrace + 1;
- llvm::Optional<char32_t> Res =
- llvm::sys::unicode::nameToCodepointStrict(Name);
+ std::optional<char32_t> Res = llvm::sys::unicode::nameToCodepointStrict(Name);
if (!Res) {
if (Diags)
DiagnoseInvalidUnicodeCharacterName(Diags, Features, Loc, ThisTokBegin,
@@ -766,13 +764,13 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
switch (bytesToWrite) { // note: everything falls through.
case 4:
*--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 3:
*--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 2:
*--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 1:
*--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]);
}
@@ -945,9 +943,13 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// CUDA host and device may have different _Float16 support, therefore
// allows f16 literals to avoid false alarm.
+ // When we compile for OpenMP target offloading on NVPTX, f16 suffix
+ // should also be supported.
// ToDo: more precise check for CUDA.
- if ((Target.hasFloat16Type() || LangOpts.CUDA) && s + 2 < ThisTokEnd &&
- s[1] == '1' && s[2] == '6') {
+ // TODO: AMDGPU might also support it in the future.
+ if ((Target.hasFloat16Type() || LangOpts.CUDA ||
+ (LangOpts.OpenMPIsDevice && Target.getTriple().isNVPTX())) &&
+ s + 2 < ThisTokEnd && s[1] == '1' && s[2] == '6') {
s += 2; // success, eat up 2 characters.
isFloat16 = true;
continue;
@@ -1037,7 +1039,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
break;
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 'j':
case 'J':
if (isImaginary) break; // Cannot be repeated.
diff --git a/clang/lib/Lex/MacroArgs.cpp b/clang/lib/Lex/MacroArgs.cpp
index 7ede00b4aa64..c54f69bb9ead 100644
--- a/clang/lib/Lex/MacroArgs.cpp
+++ b/clang/lib/Lex/MacroArgs.cpp
@@ -62,7 +62,7 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
// Copy the actual unexpanded tokens to immediately after the result ptr.
if (!UnexpArgTokens.empty()) {
- static_assert(std::is_trivial<Token>::value,
+ static_assert(std::is_trivial_v<Token>,
"assume trivial copyability if copying into the "
"uninitialized array (as opposed to reusing a cached "
"MacroArgs)");
@@ -94,7 +94,7 @@ MacroArgs *MacroArgs::deallocate() {
// Run the dtor to deallocate the vectors.
this->~MacroArgs();
// Release the memory for the object.
- static_assert(std::is_trivially_destructible<Token>::value,
+ static_assert(std::is_trivially_destructible_v<Token>,
"assume trivially destructible and forego destructors");
free(this);
@@ -169,7 +169,7 @@ const std::vector<Token> &MacroArgs::getPreExpArgument(unsigned Arg,
std::vector<Token> &Result = PreExpArgTokens[Arg];
if (!Result.empty()) return Result;
- SaveAndRestore<bool> PreExpandingMacroArgs(PP.InMacroArgPreExpansion, true);
+ SaveAndRestore PreExpandingMacroArgs(PP.InMacroArgPreExpansion, true);
const Token *AT = getUnexpArgument(Arg);
unsigned NumToks = getArgLength(AT)+1; // Include the EOF.
diff --git a/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp
index eae12beb6244..39bb0f44eff2 100644
--- a/clang/lib/Lex/MacroInfo.cpp
+++ b/clang/lib/Lex/MacroInfo.cpp
@@ -18,12 +18,12 @@
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <optional>
#include <utility>
using namespace clang;
@@ -34,11 +34,11 @@ namespace {
// and 4 byte SourceLocation.
template <int> class MacroInfoSizeChecker {
public:
- constexpr static bool AsExpected = true;
+ [[maybe_unused]] constexpr static bool AsExpected = true;
};
template <> class MacroInfoSizeChecker<8> {
public:
- constexpr static bool AsExpected =
+ [[maybe_unused]] constexpr static bool AsExpected =
sizeof(MacroInfo) == (32 + sizeof(SourceLocation) * 2);
};
@@ -118,7 +118,7 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
if (A.getKind() != B.getKind())
return false;
- // If this isn't the first first token, check that the whitespace and
+ // If this isn't the first token, check that the whitespace and
// start-of-line characteristics match.
if (i != 0 &&
(A.isAtStartOfLine() != B.isAtStartOfLine() ||
@@ -198,7 +198,7 @@ LLVM_DUMP_METHOD void MacroInfo::dump() const {
MacroDirective::DefInfo MacroDirective::getDefinition() {
MacroDirective *MD = this;
SourceLocation UndefLoc;
- Optional<bool> isPublic;
+ std::optional<bool> isPublic;
for (; MD; MD = MD->getPrevious()) {
if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD))
return DefInfo(DefMD, UndefLoc, !isPublic || *isPublic);
@@ -213,7 +213,7 @@ MacroDirective::DefInfo MacroDirective::getDefinition() {
isPublic = VisMD->isPublic();
}
- return DefInfo(nullptr, UndefLoc, !isPublic || isPublic.value());
+ return DefInfo(nullptr, UndefLoc, !isPublic || *isPublic);
}
const MacroDirective::DefInfo
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 47d6f5893e97..ee2cca4e0814 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -28,7 +28,6 @@
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -47,6 +46,7 @@
#include <cassert>
#include <cstdint>
#include <cstring>
+#include <optional>
#include <string>
#include <system_error>
#include <utility>
@@ -75,7 +75,6 @@ void ModuleMap::addLinkAsDependency(Module *Mod) {
Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) {
switch ((int)Role) {
- default: llvm_unreachable("unknown header role");
case NormalHeader:
return Module::HK_Normal;
case PrivateHeader:
@@ -84,7 +83,10 @@ Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) {
return Module::HK_Textual;
case PrivateHeader | TextualHeader:
return Module::HK_PrivateTextual;
+ case ExcludedHeader:
+ return Module::HK_Excluded;
}
+ llvm_unreachable("unknown header role");
}
ModuleMap::ModuleHeaderRole
@@ -99,11 +101,15 @@ ModuleMap::headerKindToRole(Module::HeaderKind Kind) {
case Module::HK_PrivateTextual:
return ModuleHeaderRole(PrivateHeader | TextualHeader);
case Module::HK_Excluded:
- llvm_unreachable("unexpected header kind");
+ return ExcludedHeader;
}
llvm_unreachable("unknown header kind");
}
+bool ModuleMap::isModular(ModuleHeaderRole Role) {
+ return !(Role & (ModuleMap::TextualHeader | ModuleMap::ExcludedHeader));
+}
+
Module::ExportDecl
ModuleMap::resolveExport(Module *Mod,
const Module::UnresolvedExportDecl &Unresolved,
@@ -171,23 +177,23 @@ static void appendSubframeworkPaths(Module *Mod,
llvm::sys::path::append(Path, "Frameworks", Framework + ".framework");
}
-Optional<FileEntryRef> ModuleMap::findHeader(
+OptionalFileEntryRef ModuleMap::findHeader(
Module *M, const Module::UnresolvedHeaderDirective &Header,
SmallVectorImpl<char> &RelativePathName, bool &NeedsFramework) {
// Search for the header file within the module's home directory.
auto *Directory = M->Directory;
SmallString<128> FullPathName(Directory->getName());
- auto GetFile = [&](StringRef Filename) -> Optional<FileEntryRef> {
+ auto GetFile = [&](StringRef Filename) -> OptionalFileEntryRef {
auto File =
expectedToOptional(SourceMgr.getFileManager().getFileRef(Filename));
if (!File || (Header.Size && File->getSize() != *Header.Size) ||
(Header.ModTime && File->getModificationTime() != *Header.ModTime))
- return None;
+ return std::nullopt;
return *File;
};
- auto GetFrameworkFile = [&]() -> Optional<FileEntryRef> {
+ auto GetFrameworkFile = [&]() -> OptionalFileEntryRef {
unsigned FullPathLength = FullPathName.size();
appendSubframeworkPaths(M, RelativePathName);
unsigned RelativePathLength = RelativePathName.size();
@@ -241,7 +247,7 @@ Optional<FileEntryRef> ModuleMap::findHeader(
<< Header.FileName << M->getFullModuleName();
NeedsFramework = true;
}
- return None;
+ return std::nullopt;
}
return NormalHdrFile;
@@ -251,7 +257,7 @@ void ModuleMap::resolveHeader(Module *Mod,
const Module::UnresolvedHeaderDirective &Header,
bool &NeedsFramework) {
SmallString<128> RelativePathName;
- if (Optional<FileEntryRef> File =
+ if (OptionalFileEntryRef File =
findHeader(Mod, Header, RelativePathName, NeedsFramework)) {
if (Header.IsUmbrella) {
const DirectoryEntry *UmbrellaDir = &File->getDir().getDirEntry();
@@ -264,10 +270,7 @@ void ModuleMap::resolveHeader(Module *Mod,
} else {
Module::Header H = {Header.FileName, std::string(RelativePathName.str()),
*File};
- if (Header.Kind == Module::HK_Excluded)
- excludeHeader(Mod, H);
- else
- addHeader(Mod, H, headerKindToRole(Header.Kind));
+ addHeader(Mod, H, headerKindToRole(Header.Kind));
}
} else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) {
// There's a builtin header but no corresponding on-disk header. Assume
@@ -301,7 +304,7 @@ 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().getOptionalFileRef(Path);
if (!File)
return false;
@@ -479,7 +482,7 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
if (RequestingModule) {
resolveUses(RequestingModule, /*Complain=*/false);
- resolveHeaderDirectives(RequestingModule, /*File=*/llvm::None);
+ resolveHeaderDirectives(RequestingModule, /*File=*/std::nullopt);
}
bool Excluded = false;
@@ -489,6 +492,12 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
HeadersMap::iterator Known = findKnownHeader(File);
if (Known != Headers.end()) {
for (const KnownHeader &Header : Known->second) {
+ // Excluded headers don't really belong to a module.
+ if (Header.getRole() == ModuleMap::ExcludedHeader) {
+ Excluded = true;
+ continue;
+ }
+
// Remember private headers for later printing of a diagnostic.
if (violatesPrivateInclude(RequestingModule, File, Header)) {
Private = Header.getModule();
@@ -562,12 +571,18 @@ static bool isBetterKnownHeader(const ModuleMap::KnownHeader &New,
(Old.getRole() & ModuleMap::TextualHeader))
return !(New.getRole() & ModuleMap::TextualHeader);
+ // Prefer a non-excluded header over an excluded header.
+ if ((New.getRole() == ModuleMap::ExcludedHeader) !=
+ (Old.getRole() == ModuleMap::ExcludedHeader))
+ return New.getRole() != ModuleMap::ExcludedHeader;
+
// Don't have a reason to choose between these. Just keep the first one.
return false;
}
ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File,
- bool AllowTextual) {
+ bool AllowTextual,
+ bool AllowExcluded) {
auto MakeResult = [&](ModuleMap::KnownHeader R) -> ModuleMap::KnownHeader {
if (!AllowTextual && R.getRole() & ModuleMap::TextualHeader)
return {};
@@ -579,6 +594,9 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File,
ModuleMap::KnownHeader Result;
// Iterate over all modules that 'File' is part of to find the best fit.
for (KnownHeader &H : Known->second) {
+ // Cannot use a module if the header is excluded in it.
+ if (!AllowExcluded && H.getRole() == ModuleMap::ExcludedHeader)
+ continue;
// Prefer a header from the source module over all others.
if (H.getModule()->getTopLevelModule() == SourceModule)
return MakeResult(H);
@@ -607,7 +625,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
UmbrellaModule = UmbrellaModule->Parent;
if (UmbrellaModule->InferSubmodules) {
- const FileEntry *UmbrellaModuleMap =
+ OptionalFileEntryRefDegradesToFileEntryPtr UmbrellaModuleMap =
getModuleMapFileForUniquing(UmbrellaModule);
// Infer submodules for each of the directories we found between
@@ -672,7 +690,7 @@ ModuleMap::findAllModulesForHeader(const FileEntry *File) {
if (findOrCreateModuleForHeaderInUmbrellaDir(File))
return Headers.find(File)->second;
- return None;
+ return std::nullopt;
}
ArrayRef<ModuleMap::KnownHeader>
@@ -681,7 +699,7 @@ ModuleMap::findResolvedModulesForHeader(const FileEntry *File) const {
resolveHeaderDirectives(File);
auto It = Headers.find(File);
if (It == Headers.end())
- return None;
+ return std::nullopt;
return It->second;
}
@@ -700,6 +718,9 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
E = Known->second.end();
I != E; ++I) {
+ if (I->getRole() == ModuleMap::ExcludedHeader)
+ continue;
+
if (I->isAvailable() &&
(!RequestingModule ||
I->getModule()->isSubModuleOf(RequestingModule))) {
@@ -852,8 +873,7 @@ ModuleMap::createPrivateModuleFragmentForInterfaceUnit(Module *Parent,
}
Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
- StringRef Name,
- Module *GlobalModule) {
+ StringRef Name) {
assert(LangOpts.CurrentModule == Name && "module name mismatch");
assert(!Modules[Name] && "redefining existing module");
@@ -879,29 +899,6 @@ Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
return Result;
}
-Module *ModuleMap::createHeaderModule(StringRef Name,
- ArrayRef<Module::Header> Headers) {
- assert(LangOpts.CurrentModule == Name && "module name mismatch");
- assert(!Modules[Name] && "redefining existing module");
-
- auto *Result =
- new Module(Name, SourceLocation(), nullptr, /*IsFramework*/ false,
- /*IsExplicit*/ false, NumCreatedModules++);
- Result->Kind = Module::ModuleInterfaceUnit;
- Modules[Name] = SourceModule = Result;
-
- for (const Module::Header &H : Headers) {
- auto *M = new Module(H.NameAsWritten, SourceLocation(), Result,
- /*IsFramework*/ false,
- /*IsExplicit*/ true, NumCreatedModules++);
- // Header modules are implicitly 'export *'.
- M->Exports.push_back(Module::ExportDecl(nullptr, true));
- addHeader(M, H, NormalHeader);
- }
-
- return Result;
-}
-
Module *ModuleMap::createHeaderUnit(SourceLocation Loc, StringRef Name,
Module::Header H) {
assert(LangOpts.CurrentModule == Name && "module name mismatch");
@@ -1018,14 +1015,16 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
// If we're not allowed to infer a framework module, don't.
if (!canInfer)
return nullptr;
- } else
- ModuleMapFile = getModuleMapFileForUniquing(Parent);
-
+ } else {
+ OptionalFileEntryRefDegradesToFileEntryPtr ModuleMapRef =
+ getModuleMapFileForUniquing(Parent);
+ ModuleMapFile = ModuleMapRef;
+ }
// Look for an umbrella header.
SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h");
- auto UmbrellaHeader = FileMgr.getFile(UmbrellaName);
+ auto UmbrellaHeader = FileMgr.getOptionalFileRef(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
@@ -1137,14 +1136,14 @@ Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework,
}
void ModuleMap::setUmbrellaHeader(
- Module *Mod, const FileEntry *UmbrellaHeader, const Twine &NameAsWritten,
+ Module *Mod, FileEntryRef UmbrellaHeader, const Twine &NameAsWritten,
const Twine &PathRelativeToRootModuleDirectory) {
Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));
- Mod->Umbrella = UmbrellaHeader;
+ Mod->Umbrella = &UmbrellaHeader.getMapEntry();
Mod->UmbrellaAsWritten = NameAsWritten.str();
Mod->UmbrellaRelativeToRootModuleDirectory =
PathRelativeToRootModuleDirectory.str();
- UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
+ UmbrellaDirs[UmbrellaHeader.getDir()] = Mod;
// Notify callbacks that we just added a new header.
for (const auto &Cb : Callbacks)
@@ -1214,11 +1213,11 @@ void ModuleMap::resolveHeaderDirectives(const FileEntry *File) const {
}
void ModuleMap::resolveHeaderDirectives(
- Module *Mod, llvm::Optional<const FileEntry *> File) const {
+ Module *Mod, std::optional<const FileEntry *> File) const {
bool NeedsFramework = false;
SmallVector<Module::UnresolvedHeaderDirective, 1> NewHeaders;
- const auto Size = File ? File.value()->getSize() : 0;
- const auto ModTime = File ? File.value()->getModificationTime() : 0;
+ const auto Size = File ? (*File)->getSize() : 0;
+ const auto ModTime = File ? (*File)->getModificationTime() : 0;
for (auto &Header : Mod->UnresolvedHeaders) {
if (File && ((Header.ModTime && Header.ModTime != ModTime) ||
@@ -1260,29 +1259,21 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header,
Cb->moduleMapAddHeader(Header.Entry->getName());
}
-void ModuleMap::excludeHeader(Module *Mod, Module::Header Header) {
- // Add this as a known header so we won't implicitly add it to any
- // umbrella directory module.
- // FIXME: Should we only exclude it from umbrella modules within the
- // specified module?
- (void) Headers[Header.Entry];
-
- Mod->Headers[Module::HK_Excluded].push_back(std::move(Header));
-}
-
-const FileEntry *
+OptionalFileEntryRef
ModuleMap::getContainingModuleMapFile(const Module *Module) const {
if (Module->DefinitionLoc.isInvalid())
- return nullptr;
+ return std::nullopt;
- return SourceMgr.getFileEntryForID(
- SourceMgr.getFileID(Module->DefinitionLoc));
+ return SourceMgr.getFileEntryRefForID(
+ SourceMgr.getFileID(Module->DefinitionLoc));
}
-const FileEntry *ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
+OptionalFileEntryRef
+ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
if (M->IsInferred) {
assert(InferredModuleAllowedBy.count(M) && "missing inferred module map");
- return InferredModuleAllowedBy.find(M)->second;
+ // FIXME: Update InferredModuleAllowedBy to use FileEntryRef.
+ return InferredModuleAllowedBy.find(M)->second->getLastRef();
}
return getContainingModuleMapFile(M);
}
@@ -1292,6 +1283,49 @@ void ModuleMap::setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap) {
InferredModuleAllowedBy[M] = ModMap;
}
+std::error_code
+ModuleMap::canonicalizeModuleMapPath(SmallVectorImpl<char> &Path) {
+ StringRef Dir = llvm::sys::path::parent_path({Path.data(), Path.size()});
+
+ // Do not canonicalize within the framework; the module map parser expects
+ // Modules/ not Versions/A/Modules.
+ if (llvm::sys::path::filename(Dir) == "Modules") {
+ StringRef Parent = llvm::sys::path::parent_path(Dir);
+ if (Parent.endswith(".framework"))
+ Dir = Parent;
+ }
+
+ FileManager &FM = SourceMgr.getFileManager();
+ auto DirEntry = FM.getDirectory(Dir.empty() ? "." : Dir);
+ if (!DirEntry)
+ return DirEntry.getError();
+
+ // Canonicalize the directory.
+ StringRef CanonicalDir = FM.getCanonicalName(*DirEntry);
+ if (CanonicalDir != Dir) {
+ auto CanonicalDirEntry = FM.getDirectory(CanonicalDir);
+ // Only use the canonicalized path if it resolves to the same entry as the
+ // original. This is not true if there's a VFS overlay on top of a FS where
+ // the directory is a symlink. The overlay would not remap the target path
+ // of the symlink to the same directory entry in that case.
+ if (CanonicalDirEntry && *CanonicalDirEntry == *DirEntry) {
+ bool Done = llvm::sys::path::replace_path_prefix(Path, Dir, CanonicalDir);
+ (void)Done;
+ assert(Done && "Path should always start with Dir");
+ }
+ }
+
+ // In theory, the filename component should also be canonicalized if it
+ // on a case-insensitive filesystem. However, the extra canonicalization is
+ // expensive and if clang looked up the filename it will always be lowercase.
+
+ // Remove ., remove redundant separators, and switch to native separators.
+ // This is needed for separators between CanonicalDir and the filename.
+ llvm::sys::path::remove_dots(Path);
+
+ return std::error_code();
+}
+
void ModuleMap::addAdditionalModuleMapFile(const Module *M,
const FileEntry *ModuleMap) {
AdditionalModMaps[M].insert(ModuleMap);
@@ -1668,7 +1702,7 @@ retry:
break;
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
@@ -2026,8 +2060,7 @@ void ModuleMapParser::parseModuleDecl() {
ActiveModule->IsSystem = true;
if (Attrs.IsExternC)
ActiveModule->IsExternC = true;
- if (Attrs.NoUndeclaredIncludes ||
- (!ActiveModule->Parent && ModuleName == "Darwin"))
+ if (Attrs.NoUndeclaredIncludes)
ActiveModule->NoUndeclaredIncludes = true;
ActiveModule->Directory = Directory;
@@ -2300,6 +2333,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
SourceLocation LeadingLoc) {
// We've already consumed the first token.
ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader;
+
if (LeadingToken == MMToken::PrivateKeyword) {
Role = ModuleMap::PrivateHeader;
// 'private' may optionally be followed by 'textual'.
@@ -2307,6 +2341,8 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
LeadingToken = Tok.Kind;
consumeToken();
}
+ } else if (LeadingToken == MMToken::ExcludeKeyword) {
+ Role = ModuleMap::ExcludedHeader;
}
if (LeadingToken == MMToken::TextualKeyword)
@@ -2340,9 +2376,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
Header.FileName = std::string(Tok.getString());
Header.FileNameLoc = consumeToken();
Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
- Header.Kind =
- (LeadingToken == MMToken::ExcludeKeyword ? Module::HK_Excluded
- : Map.headerRoleToKind(Role));
+ Header.Kind = Map.headerRoleToKind(Role);
// Check whether we already have an umbrella.
if (Header.IsUmbrella && ActiveModule->Umbrella) {
@@ -2476,8 +2510,8 @@ 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 (auto FE = SourceMgr.getFileManager().getFile(I->path())) {
- Module::Header Header = {"", std::string(I->path()), *FE};
+ if (auto FE = SourceMgr.getFileManager().getOptionalFileRef(I->path())) {
+ Module::Header Header = {"", std::string(I->path()), FE};
Headers.push_back(std::move(Header));
}
}
@@ -3033,7 +3067,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
}
assert(Target && "Missing target information");
- llvm::Optional<llvm::MemoryBufferRef> Buffer = SourceMgr.getBufferOrNone(ID);
+ std::optional<llvm::MemoryBufferRef> Buffer = SourceMgr.getBufferOrNone(ID);
if (!Buffer)
return ParsedModuleMap[File] = true;
assert((!Offset || *Offset <= Buffer->getBufferSize()) &&
diff --git a/clang/lib/Lex/PPCallbacks.cpp b/clang/lib/Lex/PPCallbacks.cpp
index b618071590ba..f2b60a728e90 100644
--- a/clang/lib/Lex/PPCallbacks.cpp
+++ b/clang/lib/Lex/PPCallbacks.cpp
@@ -15,16 +15,15 @@ using namespace clang;
PPCallbacks::~PPCallbacks() = default;
void PPCallbacks::HasInclude(SourceLocation Loc, StringRef FileName,
- bool IsAngled, Optional<FileEntryRef> File,
+ bool IsAngled, OptionalFileEntryRef File,
SrcMgr::CharacteristicKind FileType) {}
// Out of line key method.
PPChainedCallbacks::~PPChainedCallbacks() = default;
void PPChainedCallbacks::HasInclude(SourceLocation Loc, StringRef FileName,
- bool IsAngled, Optional<FileEntryRef> File,
+ bool IsAngled, OptionalFileEntryRef File,
SrcMgr::CharacteristicKind FileType) {
First->HasInclude(Loc, FileName, IsAngled, File, FileType);
Second->HasInclude(Loc, FileName, IsAngled, File, FileType);
}
-
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 9a8fd4391b41..6ae513dea878 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -47,6 +47,7 @@
#include <cassert>
#include <cstring>
#include <new>
+#include <optional>
#include <string>
#include <utility>
@@ -57,9 +58,8 @@ using namespace clang;
//===----------------------------------------------------------------------===//
MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
- auto *MIChain = new (BP) MacroInfoChain{L, MIChainHead};
- MIChainHead = MIChain;
- return &MIChain->MI;
+ static_assert(std::is_trivially_destructible_v<MacroInfo>, "");
+ return new (BP) MacroInfo(L);
}
DefMacroDirective *Preprocessor::AllocateDefMacroDirective(MacroInfo *MI,
@@ -109,25 +109,6 @@ enum PPElifDiag {
PED_Elifndef
};
-// The -fmodule-name option tells the compiler to textually include headers in
-// the specified module, meaning clang won't build the specified module. This is
-// useful in a number of situations, for instance, when building a library that
-// vends a module map, one might want to avoid hitting intermediate build
-// products containimg the module map or avoid finding the system installed
-// modulemap for that library.
-static bool isForModuleBuilding(Module *M, StringRef CurrentModule,
- StringRef ModuleName) {
- StringRef TopLevelName = M->getTopLevelModuleName();
-
- // When building framework Foo, we wanna make sure that Foo *and* Foo_Private
- // are textually included and no modules are built for both.
- if (M->getTopLevelModule()->IsFramework && CurrentModule == ModuleName &&
- !CurrentModule.endswith("_Private") && TopLevelName.endswith("_Private"))
- TopLevelName = TopLevelName.drop_back(8);
-
- return TopLevelName == CurrentModule;
-}
-
static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) {
const LangOptions &Lang = PP.getLangOpts();
if (isReservedInAllContexts(II->isReserved(Lang))) {
@@ -274,9 +255,9 @@ static bool warnByDefaultOnWrongCase(StringRef Include) {
/// \param Candidates the candidates to find a similar string.
///
/// \returns a similar string if exists. If no similar string exists,
-/// returns None.
-static Optional<StringRef> findSimilarStr(
- StringRef LHS, const std::vector<StringRef> &Candidates) {
+/// returns std::nullopt.
+static std::optional<StringRef>
+findSimilarStr(StringRef LHS, const std::vector<StringRef> &Candidates) {
// We need to check if `Candidates` has the exact case-insensitive string
// because the Levenshtein distance match does not care about it.
for (StringRef C : Candidates) {
@@ -291,7 +272,7 @@ static Optional<StringRef> findSimilarStr(
size_t Length = LHS.size();
size_t MaxDist = Length < 3 ? Length - 1 : Length / 3;
- Optional<std::pair<StringRef, size_t>> SimilarStr = None;
+ std::optional<std::pair<StringRef, size_t>> SimilarStr;
for (StringRef C : Candidates) {
size_t CurDist = LHS.edit_distance(C, true);
if (CurDist <= MaxDist) {
@@ -308,7 +289,7 @@ static Optional<StringRef> findSimilarStr(
if (SimilarStr) {
return SimilarStr->first;
} else {
- return None;
+ return std::nullopt;
}
}
@@ -456,7 +437,7 @@ void Preprocessor::SuggestTypoedDirective(const Token &Tok,
if (LangOpts.C2x || LangOpts.CPlusPlus2b)
Candidates.insert(Candidates.end(), {"elifdef", "elifndef"});
- if (Optional<StringRef> Sugg = findSimilarStr(Directive, Candidates)) {
+ if (std::optional<StringRef> Sugg = findSimilarStr(Directive, Candidates)) {
// Directive cannot be coming from macro.
assert(Tok.getLocation().isFileID());
CharSourceRange DirectiveRange = CharSourceRange::getCharRange(
@@ -492,8 +473,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
// lookup pointer.
assert(!SkippingExcludedConditionalBlock &&
"calling SkipExcludedConditionalBlock recursively");
- llvm::SaveAndRestore<bool> SARSkipping(SkippingExcludedConditionalBlock,
- true);
+ llvm::SaveAndRestore SARSkipping(SkippingExcludedConditionalBlock, true);
++NumSkipped;
assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?");
@@ -856,7 +836,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
Tok.getLocation());
}
-Module *Preprocessor::getModuleForLocation(SourceLocation Loc) {
+Module *Preprocessor::getModuleForLocation(SourceLocation Loc,
+ bool AllowTextual) {
if (!SourceMgr.isInMainFile(Loc)) {
// Try to determine the module of the include directive.
// FIXME: Look into directly passing the FileEntry from LookupFile instead.
@@ -864,7 +845,7 @@ Module *Preprocessor::getModuleForLocation(SourceLocation Loc) {
if (const FileEntry *EntryOfIncl = SourceMgr.getFileEntryForID(IDOfIncl)) {
// The include comes from an included file.
return HeaderInfo.getModuleMap()
- .findModuleForHeader(EntryOfIncl)
+ .findModuleForHeader(EntryOfIncl, AllowTextual)
.getModule();
}
}
@@ -879,7 +860,8 @@ Module *Preprocessor::getModuleForLocation(SourceLocation Loc) {
const FileEntry *
Preprocessor::getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
SourceLocation Loc) {
- Module *IncM = getModuleForLocation(IncLoc);
+ Module *IncM = getModuleForLocation(
+ IncLoc, LangOpts.ModulesValidateTextualHeaderIncludes);
// Walk up through the include stack, looking through textual headers of M
// until we hit a non-textual header that we can #include. (We assume textual
@@ -908,6 +890,10 @@ Preprocessor::getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
continue;
}
+ // Don't suggest explicitly excluded headers.
+ if (Header.getRole() == ModuleMap::ExcludedHeader)
+ continue;
+
// We'll suggest including textual headers below if they're
// include-guarded.
if (Header.getRole() & ModuleMap::TextualHeader)
@@ -943,17 +929,18 @@ Preprocessor::getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
return nullptr;
}
-Optional<FileEntryRef> Preprocessor::LookupFile(
+OptionalFileEntryRef Preprocessor::LookupFile(
SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
ConstSearchDirIterator FromDir, const FileEntry *FromFile,
ConstSearchDirIterator *CurDirArg, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath,
ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped,
- bool *IsFrameworkFound, bool SkipCache) {
+ bool *IsFrameworkFound, bool SkipCache, bool OpenFile, bool CacheFailures) {
ConstSearchDirIterator CurDirLocal = nullptr;
ConstSearchDirIterator &CurDir = CurDirArg ? *CurDirArg : CurDirLocal;
- Module *RequestingModule = getModuleForLocation(FilenameLoc);
+ Module *RequestingModule = getModuleForLocation(
+ FilenameLoc, LangOpts.ModulesValidateTextualHeaderIncludes);
bool RequestingModuleIsModuleInterface = !SourceMgr.isInMainFile(FilenameLoc);
// If the header lookup mechanism may be relative to the current inclusion
@@ -1007,7 +994,7 @@ Optional<FileEntryRef> Preprocessor::LookupFile(
// the include path until we find that file or run out of files.
ConstSearchDirIterator TmpCurDir = CurDir;
ConstSearchDirIterator TmpFromDir = nullptr;
- while (Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
+ while (OptionalFileEntryRef FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, TmpFromDir, &TmpCurDir,
Includers, SearchPath, RelativePath, RequestingModule,
SuggestedModule, /*IsMapped=*/nullptr,
@@ -1025,10 +1012,10 @@ Optional<FileEntryRef> Preprocessor::LookupFile(
}
// Do a standard file entry lookup.
- Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
+ OptionalFileEntryRef FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, FromDir, &CurDir, Includers, SearchPath,
RelativePath, RequestingModule, SuggestedModule, IsMapped,
- IsFrameworkFound, SkipCache, BuildSystemModule);
+ IsFrameworkFound, SkipCache, BuildSystemModule, OpenFile, CacheFailures);
if (FE) {
if (SuggestedModule && !LangOpts.AsmPreprocessor)
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
@@ -1043,7 +1030,7 @@ Optional<FileEntryRef> Preprocessor::LookupFile(
// headers on the #include stack and pass them to HeaderInfo.
if (IsFileLexer()) {
if ((CurFileEnt = CurPPLexer->getFileEntry())) {
- if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader(
+ if (OptionalFileEntryRef FE = HeaderInfo.LookupSubframeworkHeader(
Filename, CurFileEnt, SearchPath, RelativePath, RequestingModule,
SuggestedModule)) {
if (SuggestedModule && !LangOpts.AsmPreprocessor)
@@ -1058,7 +1045,7 @@ Optional<FileEntryRef> Preprocessor::LookupFile(
for (IncludeStackInfo &ISEntry : llvm::reverse(IncludeMacroStack)) {
if (IsFileLexer(ISEntry)) {
if ((CurFileEnt = ISEntry.ThePPLexer->getFileEntry())) {
- if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader(
+ if (OptionalFileEntryRef FE = HeaderInfo.LookupSubframeworkHeader(
Filename, CurFileEnt, SearchPath, RelativePath,
RequestingModule, SuggestedModule)) {
if (SuggestedModule && !LangOpts.AsmPreprocessor)
@@ -1072,7 +1059,7 @@ Optional<FileEntryRef> Preprocessor::LookupFile(
}
// Otherwise, we really couldn't find the file.
- return None;
+ return std::nullopt;
}
//===----------------------------------------------------------------------===//
@@ -1998,7 +1985,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
}
-Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
+OptionalFileEntryRef Preprocessor::LookupHeaderIncludeOrImport(
ConstSearchDirIterator *CurDir, StringRef &Filename,
SourceLocation FilenameLoc, CharSourceRange FilenameRange,
const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
@@ -2006,24 +1993,26 @@ Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
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,
+ OptionalFileEntryRef File = LookupFile(
+ FilenameLoc, LookupFilename, isAngled, LookupFrom, LookupFromFile, CurDir,
Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
&SuggestedModule, &IsMapped, &IsFrameworkFound);
if (File)
return File;
+ // Give the clients a chance to silently skip this include.
+ if (Callbacks && Callbacks->FileNotFound(Filename))
+ return std::nullopt;
+
if (SuppressIncludeNotFoundError)
- return None;
+ return std::nullopt;
// 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,
+ OptionalFileEntryRef File = LookupFile(
+ FilenameLoc, LookupFilename, false, LookupFrom, LookupFromFile, CurDir,
Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
&SuggestedModule, &IsMapped,
/*IsFrameworkFound=*/nullptr);
@@ -2052,9 +2041,9 @@ Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
StringRef TypoCorrectionName = CorrectTypoFilename(Filename);
StringRef TypoCorrectionLookupName = CorrectTypoFilename(LookupFilename);
- Optional<FileEntryRef> File = LookupFile(
- FilenameLoc, TypoCorrectionLookupName, isAngled, LookupFrom, LookupFromFile,
- CurDir, Callbacks ? &SearchPath : nullptr,
+ OptionalFileEntryRef File = LookupFile(
+ FilenameLoc, TypoCorrectionLookupName, isAngled, LookupFrom,
+ LookupFromFile, CurDir, Callbacks ? &SearchPath : nullptr,
Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
/*IsFrameworkFound=*/nullptr);
if (File) {
@@ -2090,7 +2079,7 @@ Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
<< CacheEntry.Directory->getName();
}
- return None;
+ return std::nullopt;
}
/// Handle either a #include-like directive or an import declaration that names
@@ -2177,7 +2166,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
BackslashStyle = llvm::sys::path::Style::windows;
}
- Optional<FileEntryRef> File = LookupHeaderIncludeOrImport(
+ OptionalFileEntryRef File = LookupHeaderIncludeOrImport(
&CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok,
IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile,
LookupFilename, RelativePath, SearchPath, SuggestedModule, isAngled);
@@ -2215,14 +2204,13 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
alreadyIncluded(*File))
Action = IncludeLimitReached;
- bool MaybeTranslateInclude = Action == Enter && File && SuggestedModule &&
- !isForModuleBuilding(SuggestedModule.getModule(),
- getLangOpts().CurrentModule,
- getLangOpts().ModuleName);
-
// FIXME: We do not have a good way to disambiguate C++ clang modules from
// C++ standard modules (other than use/non-use of Header Units).
Module *SM = SuggestedModule.getModule();
+
+ bool MaybeTranslateInclude =
+ Action == Enter && File && SM && !SM->isForBuilding(getLangOpts());
+
// Maybe a usable Header Unit
bool UsableHeaderUnit = false;
if (getLangOpts().CPlusPlusModules && SM && SM->isHeaderUnit()) {
@@ -2235,14 +2223,14 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
}
}
// Maybe a usable clang header module.
- bool UsableHeaderModule =
+ bool UsableClangHeaderModule =
(getLangOpts().CPlusPlusModules || getLangOpts().Modules) && SM &&
!SM->isHeaderUnit();
// Determine whether we should try to import the module for this #include, if
// there is one. Don't do so if precompiled module support is disabled or we
// are processing this module textually (because we're building the module).
- if (MaybeTranslateInclude && (UsableHeaderUnit || UsableHeaderModule)) {
+ if (MaybeTranslateInclude && (UsableHeaderUnit || UsableClangHeaderModule)) {
// If this include corresponds to a module but that module is
// unavailable, diagnose the situation and bail out.
// FIXME: Remove this; loadModule does the same check (but produces
@@ -2281,11 +2269,14 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
if (Imported) {
Action = Import;
} else if (Imported.isMissingExpected()) {
+ markClangModuleAsAffecting(
+ static_cast<Module *>(Imported)->getTopLevelModule());
// We failed to find a submodule that we assumed would exist (because it
// was in the directory of an umbrella header, for instance), but no
// actual module containing it exists (because the umbrella header is
// incomplete). Treat this as a textual inclusion.
SuggestedModule = ModuleMap::KnownHeader();
+ SM = nullptr;
} else if (Imported.isConfigMismatch()) {
// On a configuration mismatch, enter the header textually. We still know
// that it's part of the corresponding module.
@@ -2549,9 +2540,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// that behaves the same as the header would behave in a compilation using
// that PCH, which means we should enter the submodule. We need to teach
// the AST serialization layer to deal with the resulting AST.
- if (getLangOpts().CompilingPCH &&
- isForModuleBuilding(SM, getLangOpts().CurrentModule,
- getLangOpts().ModuleName))
+ if (getLangOpts().CompilingPCH && SM->isForBuilding(getLangOpts()))
return {ImportAction::None};
assert(!CurLexerSubmodule && "should not have marked this as a module yet");
diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp
index bd35689f18e7..aa411cfc5f2c 100644
--- a/clang/lib/Lex/PPExpressions.cpp
+++ b/clang/lib/Lex/PPExpressions.cpp
@@ -869,7 +869,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
/// to "!defined(X)" return X in IfNDefMacro.
Preprocessor::DirectiveEvalResult
Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
- SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true);
+ SaveAndRestore PPDir(ParsingIfOrElifDirective, true);
// Save the current state of 'DisableMacroExpansion' and reset it to false. If
// 'DisableMacroExpansion' is true, then we must be in a macro argument list
// in which case a directive is undefined behavior. We want macros to be able
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index 36d3aa59bb2f..66168467ecf5 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/Path.h"
+#include <optional>
using namespace clang;
@@ -75,7 +76,7 @@ bool Preprocessor::EnterSourceFile(FileID FID, ConstSearchDirIterator CurDir,
MaxIncludeStackDepth = IncludeMacroStack.size();
// Get the MemoryBuffer for this FID, if it fails, we fail.
- llvm::Optional<llvm::MemoryBufferRef> InputFile =
+ std::optional<llvm::MemoryBufferRef> InputFile =
getSourceManager().getBufferOrNone(FID, Loc);
if (!InputFile) {
SourceLocation FileStart = SourceMgr.getLocForStartOfFile(FID);
@@ -94,8 +95,8 @@ bool Preprocessor::EnterSourceFile(FileID FID, ConstSearchDirIterator CurDir,
Lexer *TheLexer = new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile);
if (getPreprocessorOpts().DependencyDirectivesForFile &&
FID != PredefinesFileID) {
- if (Optional<FileEntryRef> File = SourceMgr.getFileEntryRefForID(FID)) {
- if (Optional<ArrayRef<dependency_directives_scan::Directive>>
+ if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) {
+ if (std::optional<ArrayRef<dependency_directives_scan::Directive>>
DepDirectives =
getPreprocessorOpts().DependencyDirectivesForFile(*File)) {
TheLexer->DepDirectives = *DepDirectives;
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index f3be2107f985..bbc271e5611e 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -37,8 +37,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -54,6 +52,7 @@
#include <cstddef>
#include <cstring>
#include <ctime>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -285,7 +284,8 @@ void Preprocessor::dumpMacroInfo(const IdentifierInfo *II) {
// Dump module macros.
llvm::DenseSet<ModuleMacro*> Active;
- for (auto *MM : State ? State->getActiveModuleMacros(*this, II) : None)
+ for (auto *MM :
+ State ? State->getActiveModuleMacros(*this, II) : std::nullopt)
Active.insert(MM);
llvm::DenseSet<ModuleMacro*> Visited;
llvm::SmallVector<ModuleMacro *, 16> Worklist(Leaf.begin(), Leaf.end());
@@ -371,6 +371,8 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature");
Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension");
Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin");
+ Ident__has_constexpr_builtin =
+ RegisterBuiltinMacro(*this, "__has_constexpr_builtin");
Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute");
if (!getLangOpts().CPlusPlus)
Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute");
@@ -387,6 +389,10 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__is_target_os = RegisterBuiltinMacro(*this, "__is_target_os");
Ident__is_target_environment =
RegisterBuiltinMacro(*this, "__is_target_environment");
+ Ident__is_target_variant_os =
+ RegisterBuiltinMacro(*this, "__is_target_variant_os");
+ Ident__is_target_variant_environment =
+ RegisterBuiltinMacro(*this, "__is_target_variant_environment");
// Modules.
Ident__building_module = RegisterBuiltinMacro(*this, "__building_module");
@@ -1081,8 +1087,15 @@ void Preprocessor::removeCachedMacroExpandedTokensOfLastLexer() {
/// the identifier tokens inserted.
static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
Preprocessor &PP) {
- time_t TT = time(nullptr);
- struct tm *TM = localtime(&TT);
+ time_t TT;
+ std::tm *TM;
+ if (PP.getPreprocessorOpts().SourceDateEpoch) {
+ TT = *PP.getPreprocessorOpts().SourceDateEpoch;
+ TM = std::gmtime(&TT);
+ } else {
+ TT = std::time(nullptr);
+ TM = std::localtime(&TT);
+ }
static const char * const Months[] = {
"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
@@ -1091,8 +1104,11 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
{
SmallString<32> TmpBuffer;
llvm::raw_svector_ostream TmpStream(TmpBuffer);
- TmpStream << llvm::format("\"%s %2d %4d\"", Months[TM->tm_mon],
- TM->tm_mday, TM->tm_year + 1900);
+ if (TM)
+ TmpStream << llvm::format("\"%s %2d %4d\"", Months[TM->tm_mon],
+ TM->tm_mday, TM->tm_year + 1900);
+ else
+ TmpStream << "??? ?? ????";
Token TmpTok;
TmpTok.startToken();
PP.CreateString(TmpStream.str(), TmpTok);
@@ -1102,8 +1118,11 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc,
{
SmallString<32> TmpBuffer;
llvm::raw_svector_ostream TmpStream(TmpBuffer);
- TmpStream << llvm::format("\"%02d:%02d:%02d\"",
- TM->tm_hour, TM->tm_min, TM->tm_sec);
+ if (TM)
+ TmpStream << llvm::format("\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min,
+ TM->tm_sec);
+ else
+ TmpStream << "??:??:??";
Token TmpTok;
TmpTok.startToken();
PP.CreateString(TmpStream.str(), TmpTok);
@@ -1230,7 +1249,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok, IdentifierInfo *II,
return false;
// Search include directories.
- Optional<FileEntryRef> File =
+ OptionalFileEntryRef File =
PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
@@ -1282,7 +1301,7 @@ static void EvaluateFeatureLikeBuiltinMacro(llvm::raw_svector_ostream& OS,
unsigned ParenDepth = 1;
SourceLocation LParenLoc = Tok.getLocation();
- llvm::Optional<int> Result;
+ std::optional<int> Result;
Token ResultTok;
bool SuppressDiagnostic = false;
@@ -1326,10 +1345,10 @@ already_lexed:
// The last ')' has been reached; return the value if one found or
// a diagnostic and a dummy value.
if (Result) {
- OS << Result.value();
+ OS << *Result;
// For strict conformance to __has_cpp_attribute rules, use 'L'
// suffix for dated literals.
- if (Result.value() > 1)
+ if (*Result > 1)
OS << 'L';
} else {
OS << 0;
@@ -1428,9 +1447,47 @@ static bool isTargetEnvironment(const TargetInfo &TI,
const IdentifierInfo *II) {
std::string EnvName = (llvm::Twine("---") + II->getName().lower()).str();
llvm::Triple Env(EnvName);
+ // The unknown environment is matched only if
+ // '__is_target_environment(unknown)' is used.
+ if (Env.getEnvironment() == llvm::Triple::UnknownEnvironment &&
+ EnvName != "---unknown")
+ return false;
return TI.getTriple().getEnvironment() == Env.getEnvironment();
}
+/// Implements the __is_target_variant_os builtin macro.
+static bool isTargetVariantOS(const TargetInfo &TI, const IdentifierInfo *II) {
+ if (TI.getTriple().isOSDarwin()) {
+ const llvm::Triple *VariantTriple = TI.getDarwinTargetVariantTriple();
+ if (!VariantTriple)
+ return false;
+
+ std::string OSName =
+ (llvm::Twine("unknown-unknown-") + II->getName().lower()).str();
+ llvm::Triple OS(OSName);
+ if (OS.getOS() == llvm::Triple::Darwin) {
+ // Darwin matches macos, ios, etc.
+ return VariantTriple->isOSDarwin();
+ }
+ return VariantTriple->getOS() == OS.getOS();
+ }
+ return false;
+}
+
+/// Implements the __is_target_variant_environment builtin macro.
+static bool isTargetVariantEnvironment(const TargetInfo &TI,
+ const IdentifierInfo *II) {
+ if (TI.getTriple().isOSDarwin()) {
+ const llvm::Triple *VariantTriple = TI.getDarwinTargetVariantTriple();
+ if (!VariantTriple)
+ return false;
+ std::string EnvName = (llvm::Twine("---") + II->getName().lower()).str();
+ llvm::Triple Env(EnvName);
+ return VariantTriple->getEnvironment() == Env.getEnvironment();
+ }
+ return false;
+}
+
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
/// as a builtin macro, handle it and return the next token as 'Tok'.
void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
@@ -1556,22 +1613,24 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Diag(Tok.getLocation(), diag::warn_pp_date_time);
// MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be
// of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime.
-
- // Get the file that we are lexing out of. If we're currently lexing from
- // a macro, dig into the include stack.
- const FileEntry *CurFile = nullptr;
- PreprocessorLexer *TheLexer = getCurrentFileLexer();
-
- if (TheLexer)
- CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID());
-
const char *Result;
- if (CurFile) {
- time_t TT = CurFile->getModificationTime();
- struct tm *TM = localtime(&TT);
+ if (getPreprocessorOpts().SourceDateEpoch) {
+ time_t TT = *getPreprocessorOpts().SourceDateEpoch;
+ std::tm *TM = std::gmtime(&TT);
Result = asctime(TM);
} else {
- Result = "??? ??? ?? ??:??:?? ????\n";
+ // Get the file that we are lexing out of. If we're currently lexing from
+ // a macro, dig into the include stack.
+ const FileEntry *CurFile = nullptr;
+ if (PreprocessorLexer *TheLexer = getCurrentFileLexer())
+ CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID());
+ if (CurFile) {
+ time_t TT = CurFile->getModificationTime();
+ struct tm *TM = localtime(&TT);
+ Result = asctime(TM);
+ } else {
+ Result = "??? ??? ?? ??:??:?? ????\n";
+ }
}
// Surround the string with " and strip the trailing newline.
OS << '"' << StringRef(Result).drop_back() << '"';
@@ -1663,7 +1722,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
.Case("__array_rank", true)
.Case("__array_extent", true)
.Case("__reference_binds_to_temporary", true)
- .Case("__underlying_type", true)
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) .Case("__" #Trait, true)
+#include "clang/Basic/TransformTypeTraits.def"
.Default(false);
} else {
return llvm::StringSwitch<bool>(II->getName())
@@ -1677,9 +1737,23 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
.Case("__is_target_vendor", true)
.Case("__is_target_os", true)
.Case("__is_target_environment", true)
+ .Case("__is_target_variant_os", true)
+ .Case("__is_target_variant_environment", true)
.Default(false);
}
});
+ } else if (II == Ident__has_constexpr_builtin) {
+ EvaluateFeatureLikeBuiltinMacro(
+ OS, Tok, II, *this, false,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+ Tok, *this, diag::err_feature_check_malformed);
+ if (!II)
+ return false;
+ unsigned BuiltinOp = II->getBuiltinID();
+ return BuiltinOp != 0 &&
+ this->getBuiltinInfo().isConstantEvaluated(BuiltinOp);
+ });
} else if (II == Ident__is_identifier) {
EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false,
[](Token &Tok, bool &HasLexedNextToken) -> int {
@@ -1877,6 +1951,22 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
Tok, *this, diag::err_feature_check_malformed);
return II && isTargetEnvironment(getTargetInfo(), II);
});
+ } else if (II == Ident__is_target_variant_os) {
+ EvaluateFeatureLikeBuiltinMacro(
+ OS, Tok, II, *this, false,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+ Tok, *this, diag::err_feature_check_malformed);
+ return II && isTargetVariantOS(getTargetInfo(), II);
+ });
+ } else if (II == Ident__is_target_variant_environment) {
+ EvaluateFeatureLikeBuiltinMacro(
+ OS, Tok, II, *this, false,
+ [this](Token &Tok, bool &HasLexedNextToken) -> int {
+ IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+ Tok, *this, diag::err_feature_check_malformed);
+ return II && isTargetVariantEnvironment(getTargetInfo(), II);
+ });
} else {
llvm_unreachable("Unknown identifier!");
}
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index fb4f2dc45758..4da9d1603770 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -48,6 +48,7 @@
#include <cstddef>
#include <cstdint>
#include <limits>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -527,7 +528,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
return;
// Search include directories for this file.
- Optional<FileEntryRef> File =
+ OptionalFileEntryRef File =
LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
if (!File) {
@@ -1043,7 +1044,7 @@ struct PragmaDebugHandler : public PragmaHandler {
Token Tok;
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::identifier)) {
- PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
+ PP.Diag(Tok, diag::warn_pragma_debug_missing_command);
return;
}
IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -1181,6 +1182,23 @@ struct PragmaDebugHandler : public PragmaHandler {
PP.Diag(Tok, diag::warn_pragma_debug_unexpected_command)
<< DumpII->getName();
}
+ } else if (II->isStr("sloc_usage")) {
+ // An optional integer literal argument specifies the number of files to
+ // specifically report information about.
+ std::optional<unsigned> MaxNotes;
+ Token ArgToken;
+ PP.Lex(ArgToken);
+ uint64_t Value;
+ if (ArgToken.is(tok::numeric_constant) &&
+ PP.parseSimpleIntegerLiteral(ArgToken, Value)) {
+ MaxNotes = Value;
+ } else if (ArgToken.isNot(tok::eod)) {
+ PP.Diag(ArgToken, diag::warn_pragma_debug_unexpected_argument);
+ }
+
+ PP.Diag(Tok, diag::remark_sloc_usage);
+ PP.getSourceManager().noteSLocAddressSpaceUsage(PP.getDiagnostics(),
+ MaxNotes);
} else {
PP.Diag(Tok, diag::warn_pragma_debug_unexpected_command)
<< II->getName();
@@ -1940,6 +1958,15 @@ struct PragmaRegionHandler : public PragmaHandler {
}
};
+/// "\#pragma managed"
+/// "\#pragma managed(...)"
+/// "\#pragma unmanaged"
+/// MSVC ignores this pragma when not compiling using /clr, which clang doesn't
+/// support. We parse it and ignore it to avoid -Wunknown-pragma warnings.
+struct PragmaManagedHandler : public EmptyPragmaHandler {
+ PragmaManagedHandler(const char *pragma) : EmptyPragmaHandler(pragma) {}
+};
+
/// This handles parsing pragmas that take a macro name and optional message
static IdentifierInfo *HandleMacroAnnotationPragma(Preprocessor &PP, Token &Tok,
const char *Pragma,
@@ -2112,6 +2139,8 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler(new PragmaIncludeAliasHandler());
AddPragmaHandler(new PragmaHdrstopHandler());
AddPragmaHandler(new PragmaSystemHeaderHandler());
+ AddPragmaHandler(new PragmaManagedHandler("managed"));
+ AddPragmaHandler(new PragmaManagedHandler("unmanaged"));
}
// Pragmas added by plugins
diff --git a/clang/lib/Lex/PreprocessingRecord.cpp b/clang/lib/Lex/PreprocessingRecord.cpp
index 2146a7c04217..85eb57f61611 100644
--- a/clang/lib/Lex/PreprocessingRecord.cpp
+++ b/clang/lib/Lex/PreprocessingRecord.cpp
@@ -20,7 +20,6 @@
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Capacity.h"
@@ -31,6 +30,7 @@
#include <cstddef>
#include <cstring>
#include <iterator>
+#include <optional>
#include <utility>
#include <vector>
@@ -42,7 +42,7 @@ ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() =
InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
InclusionKind Kind, StringRef FileName,
bool InQuotes, bool ImportedModule,
- Optional<FileEntryRef> File,
+ OptionalFileEntryRef File,
SourceRange Range)
: PreprocessingDirective(InclusionDirectiveKind, Range), InQuotes(InQuotes),
Kind(Kind), ImportedModule(ImportedModule), File(File) {
@@ -112,10 +112,9 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
// See if the external source can see if the entity is in the file without
// deserializing it.
- Optional<bool> IsInFile =
- ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID);
- if (IsInFile)
- return IsInFile.value();
+ if (std::optional<bool> IsInFile =
+ ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID))
+ return *IsInFile;
// The external source did not provide a definite answer, go and deserialize
// the entity to check it.
@@ -476,15 +475,9 @@ void PreprocessingRecord::MacroUndefined(const Token &Id,
}
void PreprocessingRecord::InclusionDirective(
- SourceLocation HashLoc,
- const Token &IncludeTok,
- StringRef FileName,
- bool IsAngled,
- CharSourceRange FilenameRange,
- Optional<FileEntryRef> File,
- StringRef SearchPath,
- StringRef RelativePath,
- const Module *Imported,
+ SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+ bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
+ StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
InclusionDirective::InclusionKind Kind = InclusionDirective::Include;
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 5310db3c882b..fe9adb5685e3 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -58,7 +58,6 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -66,6 +65,7 @@
#include <algorithm>
#include <cassert>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -166,12 +166,6 @@ Preprocessor::~Preprocessor() {
IncludeMacroStack.clear();
- // Destroy any macro definitions.
- while (MacroInfoChain *I = MIChainHead) {
- MIChainHead = I->Next;
- I->~MacroInfoChain();
- }
-
// Free any cached macro expanders.
// This populates MacroArgCache, so all TokenLexers need to be destroyed
// before the code below that frees up the MacroArgCache list.
@@ -406,7 +400,7 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File,
assert(!CodeCompletionFile && "Already set");
// Load the actual file's contents.
- Optional<llvm::MemoryBufferRef> Buffer =
+ std::optional<llvm::MemoryBufferRef> Buffer =
SourceMgr.getMemoryBufferForFileOrNone(File);
if (!Buffer)
return true;
@@ -535,6 +529,13 @@ Module *Preprocessor::getCurrentModule() {
return getHeaderSearchInfo().lookupModule(getLangOpts().CurrentModule);
}
+Module *Preprocessor::getCurrentModuleImplementation() {
+ if (!getLangOpts().isCompilingModuleImplementation())
+ return nullptr;
+
+ return getHeaderSearchInfo().lookupModule(getLangOpts().ModuleName);
+}
+
//===----------------------------------------------------------------------===//
// Preprocessor Initialization Methods
//===----------------------------------------------------------------------===//
@@ -580,7 +581,7 @@ void Preprocessor::EnterMainSourceFile() {
if (!PPOpts->PCHThroughHeader.empty()) {
// Lookup and save the FileID for the through header. If it isn't found
// in the search path, it's a fatal error.
- Optional<FileEntryRef> File = LookupFile(
+ OptionalFileEntryRef File = LookupFile(
SourceLocation(), PPOpts->PCHThroughHeader,
/*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr,
/*CurDir=*/nullptr, /*SearchPath=*/nullptr, /*RelativePath=*/nullptr,
@@ -773,29 +774,6 @@ void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) {
Diag(Identifier,it->second) << Identifier.getIdentifierInfo();
}
-/// Returns a diagnostic message kind for reporting a future keyword as
-/// appropriate for the identifier and specified language.
-static diag::kind getFutureCompatDiagKind(const IdentifierInfo &II,
- const LangOptions &LangOpts) {
- assert(II.isFutureCompatKeyword() && "diagnostic should not be needed");
-
- if (LangOpts.CPlusPlus)
- return llvm::StringSwitch<diag::kind>(II.getName())
-#define CXX11_KEYWORD(NAME, FLAGS) \
- .Case(#NAME, diag::warn_cxx11_keyword)
-#define CXX20_KEYWORD(NAME, FLAGS) \
- .Case(#NAME, diag::warn_cxx20_keyword)
-#include "clang/Basic/TokenKinds.def"
- // char8_t is not modeled as a CXX20_KEYWORD because it's not
- // unconditionally enabled in C++20 mode. (It can be disabled
- // by -fno-char8_t.)
- .Case("char8_t", diag::warn_cxx20_keyword)
- ;
-
- llvm_unreachable(
- "Keyword not known to come from a newer Standard or proposed Standard");
-}
-
void Preprocessor::updateOutOfDateIdentifier(IdentifierInfo &II) const {
assert(II.isOutOfDate() && "not out of date");
getExternalSource()->updateOutOfDateIdentifier(II);
@@ -867,7 +845,7 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
// FIXME: This warning is disabled in cases where it shouldn't be, like
// "#define constexpr constexpr", "int constexpr;"
if (II.isFutureCompatKeyword() && !DisableMacroExpansion) {
- Diag(Identifier, getFutureCompatDiagKind(II, getLangOpts()))
+ Diag(Identifier, getIdentifierTable().getFutureCompatDiagKind(II, getLangOpts()))
<< II.getName();
// Don't diagnose this keyword again in this translation unit.
II.setIsFutureCompatKeyword(false);
@@ -894,7 +872,7 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
(getLangOpts().Modules || getLangOpts().DebuggerSupport) &&
CurLexerKind != CLK_CachingLexer) {
ModuleImportLoc = Identifier.getLocation();
- ModuleImportPath.clear();
+ NamedModuleImportPath.clear();
ModuleImportExpectsIdentifier = true;
CurLexerKind = CLK_LexAfterModuleImport;
}
@@ -939,57 +917,57 @@ void Preprocessor::Lex(Token &Result) {
Result.setIdentifierInfo(nullptr);
}
- // Update ImportSeqState to track our position within a C++20 import-seq
+ // Update StdCXXImportSeqState to track our position within a C++20 import-seq
// if this token is being produced as a result of phase 4 of translation.
// Update TrackGMFState to decide if we are currently in a Global Module
- // Fragment. GMF state updates should precede ImportSeq ones, since GMF state
- // depends on the prevailing ImportSeq state in two cases.
+ // Fragment. GMF state updates should precede StdCXXImportSeq ones, since GMF state
+ // depends on the prevailing StdCXXImportSeq state in two cases.
if (getLangOpts().CPlusPlusModules && LexLevel == 1 &&
!Result.getFlag(Token::IsReinjected)) {
switch (Result.getKind()) {
case tok::l_paren: case tok::l_square: case tok::l_brace:
- ImportSeqState.handleOpenBracket();
+ StdCXXImportSeqState.handleOpenBracket();
break;
case tok::r_paren: case tok::r_square:
- ImportSeqState.handleCloseBracket();
+ StdCXXImportSeqState.handleCloseBracket();
break;
case tok::r_brace:
- ImportSeqState.handleCloseBrace();
+ StdCXXImportSeqState.handleCloseBrace();
break;
// This token is injected to represent the translation of '#include "a.h"'
// into "import a.h;". Mimic the notional ';'.
case tok::annot_module_include:
case tok::semi:
TrackGMFState.handleSemi();
- ImportSeqState.handleSemi();
+ StdCXXImportSeqState.handleSemi();
break;
case tok::header_name:
case tok::annot_header_unit:
- ImportSeqState.handleHeaderName();
+ StdCXXImportSeqState.handleHeaderName();
break;
case tok::kw_export:
TrackGMFState.handleExport();
- ImportSeqState.handleExport();
+ StdCXXImportSeqState.handleExport();
break;
case tok::identifier:
if (Result.getIdentifierInfo()->isModulesImport()) {
- TrackGMFState.handleImport(ImportSeqState.afterTopLevelSeq());
- ImportSeqState.handleImport();
- if (ImportSeqState.afterImportSeq()) {
+ TrackGMFState.handleImport(StdCXXImportSeqState.afterTopLevelSeq());
+ StdCXXImportSeqState.handleImport();
+ if (StdCXXImportSeqState.afterImportSeq()) {
ModuleImportLoc = Result.getLocation();
- ModuleImportPath.clear();
+ NamedModuleImportPath.clear();
ModuleImportExpectsIdentifier = true;
CurLexerKind = CLK_LexAfterModuleImport;
}
break;
} else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) {
- TrackGMFState.handleModule(ImportSeqState.afterTopLevelSeq());
+ TrackGMFState.handleModule(StdCXXImportSeqState.afterTopLevelSeq());
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
TrackGMFState.handleMisc();
- ImportSeqState.handleMisc();
+ StdCXXImportSeqState.handleMisc();
break;
}
}
@@ -1170,7 +1148,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
// For now, we only support header-name imports in C++20 mode.
// FIXME: Should we allow this in all language modes that support an import
// declaration as an extension?
- if (ModuleImportPath.empty() && getLangOpts().CPlusPlusModules) {
+ if (NamedModuleImportPath.empty() && getLangOpts().CPlusPlusModules) {
if (LexHeaderName(Result))
return true;
} else {
@@ -1232,7 +1210,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
Suffix.back().setLocation(SemiLoc);
Suffix.back().setAnnotationEndLoc(SemiLoc);
Suffix.back().setAnnotationValue(Action.ModuleForHeader);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ImportAction::ModuleImport:
case ImportAction::HeaderUnitImport:
@@ -1266,7 +1244,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
if (ModuleImportExpectsIdentifier && Result.getKind() == tok::identifier) {
// We expected to see an identifier here, and we did; continue handling
// identifiers.
- ModuleImportPath.push_back(std::make_pair(Result.getIdentifierInfo(),
+ NamedModuleImportPath.push_back(std::make_pair(Result.getIdentifierInfo(),
Result.getLocation()));
ModuleImportExpectsIdentifier = false;
CurLexerKind = CLK_LexAfterModuleImport;
@@ -1283,7 +1261,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
}
// If we didn't recognize a module name at all, this is not a (valid) import.
- if (ModuleImportPath.empty() || Result.is(tok::eof))
+ if (NamedModuleImportPath.empty() || Result.is(tok::eof))
return true;
// Consume the pp-import-suffix and expand any macros in it now, if we're not
@@ -1306,28 +1284,28 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
// FIXME: Is this the right level to be performing this transformation?
std::string FlatModuleName;
if (getLangOpts().ModulesTS || getLangOpts().CPlusPlusModules) {
- for (auto &Piece : ModuleImportPath) {
+ for (auto &Piece : NamedModuleImportPath) {
if (!FlatModuleName.empty())
FlatModuleName += ".";
FlatModuleName += Piece.first->getName();
}
- SourceLocation FirstPathLoc = ModuleImportPath[0].second;
- ModuleImportPath.clear();
- ModuleImportPath.push_back(
+ SourceLocation FirstPathLoc = NamedModuleImportPath[0].second;
+ NamedModuleImportPath.clear();
+ NamedModuleImportPath.push_back(
std::make_pair(getIdentifierInfo(FlatModuleName), FirstPathLoc));
}
Module *Imported = nullptr;
if (getLangOpts().Modules) {
Imported = TheModuleLoader.loadModule(ModuleImportLoc,
- ModuleImportPath,
+ NamedModuleImportPath,
Module::Hidden,
/*IsInclusionDirective=*/false);
if (Imported)
makeModuleVisible(Imported, SemiLoc);
}
if (Callbacks)
- Callbacks->moduleImport(ModuleImportLoc, ModuleImportPath, Imported);
+ Callbacks->moduleImport(ModuleImportLoc, NamedModuleImportPath, Imported);
if (!Suffix.empty()) {
EnterTokens(Suffix);
diff --git a/clang/lib/Lex/TokenConcatenation.cpp b/clang/lib/Lex/TokenConcatenation.cpp
index f6b005d9e19c..1b3201bd805b 100644
--- a/clang/lib/Lex/TokenConcatenation.cpp
+++ b/clang/lib/Lex/TokenConcatenation.cpp
@@ -240,7 +240,7 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
// it as an identifier.
if (!PrevTok.hasUDSuffix())
return false;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::identifier: // id+id or id+number or id+L"foo".
// id+'.'... will not append.
if (Tok.is(tok::numeric_constant))
diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index efda6d0046fa..c6968b9f417e 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -25,11 +25,13 @@
#include "clang/Lex/Token.h"
#include "clang/Lex/VariadicMacroSupport.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include <cassert>
#include <cstring>
+#include <optional>
using namespace clang;
@@ -203,7 +205,7 @@ void TokenLexer::stringifyVAOPTContents(
assert(CurTokenIdx != 0 &&
"Can not have __VAOPT__ contents begin with a ##");
Token &LHS = VAOPTTokens[CurTokenIdx - 1];
- pasteTokens(LHS, llvm::makeArrayRef(VAOPTTokens, NumVAOptTokens),
+ pasteTokens(LHS, llvm::ArrayRef(VAOPTTokens, NumVAOptTokens),
CurTokenIdx);
// Replace the token prior to the first ## in this iteration.
ConcatenatedVAOPTResultToks.back() = LHS;
@@ -247,7 +249,7 @@ void TokenLexer::ExpandFunctionArguments() {
// we install the newly expanded sequence as the new 'Tokens' list.
bool MadeChange = false;
- Optional<bool> CalledWithVariadicArguments;
+ std::optional<bool> CalledWithVariadicArguments;
VAOptExpansionContext VCtx(PP);
@@ -721,7 +723,7 @@ bool TokenLexer::Lex(Token &Tok) {
}
bool TokenLexer::pasteTokens(Token &Tok) {
- return pasteTokens(Tok, llvm::makeArrayRef(Tokens, NumTokens), CurTokenIdx);
+ return pasteTokens(Tok, llvm::ArrayRef(Tokens, NumTokens), CurTokenIdx);
}
/// LHSTok is the LHS of a ## operator, and CurTokenIdx is the ##
@@ -984,65 +986,71 @@ TokenLexer::getExpansionLocForMacroDefLoc(SourceLocation loc) const {
/// \arg begin_tokens will be updated to a position past all the found
/// consecutive tokens.
static void updateConsecutiveMacroArgTokens(SourceManager &SM,
- SourceLocation InstLoc,
+ SourceLocation ExpandLoc,
Token *&begin_tokens,
Token * end_tokens) {
- assert(begin_tokens < end_tokens);
-
- SourceLocation FirstLoc = begin_tokens->getLocation();
- SourceLocation CurLoc = FirstLoc;
-
- // Compare the source location offset of tokens and group together tokens that
- // are close, even if their locations point to different FileIDs. e.g.
- //
- // |bar | foo | cake | (3 tokens from 3 consecutive FileIDs)
- // ^ ^
- // |bar foo cake| (one SLocEntry chunk for all tokens)
- //
- // we can perform this "merge" since the token's spelling location depends
- // on the relative offset.
-
- Token *NextTok = begin_tokens + 1;
- for (; NextTok < end_tokens; ++NextTok) {
- SourceLocation NextLoc = NextTok->getLocation();
- if (CurLoc.isFileID() != NextLoc.isFileID())
- break; // Token from different kind of FileID.
-
- SourceLocation::IntTy RelOffs;
- if (!SM.isInSameSLocAddrSpace(CurLoc, NextLoc, &RelOffs))
- break; // Token from different local/loaded location.
- // Check that token is not before the previous token or more than 50
- // "characters" away.
- if (RelOffs < 0 || RelOffs > 50)
- break;
-
- if (CurLoc.isMacroID() && !SM.isWrittenInSameFile(CurLoc, NextLoc))
- break; // Token from a different macro.
-
- CurLoc = NextLoc;
+ assert(begin_tokens + 1 < end_tokens);
+ SourceLocation BeginLoc = begin_tokens->getLocation();
+ llvm::MutableArrayRef<Token> All(begin_tokens, end_tokens);
+ llvm::MutableArrayRef<Token> Partition;
+
+ auto NearLast = [&, Last = BeginLoc](SourceLocation Loc) mutable {
+ // The maximum distance between two consecutive tokens in a partition.
+ // This is an important trick to avoid using too much SourceLocation address
+ // space!
+ static constexpr SourceLocation::IntTy MaxDistance = 50;
+ auto Distance = Loc.getRawEncoding() - Last.getRawEncoding();
+ Last = Loc;
+ return Distance <= MaxDistance;
+ };
+
+ // Partition the tokens by their FileID.
+ // This is a hot function, and calling getFileID can be expensive, the
+ // implementation is optimized by reducing the number of getFileID.
+ if (BeginLoc.isFileID()) {
+ // Consecutive tokens not written in macros must be from the same file.
+ // (Neither #include nor eof can occur inside a macro argument.)
+ Partition = All.take_while([&](const Token &T) {
+ return T.getLocation().isFileID() && NearLast(T.getLocation());
+ });
+ } else {
+ // Call getFileID once to calculate the bounds, and use the cheaper
+ // sourcelocation-against-bounds comparison.
+ FileID BeginFID = SM.getFileID(BeginLoc);
+ SourceLocation Limit =
+ SM.getComposedLoc(BeginFID, SM.getFileIDSize(BeginFID));
+ Partition = All.take_while([&](const Token &T) {
+ return T.getLocation() >= BeginLoc && T.getLocation() < Limit &&
+ NearLast(T.getLocation());
+ });
}
+ assert(!Partition.empty());
// For the consecutive tokens, find the length of the SLocEntry to contain
// all of them.
- Token &LastConsecutiveTok = *(NextTok-1);
- SourceLocation::IntTy LastRelOffs = 0;
- SM.isInSameSLocAddrSpace(FirstLoc, LastConsecutiveTok.getLocation(),
- &LastRelOffs);
SourceLocation::UIntTy FullLength =
- LastRelOffs + LastConsecutiveTok.getLength();
-
+ Partition.back().getEndLoc().getRawEncoding() -
+ Partition.front().getLocation().getRawEncoding();
// Create a macro expansion SLocEntry that will "contain" all of the tokens.
SourceLocation Expansion =
- SM.createMacroArgExpansionLoc(FirstLoc, InstLoc,FullLength);
-
+ SM.createMacroArgExpansionLoc(BeginLoc, ExpandLoc, FullLength);
+
+#ifdef EXPENSIVE_CHECKS
+ assert(llvm::all_of(Partition.drop_front(),
+ [&SM, ID = SM.getFileID(Partition.front().getLocation())](
+ const Token &T) {
+ return ID == SM.getFileID(T.getLocation());
+ }) &&
+ "Must have the same FIleID!");
+#endif
// Change the location of the tokens from the spelling location to the new
// expanded location.
- for (; begin_tokens < NextTok; ++begin_tokens) {
- Token &Tok = *begin_tokens;
- SourceLocation::IntTy RelOffs = 0;
- SM.isInSameSLocAddrSpace(FirstLoc, Tok.getLocation(), &RelOffs);
- Tok.setLocation(Expansion.getLocWithOffset(RelOffs));
+ for (Token& T : Partition) {
+ SourceLocation::IntTy RelativeOffset =
+ T.getLocation().getRawEncoding() - BeginLoc.getRawEncoding();
+ T.setLocation(Expansion.getLocWithOffset(RelativeOffset));
}
+ begin_tokens = &Partition.back() + 1;
}
/// Creates SLocEntries and updates the locations of macro argument
@@ -1055,7 +1063,7 @@ void TokenLexer::updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc,
Token *end_tokens) {
SourceManager &SM = PP.getSourceManager();
- SourceLocation InstLoc =
+ SourceLocation ExpandLoc =
getExpansionLocForMacroDefLoc(ArgIdSpellLoc);
while (begin_tokens < end_tokens) {
@@ -1063,12 +1071,12 @@ void TokenLexer::updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc,
if (end_tokens - begin_tokens == 1) {
Token &Tok = *begin_tokens;
Tok.setLocation(SM.createMacroArgExpansionLoc(Tok.getLocation(),
- InstLoc,
+ ExpandLoc,
Tok.getLength()));
return;
}
- updateConsecutiveMacroArgTokens(SM, InstLoc, begin_tokens, end_tokens);
+ updateConsecutiveMacroArgTokens(SM, ExpandLoc, begin_tokens, end_tokens);
}
}
diff --git a/clang/lib/Lex/UnicodeCharSets.h b/clang/lib/Lex/UnicodeCharSets.h
index e79a85bc72b7..5316d2540b76 100644
--- a/clang/lib/Lex/UnicodeCharSets.h
+++ b/clang/lib/Lex/UnicodeCharSets.h
@@ -10,7 +10,7 @@
#include "llvm/Support/UnicodeCharRanges.h"
-// Unicode 14 XID_Start
+// Unicode 15.0 XID_Start
static const llvm::sys::UnicodeCharRange XIDStartRanges[] = {
{0x0041, 0x005A}, {0x0061, 0x007A}, {0x00AA, 0x00AA},
{0x00B5, 0x00B5}, {0x00BA, 0x00BA}, {0x00C0, 0x00D6},
@@ -170,69 +170,72 @@ static const llvm::sys::UnicodeCharRange XIDStartRanges[] = {
{0x11144, 0x11144}, {0x11147, 0x11147}, {0x11150, 0x11172},
{0x11176, 0x11176}, {0x11183, 0x111B2}, {0x111C1, 0x111C4},
{0x111DA, 0x111DA}, {0x111DC, 0x111DC}, {0x11200, 0x11211},
- {0x11213, 0x1122B}, {0x11280, 0x11286}, {0x11288, 0x11288},
- {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, {0x1129F, 0x112A8},
- {0x112B0, 0x112DE}, {0x11305, 0x1130C}, {0x1130F, 0x11310},
- {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333},
- {0x11335, 0x11339}, {0x1133D, 0x1133D}, {0x11350, 0x11350},
- {0x1135D, 0x11361}, {0x11400, 0x11434}, {0x11447, 0x1144A},
- {0x1145F, 0x11461}, {0x11480, 0x114AF}, {0x114C4, 0x114C5},
- {0x114C7, 0x114C7}, {0x11580, 0x115AE}, {0x115D8, 0x115DB},
- {0x11600, 0x1162F}, {0x11644, 0x11644}, {0x11680, 0x116AA},
- {0x116B8, 0x116B8}, {0x11700, 0x1171A}, {0x11740, 0x11746},
- {0x11800, 0x1182B}, {0x118A0, 0x118DF}, {0x118FF, 0x11906},
- {0x11909, 0x11909}, {0x1190C, 0x11913}, {0x11915, 0x11916},
- {0x11918, 0x1192F}, {0x1193F, 0x1193F}, {0x11941, 0x11941},
- {0x119A0, 0x119A7}, {0x119AA, 0x119D0}, {0x119E1, 0x119E1},
- {0x119E3, 0x119E3}, {0x11A00, 0x11A00}, {0x11A0B, 0x11A32},
- {0x11A3A, 0x11A3A}, {0x11A50, 0x11A50}, {0x11A5C, 0x11A89},
- {0x11A9D, 0x11A9D}, {0x11AB0, 0x11AF8}, {0x11C00, 0x11C08},
- {0x11C0A, 0x11C2E}, {0x11C40, 0x11C40}, {0x11C72, 0x11C8F},
- {0x11D00, 0x11D06}, {0x11D08, 0x11D09}, {0x11D0B, 0x11D30},
- {0x11D46, 0x11D46}, {0x11D60, 0x11D65}, {0x11D67, 0x11D68},
- {0x11D6A, 0x11D89}, {0x11D98, 0x11D98}, {0x11EE0, 0x11EF2},
- {0x11FB0, 0x11FB0}, {0x12000, 0x12399}, {0x12400, 0x1246E},
- {0x12480, 0x12543}, {0x12F90, 0x12FF0}, {0x13000, 0x1342E},
- {0x14400, 0x14646}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E},
- {0x16A70, 0x16ABE}, {0x16AD0, 0x16AED}, {0x16B00, 0x16B2F},
- {0x16B40, 0x16B43}, {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F},
- {0x16E40, 0x16E7F}, {0x16F00, 0x16F4A}, {0x16F50, 0x16F50},
- {0x16F93, 0x16F9F}, {0x16FE0, 0x16FE1}, {0x16FE3, 0x16FE3},
- {0x17000, 0x187F7}, {0x18800, 0x18CD5}, {0x18D00, 0x18D08},
- {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1AFFD, 0x1AFFE},
- {0x1B000, 0x1B122}, {0x1B150, 0x1B152}, {0x1B164, 0x1B167},
- {0x1B170, 0x1B2FB}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C},
- {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1D400, 0x1D454},
- {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F}, {0x1D4A2, 0x1D4A2},
- {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9},
- {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505},
- {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C},
- {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544},
- {0x1D546, 0x1D546}, {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5},
- {0x1D6A8, 0x1D6C0}, {0x1D6C2, 0x1D6DA}, {0x1D6DC, 0x1D6FA},
- {0x1D6FC, 0x1D714}, {0x1D716, 0x1D734}, {0x1D736, 0x1D74E},
- {0x1D750, 0x1D76E}, {0x1D770, 0x1D788}, {0x1D78A, 0x1D7A8},
- {0x1D7AA, 0x1D7C2}, {0x1D7C4, 0x1D7CB}, {0x1DF00, 0x1DF1E},
+ {0x11213, 0x1122B}, {0x1123F, 0x11240}, {0x11280, 0x11286},
+ {0x11288, 0x11288}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D},
+ {0x1129F, 0x112A8}, {0x112B0, 0x112DE}, {0x11305, 0x1130C},
+ {0x1130F, 0x11310}, {0x11313, 0x11328}, {0x1132A, 0x11330},
+ {0x11332, 0x11333}, {0x11335, 0x11339}, {0x1133D, 0x1133D},
+ {0x11350, 0x11350}, {0x1135D, 0x11361}, {0x11400, 0x11434},
+ {0x11447, 0x1144A}, {0x1145F, 0x11461}, {0x11480, 0x114AF},
+ {0x114C4, 0x114C5}, {0x114C7, 0x114C7}, {0x11580, 0x115AE},
+ {0x115D8, 0x115DB}, {0x11600, 0x1162F}, {0x11644, 0x11644},
+ {0x11680, 0x116AA}, {0x116B8, 0x116B8}, {0x11700, 0x1171A},
+ {0x11740, 0x11746}, {0x11800, 0x1182B}, {0x118A0, 0x118DF},
+ {0x118FF, 0x11906}, {0x11909, 0x11909}, {0x1190C, 0x11913},
+ {0x11915, 0x11916}, {0x11918, 0x1192F}, {0x1193F, 0x1193F},
+ {0x11941, 0x11941}, {0x119A0, 0x119A7}, {0x119AA, 0x119D0},
+ {0x119E1, 0x119E1}, {0x119E3, 0x119E3}, {0x11A00, 0x11A00},
+ {0x11A0B, 0x11A32}, {0x11A3A, 0x11A3A}, {0x11A50, 0x11A50},
+ {0x11A5C, 0x11A89}, {0x11A9D, 0x11A9D}, {0x11AB0, 0x11AF8},
+ {0x11C00, 0x11C08}, {0x11C0A, 0x11C2E}, {0x11C40, 0x11C40},
+ {0x11C72, 0x11C8F}, {0x11D00, 0x11D06}, {0x11D08, 0x11D09},
+ {0x11D0B, 0x11D30}, {0x11D46, 0x11D46}, {0x11D60, 0x11D65},
+ {0x11D67, 0x11D68}, {0x11D6A, 0x11D89}, {0x11D98, 0x11D98},
+ {0x11EE0, 0x11EF2}, {0x11F02, 0x11F02}, {0x11F04, 0x11F10},
+ {0x11F12, 0x11F33}, {0x11FB0, 0x11FB0}, {0x12000, 0x12399},
+ {0x12400, 0x1246E}, {0x12480, 0x12543}, {0x12F90, 0x12FF0},
+ {0x13000, 0x1342F}, {0x13441, 0x13446}, {0x14400, 0x14646},
+ {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A70, 0x16ABE},
+ {0x16AD0, 0x16AED}, {0x16B00, 0x16B2F}, {0x16B40, 0x16B43},
+ {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16E40, 0x16E7F},
+ {0x16F00, 0x16F4A}, {0x16F50, 0x16F50}, {0x16F93, 0x16F9F},
+ {0x16FE0, 0x16FE1}, {0x16FE3, 0x16FE3}, {0x17000, 0x187F7},
+ {0x18800, 0x18CD5}, {0x18D00, 0x18D08}, {0x1AFF0, 0x1AFF3},
+ {0x1AFF5, 0x1AFFB}, {0x1AFFD, 0x1AFFE}, {0x1B000, 0x1B122},
+ {0x1B132, 0x1B132}, {0x1B150, 0x1B152}, {0x1B155, 0x1B155},
+ {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1BC00, 0x1BC6A},
+ {0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99},
+ {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F},
+ {0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC},
+ {0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3},
+ {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514},
+ {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E},
+ {0x1D540, 0x1D544}, {0x1D546, 0x1D546}, {0x1D54A, 0x1D550},
+ {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D6C0}, {0x1D6C2, 0x1D6DA},
+ {0x1D6DC, 0x1D6FA}, {0x1D6FC, 0x1D714}, {0x1D716, 0x1D734},
+ {0x1D736, 0x1D74E}, {0x1D750, 0x1D76E}, {0x1D770, 0x1D788},
+ {0x1D78A, 0x1D7A8}, {0x1D7AA, 0x1D7C2}, {0x1D7C4, 0x1D7CB},
+ {0x1DF00, 0x1DF1E}, {0x1DF25, 0x1DF2A}, {0x1E030, 0x1E06D},
{0x1E100, 0x1E12C}, {0x1E137, 0x1E13D}, {0x1E14E, 0x1E14E},
- {0x1E290, 0x1E2AD}, {0x1E2C0, 0x1E2EB}, {0x1E7E0, 0x1E7E6},
- {0x1E7E8, 0x1E7EB}, {0x1E7ED, 0x1E7EE}, {0x1E7F0, 0x1E7FE},
- {0x1E800, 0x1E8C4}, {0x1E900, 0x1E943}, {0x1E94B, 0x1E94B},
- {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22},
- {0x1EE24, 0x1EE24}, {0x1EE27, 0x1EE27}, {0x1EE29, 0x1EE32},
- {0x1EE34, 0x1EE37}, {0x1EE39, 0x1EE39}, {0x1EE3B, 0x1EE3B},
- {0x1EE42, 0x1EE42}, {0x1EE47, 0x1EE47}, {0x1EE49, 0x1EE49},
- {0x1EE4B, 0x1EE4B}, {0x1EE4D, 0x1EE4F}, {0x1EE51, 0x1EE52},
- {0x1EE54, 0x1EE54}, {0x1EE57, 0x1EE57}, {0x1EE59, 0x1EE59},
- {0x1EE5B, 0x1EE5B}, {0x1EE5D, 0x1EE5D}, {0x1EE5F, 0x1EE5F},
- {0x1EE61, 0x1EE62}, {0x1EE64, 0x1EE64}, {0x1EE67, 0x1EE6A},
- {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C},
- {0x1EE7E, 0x1EE7E}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B},
- {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB},
- {0x20000, 0x2A6DF}, {0x2A700, 0x2B738}, {0x2B740, 0x2B81D},
- {0x2B820, 0x2CEA1}, {0x2CEB0, 0x2EBE0}, {0x2F800, 0x2FA1D},
- {0x30000, 0x3134A}};
-
-// Unicode 14 XID_Continue, excluding XID_Start
+ {0x1E290, 0x1E2AD}, {0x1E2C0, 0x1E2EB}, {0x1E4D0, 0x1E4EB},
+ {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB}, {0x1E7ED, 0x1E7EE},
+ {0x1E7F0, 0x1E7FE}, {0x1E800, 0x1E8C4}, {0x1E900, 0x1E943},
+ {0x1E94B, 0x1E94B}, {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F},
+ {0x1EE21, 0x1EE22}, {0x1EE24, 0x1EE24}, {0x1EE27, 0x1EE27},
+ {0x1EE29, 0x1EE32}, {0x1EE34, 0x1EE37}, {0x1EE39, 0x1EE39},
+ {0x1EE3B, 0x1EE3B}, {0x1EE42, 0x1EE42}, {0x1EE47, 0x1EE47},
+ {0x1EE49, 0x1EE49}, {0x1EE4B, 0x1EE4B}, {0x1EE4D, 0x1EE4F},
+ {0x1EE51, 0x1EE52}, {0x1EE54, 0x1EE54}, {0x1EE57, 0x1EE57},
+ {0x1EE59, 0x1EE59}, {0x1EE5B, 0x1EE5B}, {0x1EE5D, 0x1EE5D},
+ {0x1EE5F, 0x1EE5F}, {0x1EE61, 0x1EE62}, {0x1EE64, 0x1EE64},
+ {0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77},
+ {0x1EE79, 0x1EE7C}, {0x1EE7E, 0x1EE7E}, {0x1EE80, 0x1EE89},
+ {0x1EE8B, 0x1EE9B}, {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9},
+ {0x1EEAB, 0x1EEBB}, {0x20000, 0x2A6DF}, {0x2A700, 0x2B739},
+ {0x2B740, 0x2B81D}, {0x2B820, 0x2CEA1}, {0x2CEB0, 0x2EBE0},
+ {0x2F800, 0x2FA1D}, {0x30000, 0x3134A}, {0x31350, 0x323AF}};
+
+// Unicode 15.0 XID_Continue, excluding XID_Start
// The Unicode Property XID_Continue is a super set of XID_Start.
// To save Space, the table below only contains the codepoints
// that are not also in XID_Start.
@@ -268,64 +271,65 @@ static const llvm::sys::UnicodeCharRange XIDContinueRanges[] = {
{0x0C66, 0x0C6F}, {0x0C81, 0x0C83}, {0x0CBC, 0x0CBC},
{0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD},
{0x0CD5, 0x0CD6}, {0x0CE2, 0x0CE3}, {0x0CE6, 0x0CEF},
- {0x0D00, 0x0D03}, {0x0D3B, 0x0D3C}, {0x0D3E, 0x0D44},
- {0x0D46, 0x0D48}, {0x0D4A, 0x0D4D}, {0x0D57, 0x0D57},
- {0x0D62, 0x0D63}, {0x0D66, 0x0D6F}, {0x0D81, 0x0D83},
- {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4}, {0x0DD6, 0x0DD6},
- {0x0DD8, 0x0DDF}, {0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF3},
- {0x0E31, 0x0E31}, {0x0E33, 0x0E3A}, {0x0E47, 0x0E4E},
- {0x0E50, 0x0E59}, {0x0EB1, 0x0EB1}, {0x0EB3, 0x0EBC},
- {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9}, {0x0F18, 0x0F19},
- {0x0F20, 0x0F29}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37},
- {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F}, {0x0F71, 0x0F84},
- {0x0F86, 0x0F87}, {0x0F8D, 0x0F97}, {0x0F99, 0x0FBC},
- {0x0FC6, 0x0FC6}, {0x102B, 0x103E}, {0x1040, 0x1049},
- {0x1056, 0x1059}, {0x105E, 0x1060}, {0x1062, 0x1064},
- {0x1067, 0x106D}, {0x1071, 0x1074}, {0x1082, 0x108D},
- {0x108F, 0x109D}, {0x135D, 0x135F}, {0x1369, 0x1371},
- {0x1712, 0x1715}, {0x1732, 0x1734}, {0x1752, 0x1753},
- {0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD},
- {0x17E0, 0x17E9}, {0x180B, 0x180D}, {0x180F, 0x1819},
- {0x18A9, 0x18A9}, {0x1920, 0x192B}, {0x1930, 0x193B},
- {0x1946, 0x194F}, {0x19D0, 0x19DA}, {0x1A17, 0x1A1B},
- {0x1A55, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A89},
- {0x1A90, 0x1A99}, {0x1AB0, 0x1ABD}, {0x1ABF, 0x1ACE},
- {0x1B00, 0x1B04}, {0x1B34, 0x1B44}, {0x1B50, 0x1B59},
- {0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, {0x1BA1, 0x1BAD},
- {0x1BB0, 0x1BB9}, {0x1BE6, 0x1BF3}, {0x1C24, 0x1C37},
- {0x1C40, 0x1C49}, {0x1C50, 0x1C59}, {0x1CD0, 0x1CD2},
- {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF4, 0x1CF4},
- {0x1CF7, 0x1CF9}, {0x1DC0, 0x1DFF}, {0x203F, 0x2040},
- {0x2054, 0x2054}, {0x20D0, 0x20DC}, {0x20E1, 0x20E1},
- {0x20E5, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F},
- {0x2DE0, 0x2DFF}, {0x302A, 0x302F}, {0x3099, 0x309A},
- {0xA620, 0xA629}, {0xA66F, 0xA66F}, {0xA674, 0xA67D},
- {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA802, 0xA802},
- {0xA806, 0xA806}, {0xA80B, 0xA80B}, {0xA823, 0xA827},
- {0xA82C, 0xA82C}, {0xA880, 0xA881}, {0xA8B4, 0xA8C5},
- {0xA8D0, 0xA8D9}, {0xA8E0, 0xA8F1}, {0xA8FF, 0xA909},
- {0xA926, 0xA92D}, {0xA947, 0xA953}, {0xA980, 0xA983},
- {0xA9B3, 0xA9C0}, {0xA9D0, 0xA9D9}, {0xA9E5, 0xA9E5},
- {0xA9F0, 0xA9F9}, {0xAA29, 0xAA36}, {0xAA43, 0xAA43},
- {0xAA4C, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA7B, 0xAA7D},
- {0xAAB0, 0xAAB0}, {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8},
- {0xAABE, 0xAABF}, {0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF},
- {0xAAF5, 0xAAF6}, {0xABE3, 0xABEA}, {0xABEC, 0xABED},
- {0xABF0, 0xABF9}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F},
- {0xFE20, 0xFE2F}, {0xFE33, 0xFE34}, {0xFE4D, 0xFE4F},
- {0xFF10, 0xFF19}, {0xFF3F, 0xFF3F}, {0xFF9E, 0xFF9F},
- {0x101FD, 0x101FD}, {0x102E0, 0x102E0}, {0x10376, 0x1037A},
- {0x104A0, 0x104A9}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06},
- {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F},
- {0x10AE5, 0x10AE6}, {0x10D24, 0x10D27}, {0x10D30, 0x10D39},
- {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50}, {0x10F82, 0x10F85},
- {0x11000, 0x11002}, {0x11038, 0x11046}, {0x11066, 0x11070},
- {0x11073, 0x11074}, {0x1107F, 0x11082}, {0x110B0, 0x110BA},
- {0x110C2, 0x110C2}, {0x110F0, 0x110F9}, {0x11100, 0x11102},
- {0x11127, 0x11134}, {0x11136, 0x1113F}, {0x11145, 0x11146},
- {0x11173, 0x11173}, {0x11180, 0x11182}, {0x111B3, 0x111C0},
- {0x111C9, 0x111CC}, {0x111CE, 0x111D9}, {0x1122C, 0x11237},
- {0x1123E, 0x1123E}, {0x112DF, 0x112EA}, {0x112F0, 0x112F9},
+ {0x0CF3, 0x0CF3}, {0x0D00, 0x0D03}, {0x0D3B, 0x0D3C},
+ {0x0D3E, 0x0D44}, {0x0D46, 0x0D48}, {0x0D4A, 0x0D4D},
+ {0x0D57, 0x0D57}, {0x0D62, 0x0D63}, {0x0D66, 0x0D6F},
+ {0x0D81, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4},
+ {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DE6, 0x0DEF},
+ {0x0DF2, 0x0DF3}, {0x0E31, 0x0E31}, {0x0E33, 0x0E3A},
+ {0x0E47, 0x0E4E}, {0x0E50, 0x0E59}, {0x0EB1, 0x0EB1},
+ {0x0EB3, 0x0EBC}, {0x0EC8, 0x0ECE}, {0x0ED0, 0x0ED9},
+ {0x0F18, 0x0F19}, {0x0F20, 0x0F29}, {0x0F35, 0x0F35},
+ {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F},
+ {0x0F71, 0x0F84}, {0x0F86, 0x0F87}, {0x0F8D, 0x0F97},
+ {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102B, 0x103E},
+ {0x1040, 0x1049}, {0x1056, 0x1059}, {0x105E, 0x1060},
+ {0x1062, 0x1064}, {0x1067, 0x106D}, {0x1071, 0x1074},
+ {0x1082, 0x108D}, {0x108F, 0x109D}, {0x135D, 0x135F},
+ {0x1369, 0x1371}, {0x1712, 0x1715}, {0x1732, 0x1734},
+ {0x1752, 0x1753}, {0x1772, 0x1773}, {0x17B4, 0x17D3},
+ {0x17DD, 0x17DD}, {0x17E0, 0x17E9}, {0x180B, 0x180D},
+ {0x180F, 0x1819}, {0x18A9, 0x18A9}, {0x1920, 0x192B},
+ {0x1930, 0x193B}, {0x1946, 0x194F}, {0x19D0, 0x19DA},
+ {0x1A17, 0x1A1B}, {0x1A55, 0x1A5E}, {0x1A60, 0x1A7C},
+ {0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, {0x1AB0, 0x1ABD},
+ {0x1ABF, 0x1ACE}, {0x1B00, 0x1B04}, {0x1B34, 0x1B44},
+ {0x1B50, 0x1B59}, {0x1B6B, 0x1B73}, {0x1B80, 0x1B82},
+ {0x1BA1, 0x1BAD}, {0x1BB0, 0x1BB9}, {0x1BE6, 0x1BF3},
+ {0x1C24, 0x1C37}, {0x1C40, 0x1C49}, {0x1C50, 0x1C59},
+ {0x1CD0, 0x1CD2}, {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED},
+ {0x1CF4, 0x1CF4}, {0x1CF7, 0x1CF9}, {0x1DC0, 0x1DFF},
+ {0x203F, 0x2040}, {0x2054, 0x2054}, {0x20D0, 0x20DC},
+ {0x20E1, 0x20E1}, {0x20E5, 0x20F0}, {0x2CEF, 0x2CF1},
+ {0x2D7F, 0x2D7F}, {0x2DE0, 0x2DFF}, {0x302A, 0x302F},
+ {0x3099, 0x309A}, {0xA620, 0xA629}, {0xA66F, 0xA66F},
+ {0xA674, 0xA67D}, {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1},
+ {0xA802, 0xA802}, {0xA806, 0xA806}, {0xA80B, 0xA80B},
+ {0xA823, 0xA827}, {0xA82C, 0xA82C}, {0xA880, 0xA881},
+ {0xA8B4, 0xA8C5}, {0xA8D0, 0xA8D9}, {0xA8E0, 0xA8F1},
+ {0xA8FF, 0xA909}, {0xA926, 0xA92D}, {0xA947, 0xA953},
+ {0xA980, 0xA983}, {0xA9B3, 0xA9C0}, {0xA9D0, 0xA9D9},
+ {0xA9E5, 0xA9E5}, {0xA9F0, 0xA9F9}, {0xAA29, 0xAA36},
+ {0xAA43, 0xAA43}, {0xAA4C, 0xAA4D}, {0xAA50, 0xAA59},
+ {0xAA7B, 0xAA7D}, {0xAAB0, 0xAAB0}, {0xAAB2, 0xAAB4},
+ {0xAAB7, 0xAAB8}, {0xAABE, 0xAABF}, {0xAAC1, 0xAAC1},
+ {0xAAEB, 0xAAEF}, {0xAAF5, 0xAAF6}, {0xABE3, 0xABEA},
+ {0xABEC, 0xABED}, {0xABF0, 0xABF9}, {0xFB1E, 0xFB1E},
+ {0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, {0xFE33, 0xFE34},
+ {0xFE4D, 0xFE4F}, {0xFF10, 0xFF19}, {0xFF3F, 0xFF3F},
+ {0xFF9E, 0xFF9F}, {0x101FD, 0x101FD}, {0x102E0, 0x102E0},
+ {0x10376, 0x1037A}, {0x104A0, 0x104A9}, {0x10A01, 0x10A03},
+ {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A},
+ {0x10A3F, 0x10A3F}, {0x10AE5, 0x10AE6}, {0x10D24, 0x10D27},
+ {0x10D30, 0x10D39}, {0x10EAB, 0x10EAC}, {0x10EFD, 0x10EFF},
+ {0x10F46, 0x10F50}, {0x10F82, 0x10F85}, {0x11000, 0x11002},
+ {0x11038, 0x11046}, {0x11066, 0x11070}, {0x11073, 0x11074},
+ {0x1107F, 0x11082}, {0x110B0, 0x110BA}, {0x110C2, 0x110C2},
+ {0x110F0, 0x110F9}, {0x11100, 0x11102}, {0x11127, 0x11134},
+ {0x11136, 0x1113F}, {0x11145, 0x11146}, {0x11173, 0x11173},
+ {0x11180, 0x11182}, {0x111B3, 0x111C0}, {0x111C9, 0x111CC},
+ {0x111CE, 0x111D9}, {0x1122C, 0x11237}, {0x1123E, 0x1123E},
+ {0x11241, 0x11241}, {0x112DF, 0x112EA}, {0x112F0, 0x112F9},
{0x11300, 0x11303}, {0x1133B, 0x1133C}, {0x1133E, 0x11344},
{0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11357, 0x11357},
{0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374},
@@ -344,21 +348,54 @@ static const llvm::sys::UnicodeCharRange XIDContinueRanges[] = {
{0x11D31, 0x11D36}, {0x11D3A, 0x11D3A}, {0x11D3C, 0x11D3D},
{0x11D3F, 0x11D45}, {0x11D47, 0x11D47}, {0x11D50, 0x11D59},
{0x11D8A, 0x11D8E}, {0x11D90, 0x11D91}, {0x11D93, 0x11D97},
- {0x11DA0, 0x11DA9}, {0x11EF3, 0x11EF6}, {0x16A60, 0x16A69},
- {0x16AC0, 0x16AC9}, {0x16AF0, 0x16AF4}, {0x16B30, 0x16B36},
- {0x16B50, 0x16B59}, {0x16F4F, 0x16F4F}, {0x16F51, 0x16F87},
- {0x16F8F, 0x16F92}, {0x16FE4, 0x16FE4}, {0x16FF0, 0x16FF1},
- {0x1BC9D, 0x1BC9E}, {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46},
- {0x1D165, 0x1D169}, {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182},
- {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244},
- {0x1D7CE, 0x1D7FF}, {0x1DA00, 0x1DA36}, {0x1DA3B, 0x1DA6C},
- {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84}, {0x1DA9B, 0x1DA9F},
- {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018},
- {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A},
- {0x1E130, 0x1E136}, {0x1E140, 0x1E149}, {0x1E2AE, 0x1E2AE},
- {0x1E2EC, 0x1E2F9}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A},
+ {0x11DA0, 0x11DA9}, {0x11EF3, 0x11EF6}, {0x11F00, 0x11F01},
+ {0x11F03, 0x11F03}, {0x11F34, 0x11F3A}, {0x11F3E, 0x11F42},
+ {0x11F50, 0x11F59}, {0x13440, 0x13440}, {0x13447, 0x13455},
+ {0x16A60, 0x16A69}, {0x16AC0, 0x16AC9}, {0x16AF0, 0x16AF4},
+ {0x16B30, 0x16B36}, {0x16B50, 0x16B59}, {0x16F4F, 0x16F4F},
+ {0x16F51, 0x16F87}, {0x16F8F, 0x16F92}, {0x16FE4, 0x16FE4},
+ {0x16FF0, 0x16FF1}, {0x1BC9D, 0x1BC9E}, {0x1CF00, 0x1CF2D},
+ {0x1CF30, 0x1CF46}, {0x1D165, 0x1D169}, {0x1D16D, 0x1D172},
+ {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
+ {0x1D242, 0x1D244}, {0x1D7CE, 0x1D7FF}, {0x1DA00, 0x1DA36},
+ {0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84},
+ {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006},
+ {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024},
+ {0x1E026, 0x1E02A}, {0x1E08F, 0x1E08F}, {0x1E130, 0x1E136},
+ {0x1E140, 0x1E149}, {0x1E2AE, 0x1E2AE}, {0x1E2EC, 0x1E2F9},
+ {0x1E4EC, 0x1E4F9}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A},
{0x1E950, 0x1E959}, {0x1FBF0, 0x1FBF9}, {0xE0100, 0xE01EF}};
+// Clang supports the "Mathematical notation profile" as an extension,
+// as described in https://www.unicode.org/L2/L2022/22230-math-profile.pdf
+// Math_Start
+static const llvm::sys::UnicodeCharRange
+ MathematicalNotationProfileIDStartRanges[] = {
+ {0x02202, 0x02202}, // ∂
+ {0x02207, 0x02207}, // ∇
+ {0x0221E, 0x0221E}, // ∞
+ {0x1D6C1, 0x1D6C1}, // 𝛁
+ {0x1D6DB, 0x1D6DB}, // 𝛛
+ {0x1D6FB, 0x1D6FB}, // 𝛻
+ {0x1D715, 0x1D715}, // 𝜕
+ {0x1D735, 0x1D735}, // 𝜵
+ {0x1D74F, 0x1D74F}, // 𝝏
+ {0x1D76F, 0x1D76F}, // 𝝯
+ {0x1D789, 0x1D789}, // 𝞉
+ {0x1D7A9, 0x1D7A9}, // 𝞩
+ {0x1D7C3, 0x1D7C3}, // 𝟃
+};
+
+// Math_Continue
+static const llvm::sys::UnicodeCharRange
+ MathematicalNotationProfileIDContinueRanges[] = {
+ {0x000B2, 0x000B3}, // ²-³
+ {0x000B9, 0x000B9}, // ¹
+ {0x02070, 0x02070}, // ⁰
+ {0x02074, 0x0207E}, // ⁴-⁾
+ {0x02080, 0x0208E}, // ₀-₎
+};
+
// C11 D.1, C++11 [charname.allowed]
static const llvm::sys::UnicodeCharRange C11AllowedIDCharRanges[] = {
// 1
diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp
index 5fca029a4266..f442b6213836 100644
--- a/clang/lib/Parse/ParseAST.cpp
+++ b/clang/lib/Parse/ParseAST.cpp
@@ -176,23 +176,21 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
// and to be able to use a name based on the module name.
// At this point, we should know if we are building a non-header C++20 module.
- if (S.getLangOpts().CPlusPlusModules && !S.getLangOpts().IsHeaderFile &&
- !S.getLangOpts().CurrentModule.empty()) {
+ if (S.getLangOpts().CPlusPlusModules) {
// If we are building the module from source, then the top level module
// will be here.
Module *CodegenModule = S.getCurrentModule();
bool Interface = true;
if (CodegenModule)
- // We only use module initializers for interfaces (including partition
- // implementation units).
+ // We only use module initializers for importable module (including
+ // partition implementation units).
Interface = S.currentModuleIsInterface();
- else
+ else if (S.getLangOpts().isCompilingModuleInterface())
// If we are building the module from a PCM file, then the module can be
// found here.
CodegenModule = S.getPreprocessor().getCurrentModule();
- // If neither. then ....
- assert(CodegenModule && "codegen for a module, but don't know which?");
- if (Interface)
+
+ if (Interface && CodegenModule)
S.getASTContext().setModuleForCodeGen(CodegenModule);
}
Consumer->HandleTranslationUnit(S.getASTContext());
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 906315a078b1..3a7f5426d4a7 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -648,6 +648,11 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
Actions.ActOnStartCXXInClassMemberInitializer();
+ // The initializer isn't actually potentially evaluated unless it is
+ // used.
+ EnterExpressionEvaluationContext Eval(
+ Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed);
+
ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false,
EqualLoc);
@@ -880,7 +885,7 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
case tok::semi:
if (StopAtSemi)
return false;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
// consume this token.
Toks.push_back(Tok);
@@ -1258,13 +1263,13 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
goto consume_token;
if (AngleCount) --AngleCount;
if (KnownTemplateCount) --KnownTemplateCount;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::greatergreater:
if (!getLangOpts().CPlusPlus11)
goto consume_token;
if (AngleCount) --AngleCount;
if (KnownTemplateCount) --KnownTemplateCount;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::greater:
if (AngleCount) --AngleCount;
if (KnownTemplateCount) --KnownTemplateCount;
@@ -1369,7 +1374,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks,
case tok::semi:
if (CIK == CIK_DefaultInitializer)
return true; // End of the default initializer.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
consume_token:
Toks.push_back(Tok);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index aef9909a7c97..c7fd1156928c 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -25,10 +25,10 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
+#include <optional>
using namespace clang;
@@ -449,10 +449,8 @@ unsigned Parser::ParseAttributeArgsCommon(
? Sema::ExpressionEvaluationContext::Unevaluated
: Sema::ExpressionEvaluationContext::ConstantEvaluated);
- CommaLocsTy CommaLocs;
ExprVector ParsedExprs;
- if (ParseExpressionList(ParsedExprs, CommaLocs,
- llvm::function_ref<void()>(),
+ if (ParseExpressionList(ParsedExprs, llvm::function_ref<void()>(),
/*FailImmediatelyOnInvalidExpr=*/true,
/*EarlyTypoCorrection=*/true)) {
SkipUntil(tok::r_paren, StopAtSemi);
@@ -536,7 +534,7 @@ void Parser::ParseGNUAttributeArgs(
// These may refer to the function arguments, but need to be parsed early to
// participate in determining whether it's a redeclaration.
- llvm::Optional<ParseScope> PrototypeScope;
+ std::optional<ParseScope> PrototypeScope;
if (normalizeAttrName(AttrName->getName()) == "enable_if" &&
D && D->isFunctionDeclarator()) {
DeclaratorChunk::FunctionTypeInfo FTI = D->getFunctionTypeInfo();
@@ -914,6 +912,17 @@ void Parser::ParseOpenCLQualifiers(ParsedAttributes &Attrs) {
ParsedAttr::AS_Keyword);
}
+bool Parser::isHLSLQualifier(const Token &Tok) const {
+ return Tok.is(tok::kw_groupshared);
+}
+
+void Parser::ParseHLSLQualifiers(ParsedAttributes &Attrs) {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+ Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ ParsedAttr::AS_Keyword);
+}
+
void Parser::ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs) {
// Treat these like attributes, even though they're type specifiers.
while (true) {
@@ -1417,7 +1426,7 @@ void Parser::ParseExternalSourceSymbolAttribute(
ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(),
GeneratedDeclaration};
Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()),
- ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax);
+ ScopeName, ScopeLoc, Args, std::size(Args), Syntax);
}
/// Parse the contents of the "objc_bridge_related" attribute.
@@ -1538,7 +1547,7 @@ void Parser::ParseSwiftNewTypeAttribute(
ArgsUnion Args[] = {SwiftType};
Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, T.getCloseLocation()),
- ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax);
+ ScopeName, ScopeLoc, Args, std::size(Args), Syntax);
}
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
@@ -1680,7 +1689,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID,
Lexer::getRawToken(Attrs.Range.getBegin(), FirstLSquare, SM, LangOpts);
if (FirstLSquare.is(tok::l_square)) {
- llvm::Optional<Token> SecondLSquare =
+ std::optional<Token> SecondLSquare =
Lexer::findNextToken(FirstLSquare.getLocation(), SM, LangOpts);
if (SecondLSquare && SecondLSquare->is(tok::l_square)) {
@@ -1787,6 +1796,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
}
return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs,
true, nullptr, DeclSpecStart);
+
+ case tok::kw_cbuffer:
+ case tok::kw_tbuffer:
+ SingleDecl = ParseHLSLBuffer(DeclEnd);
+ break;
case tok::kw_namespace:
ProhibitAttributes(DeclAttrs);
ProhibitAttributes(DeclSpecAttrs);
@@ -2049,6 +2063,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return nullptr;
}
+ if (getLangOpts().HLSL)
+ MaybeParseHLSLSemantics(D);
+
if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
@@ -2078,10 +2095,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
<< (Fixit ? FixItHint::CreateInsertion(D.getBeginLoc(), "_Noreturn ")
: FixItHint());
}
- }
- // Check to see if we have a function *definition* which must have a body.
- if (D.isFunctionDeclarator()) {
+ // Check to see if we have a function *definition* which must have a body.
if (Tok.is(tok::equal) && NextToken().is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteAfterFunctionEquals(D);
@@ -2121,7 +2136,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
- if (isDeclarationSpecifier()) {
+ if (isDeclarationSpecifier(ImplicitTypenameContext::No)) {
// If there is an invalid declaration specifier right after the
// function prototype, then we must be in a missing semicolon case
// where this isn't actually a body. Just fall through into the code
@@ -2220,6 +2235,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
DiagnoseAndSkipExtendedMicrosoftTypeAttributes();
ParseDeclarator(D);
+
+ if (getLangOpts().HLSL)
+ MaybeParseHLSLSemantics(D);
+
if (!D.isInvalidType()) {
// C++2a [dcl.decl]p1
// init-declarator:
@@ -2244,7 +2263,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// Okay, there was no semicolon and one was expected. If we see a
// declaration specifier, just assume it was missing and continue parsing.
// Otherwise things are very confused and we skip to recover.
- if (!isDeclarationSpecifier()) {
+ if (!isDeclarationSpecifier(ImplicitTypenameContext::No)) {
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
TryConsumeToken(tok::semi);
}
@@ -2402,8 +2421,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None,
- LAngleLoc, nullptr));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
+ std::nullopt, LAngleLoc, nullptr));
ThisDecl =
Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D);
@@ -2478,7 +2497,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
T.consumeOpen();
ExprVector Exprs;
- CommaLocsTy CommaLocs;
InitializerScopeRAII InitScope(*this, D, ThisDecl);
@@ -2503,7 +2521,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
// ProduceConstructorSignatureHelp only on VarDecls.
ExpressionStarts = SetPreferredType;
}
- if (ParseExpressionList(Exprs, CommaLocs, ExpressionStarts)) {
+ if (ParseExpressionList(Exprs, ExpressionStarts)) {
if (ThisVarDecl && PP.isCodeCompletionReached() && !CalledSignatureHelp) {
Actions.ProduceConstructorSignatureHelp(
ThisVarDecl->getType()->getCanonicalTypeInternal(),
@@ -2516,10 +2534,6 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
} else {
// Match the ')'.
T.consumeClose();
-
- assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
- "Unexpected number of commas!");
-
InitScope.pop();
ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(),
@@ -2563,12 +2577,14 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
/// type-qualifier specifier-qualifier-list[opt]
/// [GNU] attributes specifier-qualifier-list[opt]
///
-void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
- DeclSpecContext DSC) {
+void Parser::ParseSpecifierQualifierList(
+ DeclSpec &DS, ImplicitTypenameContext AllowImplicitTypename,
+ AccessSpecifier AS, DeclSpecContext DSC) {
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
/// parse declaration-specifiers and complain about extra stuff.
/// TODO: diagnose attribute-specifiers and alignment-specifiers.
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);
+ ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC, nullptr,
+ AllowImplicitTypename);
// Validate declspec for type-name.
unsigned Specs = DS.getParsedSpecifiers();
@@ -2599,6 +2615,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
if (DS.hasExplicitSpecifier())
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
+ if (DS.isNoreturnSpecified())
+ Diag(DS.getNoreturnSpecLoc(), diag::err_typename_invalid_functionspec);
DS.ClearFunctionSpecs();
}
@@ -2800,7 +2818,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
}
}
// Fall through.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case tok::comma:
case tok::equal:
@@ -2876,24 +2894,50 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
/// DeclaratorContext enumerator values.
Parser::DeclSpecContext
Parser::getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context) {
- if (Context == DeclaratorContext::Member)
+ switch (Context) {
+ case DeclaratorContext::Member:
return DeclSpecContext::DSC_class;
- if (Context == DeclaratorContext::File)
+ case DeclaratorContext::File:
return DeclSpecContext::DSC_top_level;
- if (Context == DeclaratorContext::TemplateParam)
+ case DeclaratorContext::TemplateParam:
return DeclSpecContext::DSC_template_param;
- if (Context == DeclaratorContext::TemplateArg ||
- Context == DeclaratorContext::TemplateTypeArg)
+ case DeclaratorContext::TemplateArg:
+ return DeclSpecContext::DSC_template_arg;
+ case DeclaratorContext::TemplateTypeArg:
return DeclSpecContext::DSC_template_type_arg;
- if (Context == DeclaratorContext::TrailingReturn ||
- Context == DeclaratorContext::TrailingReturnVar)
+ case DeclaratorContext::TrailingReturn:
+ case DeclaratorContext::TrailingReturnVar:
return DeclSpecContext::DSC_trailing;
- if (Context == DeclaratorContext::AliasDecl ||
- Context == DeclaratorContext::AliasTemplate)
+ case DeclaratorContext::AliasDecl:
+ case DeclaratorContext::AliasTemplate:
return DeclSpecContext::DSC_alias_declaration;
- if (Context == DeclaratorContext::Association)
+ case DeclaratorContext::Association:
return DeclSpecContext::DSC_association;
- return DeclSpecContext::DSC_normal;
+ case DeclaratorContext::TypeName:
+ return DeclSpecContext::DSC_type_specifier;
+ case DeclaratorContext::Condition:
+ return DeclSpecContext::DSC_condition;
+ case DeclaratorContext::ConversionId:
+ return DeclSpecContext::DSC_conv_operator;
+ case DeclaratorContext::Prototype:
+ case DeclaratorContext::ObjCResult:
+ case DeclaratorContext::ObjCParameter:
+ case DeclaratorContext::KNRTypeList:
+ case DeclaratorContext::FunctionalCast:
+ case DeclaratorContext::Block:
+ case DeclaratorContext::ForInit:
+ case DeclaratorContext::SelectionInit:
+ case DeclaratorContext::CXXNew:
+ case DeclaratorContext::CXXCatch:
+ case DeclaratorContext::ObjCCatch:
+ case DeclaratorContext::BlockLiteral:
+ case DeclaratorContext::LambdaExpr:
+ case DeclaratorContext::LambdaExprParameter:
+ case DeclaratorContext::RequiresExpr:
+ return DeclSpecContext::DSC_normal;
+ }
+
+ llvm_unreachable("Missing DeclaratorContext case");
}
/// ParseAlignArgument - Parse the argument to an alignment-specifier.
@@ -3129,11 +3173,10 @@ static void SetupFixedPointError(const LangOptions &LangOpts,
/// [OpenCL] '__kernel'
/// 'friend': [C++ dcl.friend]
/// 'constexpr': [C++0x dcl.constexpr]
-void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
- const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS,
- DeclSpecContext DSContext,
- LateParsedAttrList *LateAttrs) {
+void Parser::ParseDeclarationSpecifiers(
+ DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS,
+ DeclSpecContext DSContext, LateParsedAttrList *LateAttrs,
+ ImplicitTypenameContext AllowImplicitTypename) {
if (DS.getSourceRange().isInvalid()) {
// Start the range at the current token but make the end of the range
// invalid. This will make the entire range invalid unless we successfully
@@ -3142,6 +3185,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DS.SetRangeEnd(SourceLocation());
}
+ // If we are in a operator context, convert it back into a type specifier
+ // context for better error handling later on.
+ if (DSContext == DeclSpecContext::DSC_conv_operator) {
+ // No implicit typename here.
+ AllowImplicitTypename = ImplicitTypenameContext::No;
+ DSContext = DeclSpecContext::DSC_type_specifier;
+ }
+
bool EnteringContext = (DSContext == DeclSpecContext::DSC_class ||
DSContext == DeclSpecContext::DSC_top_level);
bool AttrsLastTime = false;
@@ -3266,13 +3317,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
return;
}
- if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
- CCC = Sema::PCC_LocalDeclarationSpecifiers;
- else if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
+ // Class context can appear inside a function/block, so prioritise that.
+ if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate)
CCC = DSContext == DeclSpecContext::DSC_class ? Sema::PCC_MemberTemplate
: Sema::PCC_Template;
else if (DSContext == DeclSpecContext::DSC_class)
CCC = Sema::PCC_Class;
+ else if (getCurScope()->getFnParent() || getCurScope()->getBlockParent())
+ CCC = Sema::PCC_LocalDeclarationSpecifiers;
else if (CurParsedObjCImpl)
CCC = Sema::PCC_ObjCImplementation;
@@ -3329,7 +3381,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DSContext == DeclSpecContext::DSC_class) &&
TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) &&
- isConstructorDeclarator(/*Unqualified=*/false)) {
+ isConstructorDeclarator(/*Unqualified=*/false,
+ /*DeductionGuide=*/false,
+ DS.isFriendSpecified())) {
// The user meant this to be an out-of-line constructor
// definition, but template arguments are not allowed
// there. Just allow this as a constructor; we'll
@@ -3341,7 +3395,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeAnnotationToken(); // The C++ scope.
assert(Tok.is(tok::annot_template_id) &&
"ParseOptionalCXXScopeSpecifier not working");
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
continue;
}
@@ -3368,6 +3422,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeAnnotationToken(); // The typename
}
+ if (AllowImplicitTypename == ImplicitTypenameContext::Yes &&
+ Next.is(tok::annot_template_id) &&
+ static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
+ ->Kind == TNK_Dependent_template_name) {
+ DS.getTypeSpecScope() = SS;
+ ConsumeAnnotationToken(); // The C++ scope.
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
+ continue;
+ }
+
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
@@ -3378,7 +3442,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DSContext == DeclSpecContext::DSC_class) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
&SS) &&
- isConstructorDeclarator(/*Unqualified*/ false))
+ isConstructorDeclarator(/*Unqualified=*/false,
+ /*DeductionGuide=*/false,
+ DS.isFriendSpecified()))
goto DoneWithDeclSpec;
// C++20 [temp.spec] 13.9/6.
@@ -3387,12 +3453,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// - `return type`.
SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst);
- ParsedType TypeRep =
- Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),
- getCurScope(), &SS, false, false, nullptr,
- /*IsCtorOrDtorName=*/false,
- /*WantNontrivialTypeSourceInfo=*/true,
- isClassTemplateDeductionContext(DSContext));
+ ParsedType TypeRep = Actions.getTypeName(
+ *Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS,
+ false, false, nullptr,
+ /*IsCtorOrDtorName=*/false,
+ /*WantNontrivialTypeSourceInfo=*/true,
+ isClassTemplateDeductionContext(DSContext), AllowImplicitTypename);
if (IsTemplateSpecOrInst)
SAC.done();
@@ -3471,7 +3537,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// typedef-name
case tok::kw___super:
case tok::kw_decltype:
- case tok::identifier: {
+ case tok::identifier:
+ ParseIdentifier: {
// This identifier can only be a typedef name if we haven't already seen
// a type-specifier. Without this check we misparse:
// typedef int X; struct Y { short X; }; as 'short int'.
@@ -3555,7 +3622,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// check whether this is a constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
Actions.isCurrentClassName(*Tok.getIdentifierInfo(), getCurScope()) &&
- isConstructorDeclarator(/*Unqualified*/true))
+ isConstructorDeclarator(/*Unqualified=*/true,
+ /*DeductionGuide=*/false,
+ DS.isFriendSpecified()))
goto DoneWithDeclSpec;
ParsedType TypeRep = Actions.getTypeName(
@@ -3630,11 +3699,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (TemplateId->Kind == TNK_Concept_template) {
// If we've already diagnosed that this type-constraint has invalid
- // arguemnts, drop it and just form 'auto' or 'decltype(auto)'.
+ // arguments, drop it and just form 'auto' or 'decltype(auto)'.
if (TemplateId->hasInvalidArgs())
TemplateId = nullptr;
- if (NextToken().is(tok::identifier)) {
+ // Any of the following tokens are likely the start of the user
+ // forgetting 'auto' or 'decltype(auto)', so diagnose.
+ // Note: if updating this list, please make sure we update
+ // isCXXDeclarationSpecifier's check for IsPlaceholderSpecifier to have
+ // a matching list.
+ if (NextToken().isOneOf(tok::identifier, tok::kw_const,
+ tok::kw_volatile, tok::kw_restrict, tok::amp,
+ tok::ampamp)) {
Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto)
<< FixItHint::CreateInsertion(NextToken().getLocation(), "auto");
// Attempt to continue as if 'auto' was placed here.
@@ -3664,7 +3740,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
}
ConsumedEnd = Tok.getLocation();
- DS.setTypeofParensRange(Tracker.getRange());
+ DS.setTypeArgumentRange(Tracker.getRange());
// Even if something went wrong above, continue as if we've seen
// `decltype(auto)`.
isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec,
@@ -3688,13 +3764,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// constructor declaration.
if (getLangOpts().CPlusPlus && DSContext == DeclSpecContext::DSC_class &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope()) &&
- isConstructorDeclarator(/*Unqualified=*/true))
+ isConstructorDeclarator(/*Unqualified=*/true,
+ /*DeductionGuide=*/false,
+ DS.isFriendSpecified()))
goto DoneWithDeclSpec;
// Turn the template-id annotation token into a type annotation
// token, then try again to parse it as a type-specifier.
CXXScopeSpec SS;
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
continue;
}
@@ -4181,8 +4259,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
break;
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
ParseTypeofSpecifier(DS);
continue;
@@ -4206,8 +4285,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
HandlePragmaMSPointersToMembers();
continue;
- case tok::kw___underlying_type:
- ParseUnderlyingTypeSpecifier(DS);
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+ // HACK: libstdc++ already uses '__remove_cv' as an alias template so we
+ // work around this by expecting all transform type traits to be suffixed
+ // with '('. They're an identifier otherwise.
+ if (!MaybeParseTypeTransformTypeSpecifier(DS))
+ goto ParseIdentifier;
continue;
case tok::kw__Atomic:
@@ -4238,13 +4322,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = true;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_private:
// It's fine (but redundant) to check this for __generic on the
// fallthrough path; we only form the __generic token in OpenCL mode.
if (!getLangOpts().OpenCL)
goto DoneWithDeclSpec;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -4256,6 +4340,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ParseOpenCLQualifiers(DS.getAttributes());
break;
+ case tok::kw_groupshared:
+ // NOTE: ParseHLSLQualifiers will consume the qualifier token.
+ ParseHLSLQualifiers(DS.getAttributes());
+ continue;
+
case tok::less:
// GCC ObjC supports types like "<SomeProtocol>" as a synonym for
// "id<SomeProtocol>". This is hopelessly old fashioned and dangerous,
@@ -4581,6 +4670,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// Code completion for an enum name.
cutOffParsing();
Actions.CodeCompleteTag(getCurScope(), DeclSpec::TST_enum);
+ DS.SetTypeSpecError(); // Needed by ActOnUsingDeclaration.
return;
}
@@ -4640,6 +4730,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (Spec.isSet() && Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected) << tok::identifier;
+ DS.SetTypeSpecError();
if (Tok.isNot(tok::l_brace)) {
// Has no name and is not a definition.
// Skip the rest of this declarator, up until the comma or semicolon.
@@ -4656,6 +4747,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_either) << tok::identifier << tok::l_brace;
+ DS.SetTypeSpecError();
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, StopAtSemi);
return;
@@ -4727,7 +4819,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// enum E : int *p;
// declares 'enum E : int; E *p;' not 'enum E : int*; E p;'.
DeclSpec DS(AttrFactory);
- ParseSpecifierQualifierList(DS, AS, DeclSpecContext::DSC_type_specifier);
+ // enum-base is not assumed to be a type and therefore requires the
+ // typename keyword [p0634r3].
+ ParseSpecifierQualifierList(DS, ImplicitTypenameContext::No, AS,
+ DeclSpecContext::DSC_type_specifier);
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
DeclaratorContext::TypeName);
BaseType = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
@@ -4831,6 +4926,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (!Name && TUK != Sema::TUK_Definition) {
Diag(Tok, diag::err_enumerator_unnamed_no_def);
+ DS.SetTypeSpecError();
// Skip the rest of this declarator, up until the comma or semicolon.
SkipUntil(tok::comma, StopAtSemi);
return;
@@ -4869,14 +4965,16 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool IsDependent = false;
const char *PrevSpec = nullptr;
unsigned DiagID;
- Decl *TagDecl = Actions.ActOnTag(
- getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc,
- attrs, AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent,
- ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType,
- DSC == DeclSpecContext::DSC_type_specifier,
- DSC == DeclSpecContext::DSC_template_param ||
- DSC == DeclSpecContext::DSC_template_type_arg,
- &SkipBody);
+ UsingShadowDecl* FoundUsing = nullptr;
+ Decl *TagDecl =
+ Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, StartLoc, SS,
+ Name, NameLoc, attrs, AS, DS.getModulePrivateSpecLoc(),
+ TParams, Owned, IsDependent, ScopedEnumKWLoc,
+ IsScopedUsingClassTag,
+ BaseType, DSC == DeclSpecContext::DSC_type_specifier,
+ DSC == DeclSpecContext::DSC_template_param ||
+ DSC == DeclSpecContext::DSC_template_type_arg,
+ OffsetOfState, FoundUsing, &SkipBody).get();
if (SkipBody.ShouldSkip) {
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
@@ -4886,8 +4984,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
T.skipToEnd();
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
- NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, TagDecl, Owned,
+ NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
+ DiagID, FoundUsing ? FoundUsing : TagDecl, Owned,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
return;
@@ -4941,8 +5039,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
}
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
- NameLoc.isValid() ? NameLoc : StartLoc,
- PrevSpec, DiagID, TagDecl, Owned,
+ NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
+ DiagID, FoundUsing ? FoundUsing : TagDecl, Owned,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
}
@@ -5159,7 +5257,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::identifier: // foo::bar
if (TryAltiVecVectorToken())
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
@@ -5180,8 +5278,9 @@ bool Parser::isTypeSpecifierQualifier() {
// GNU attributes support.
case tok::kw___attribute:
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
// type-specifiers
case tok::kw_short:
@@ -5271,6 +5370,8 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw___read_only:
case tok::kw___read_write:
case tok::kw___write_only:
+
+ case tok::kw_groupshared:
return true;
case tok::kw_private:
@@ -5282,12 +5383,35 @@ bool Parser::isTypeSpecifierQualifier() {
}
}
+Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() {
+ assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode");
+
+ // Parse a top-level-stmt.
+ Parser::StmtVector Stmts;
+ ParsedStmtContext SubStmtCtx = ParsedStmtContext();
+ StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx);
+ if (!R.isUsable())
+ return nullptr;
+
+ SmallVector<Decl *, 2> DeclsInGroup;
+ DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(R.get()));
+ // Currently happens for things like -fms-extensions and use `__if_exists`.
+ for (Stmt *S : Stmts)
+ DeclsInGroup.push_back(Actions.ActOnTopLevelStmtDecl(S));
+
+ return Actions.BuildDeclaratorGroup(DeclsInGroup);
+}
+
/// isDeclarationSpecifier() - Return true if the current token is part of a
/// declaration specifier.
///
+/// \param AllowImplicitTypename whether this is a context where T::type [T
+/// dependent] can appear.
/// \param DisambiguatingWithExpression True to indicate that the purpose of
/// this check is to disambiguate between an expression and a declaration.
-bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
+bool Parser::isDeclarationSpecifier(
+ ImplicitTypenameContext AllowImplicitTypename,
+ bool DisambiguatingWithExpression) {
switch (Tok.getKind()) {
default: return false;
@@ -5302,12 +5426,12 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
return false;
if (TryAltiVecVectorToken())
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_decltype: // decltype(T())::type
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
return true;
if (TryAnnotateTypeConstraint())
return true;
@@ -5323,9 +5447,11 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
isStartOfObjCClassMessageMissingOpenBracket())
return false;
- return isDeclarationSpecifier();
+ return isDeclarationSpecifier(AllowImplicitTypename);
case tok::coloncolon: // ::foo::bar
+ if (!getLangOpts().CPlusPlus)
+ return false;
if (NextToken().is(tok::kw_new) || // ::new
NextToken().is(tok::kw_delete)) // ::delete
return false;
@@ -5334,7 +5460,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// recurse to handle whatever we get.
if (TryAnnotateTypeOrScopeToken())
return true;
- return isDeclarationSpecifier();
+ return isDeclarationSpecifier(ImplicitTypenameContext::No);
// storage-class-specifier
case tok::kw_typedef:
@@ -5419,8 +5545,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_static_assert:
case tok::kw__Static_assert:
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
// GNU attributes.
case tok::kw___attribute:
@@ -5506,6 +5633,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
#include "clang/Basic/OpenCLImageTypes.def"
+ case tok::kw_groupshared:
return true;
case tok::kw_private:
@@ -5513,7 +5641,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
}
}
-bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
+bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide,
+ DeclSpec::FriendSpecified IsFriend) {
TentativeParsingAction TPA(*this);
// Parse the C++ scope specifier.
@@ -5577,8 +5706,11 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
// Check whether the next token(s) are part of a declaration
// specifier, in which case we have the start of a parameter and,
// therefore, we know that this is a constructor.
+ // Due to an ambiguity with implicit typename, the above is not enough.
+ // Additionally, check to see if we are a friend.
bool IsConstructor = false;
- if (isDeclarationSpecifier())
+ if (isDeclarationSpecifier(IsFriend ? ImplicitTypenameContext::No
+ : ImplicitTypenameContext::Yes))
IsConstructor = true;
else if (Tok.is(tok::identifier) ||
(Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) {
@@ -5667,7 +5799,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
void Parser::ParseTypeQualifierListOpt(
DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed,
bool IdentifierRequired,
- Optional<llvm::function_ref<void()>> CodeCompletionHandler) {
+ std::optional<llvm::function_ref<void()>> CodeCompletionHandler) {
if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) &&
isCXX11AttributeSpecifier()) {
ParsedAttributes Attrs(AttrFactory);
@@ -5717,7 +5849,7 @@ void Parser::ParseTypeQualifierListOpt(
case tok::kw_private:
if (!getLangOpts().OpenCL)
goto DoneWithTypeQuals;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw___private:
case tok::kw___global:
case tok::kw___local:
@@ -5729,6 +5861,11 @@ void Parser::ParseTypeQualifierListOpt(
ParseOpenCLQualifiers(DS.getAttributes());
break;
+ case tok::kw_groupshared:
+ // NOTE: ParseHLSLQualifiers will consume the qualifier token.
+ ParseHLSLQualifiers(DS.getAttributes());
+ continue;
+
case tok::kw___unaligned:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_unaligned, Loc, PrevSpec, DiagID,
getLangOpts());
@@ -5741,7 +5878,7 @@ void Parser::ParseTypeQualifierListOpt(
if (TryKeywordIdentFallback(false))
continue;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw___sptr:
case tok::kw___w64:
case tok::kw___ptr64:
@@ -5792,7 +5929,7 @@ void Parser::ParseTypeQualifierListOpt(
continue; // do *not* consume the next token!
}
// otherwise, FALL THROUGH!
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
DoneWithTypeQuals:
// If this is not a type-qualifier token, we're done reading type
@@ -6393,10 +6530,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// is not, the declarator has been fully parsed.
bool IsAmbiguous = false;
if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) {
+ // C++2a [temp.res]p5
+ // A qualified-id is assumed to name a type if
+ // - [...]
+ // - it is a decl-specifier of the decl-specifier-seq of a
+ // - [...]
+ // - parameter-declaration in a member-declaration [...]
+ // - parameter-declaration in a declarator of a function or function
+ // template declaration whose declarator-id is qualified [...]
+ auto AllowImplicitTypename = ImplicitTypenameContext::No;
+ if (D.getCXXScopeSpec().isSet())
+ AllowImplicitTypename =
+ (ImplicitTypenameContext)Actions.isDeclaratorFunctionLike(D);
+ else if (D.getContext() == DeclaratorContext::Member) {
+ AllowImplicitTypename = ImplicitTypenameContext::Yes;
+ }
+
// The name of the declarator, if any, is tentatively declared within
// a possible direct initializer.
TentativelyDeclaredIdentifiers.push_back(D.getIdentifier());
- bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous);
+ bool IsFunctionDecl =
+ isCXXFunctionDeclarator(&IsAmbiguous, AllowImplicitTypename);
TentativelyDeclaredIdentifiers.pop_back();
if (!IsFunctionDecl)
break;
@@ -6555,11 +6709,12 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// If this can't be an abstract-declarator, this *must* be a grouping
// paren, because we haven't seen the identifier yet.
isGrouping = true;
- } else if (Tok.is(tok::r_paren) || // 'int()' is a function.
+ } else if (Tok.is(tok::r_paren) || // 'int()' is a function.
(getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) &&
NextToken().is(tok::r_paren)) || // C++ int(...)
- isDeclarationSpecifier() || // 'int(int)' is a function.
- isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function.
+ isDeclarationSpecifier(
+ ImplicitTypenameContext::No) || // 'int(int)' is a function.
+ isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function.
// This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
// considered to be a type, not a K&R identifier-list.
isGrouping = false;
@@ -6611,7 +6766,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
void Parser::InitCXXThisScopeForDeclaratorIfRelevant(
const Declarator &D, const DeclSpec &DS,
- llvm::Optional<Sema::CXXThisScopeRAII> &ThisScope) {
+ std::optional<Sema::CXXThisScopeRAII> &ThisScope) {
// C++11 [expr.prim.general]p3:
// If a declaration declares a member function or member function
// template of a class X, the expression this is a prvalue of type
@@ -6727,8 +6882,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
ProhibitAttributes(FnAttrs);
} else {
if (Tok.isNot(tok::r_paren))
- ParseParameterDeclarationClause(D.getContext(), FirstArgAttrs, ParamInfo,
- EllipsisLoc);
+ ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
else if (RequiresArg)
Diag(Tok, diag::err_argument_required_after_attribute);
@@ -6764,7 +6918,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc))
EndLoc = RefQualifierLoc;
- llvm::Optional<Sema::CXXThisScopeRAII> ThisScope;
+ std::optional<Sema::CXXThisScopeRAII> ThisScope;
InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope);
// Parse exception-specification[opt].
@@ -6987,7 +7141,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(
void Parser::ParseParameterDeclarationClause(
DeclaratorContext DeclaratorCtx, ParsedAttributes &FirstArgAttrs,
SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo,
- SourceLocation &EllipsisLoc) {
+ SourceLocation &EllipsisLoc, bool IsACXXFunctionDeclaration) {
// Avoid exceeding the maximum function scope depth.
// See https://bugs.llvm.org/show_bug.cgi?id=19607
@@ -7001,6 +7155,23 @@ void Parser::ParseParameterDeclarationClause(
return;
}
+ // C++2a [temp.res]p5
+ // A qualified-id is assumed to name a type if
+ // - [...]
+ // - it is a decl-specifier of the decl-specifier-seq of a
+ // - [...]
+ // - parameter-declaration in a member-declaration [...]
+ // - parameter-declaration in a declarator of a function or function
+ // template declaration whose declarator-id is qualified [...]
+ // - parameter-declaration in a lambda-declarator [...]
+ auto AllowImplicitTypename = ImplicitTypenameContext::No;
+ if (DeclaratorCtx == DeclaratorContext::Member ||
+ DeclaratorCtx == DeclaratorContext::LambdaExpr ||
+ DeclaratorCtx == DeclaratorContext::RequiresExpr ||
+ IsACXXFunctionDeclaration) {
+ AllowImplicitTypename = ImplicitTypenameContext::Yes;
+ }
+
do {
// FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
// before deciding this was a parameter-declaration-clause.
@@ -7030,7 +7201,9 @@ void Parser::ParseParameterDeclarationClause(
SourceLocation DSStart = Tok.getLocation();
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS, /*TemplateInfo=*/ParsedTemplateInfo(),
+ AS_none, DeclSpecContext::DSC_normal,
+ /*LateAttrs=*/nullptr, AllowImplicitTypename);
DS.takeAttributesFrom(ArgDeclSpecAttrs);
// Parse the declarator. This is "PrototypeContext" or
@@ -7046,7 +7219,8 @@ void Parser::ParseParameterDeclarationClause(
// Parse GNU attributes, if present.
MaybeParseGNUAttributes(ParmDeclarator);
- MaybeParseHLSLSemantics(DS.getAttributes());
+ if (getLangOpts().HLSL)
+ MaybeParseHLSLSemantics(DS.getAttributes());
if (Tok.is(tok::kw_requires)) {
// User tried to define a requires clause in a parameter declaration,
@@ -7427,13 +7601,27 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
/// typeof ( expressions )
/// typeof ( type-name )
/// [GNU/C++] typeof unary-expression
+/// [C2x] typeof-specifier:
+/// typeof '(' typeof-specifier-argument ')'
+/// typeof_unqual '(' typeof-specifier-argument ')'
+///
+/// typeof-specifier-argument:
+/// expression
+/// type-name
///
void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
- assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier");
+ assert(Tok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual) &&
+ "Not a typeof specifier");
+
+ bool IsUnqual = Tok.is(tok::kw_typeof_unqual);
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (getLangOpts().C2x && !II->getName().startswith("__"))
+ Diag(Tok.getLocation(), diag::warn_c2x_compat_typeof_type_specifier)
+ << IsUnqual;
+
Token OpTok = Tok;
SourceLocation StartLoc = ConsumeToken();
-
- const bool hasParens = Tok.is(tok::l_paren);
+ bool HasParens = Tok.is(tok::l_paren);
EnterExpressionEvaluationContext Unevaluated(
Actions, Sema::ExpressionEvaluationContext::Unevaluated,
@@ -7444,8 +7632,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
SourceRange CastRange;
ExprResult Operand = Actions.CorrectDelayedTyposInExpr(
ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange));
- if (hasParens)
- DS.setTypeofParensRange(CastRange);
+ if (HasParens)
+ DS.setTypeArgumentRange(CastRange);
if (CastRange.getEnd().isInvalid())
// FIXME: Not accurate, the range gets one token more than it should.
@@ -7462,7 +7650,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const char *PrevSpec = nullptr;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
- if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec,
+ if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualType
+ : DeclSpec::TST_typeofType,
+ StartLoc, PrevSpec,
DiagID, CastTy,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
@@ -7485,7 +7675,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const char *PrevSpec = nullptr;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
- if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
+ if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualExpr
+ : DeclSpec::TST_typeofExpr,
+ StartLoc, PrevSpec,
DiagID, Operand.get(),
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
@@ -7515,7 +7707,7 @@ void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
if (T.getCloseLocation().isInvalid())
return;
- DS.setTypeofParensRange(T.getRange());
+ DS.setTypeArgumentRange(T.getRange());
DS.SetRangeEnd(T.getCloseLocation());
const char *PrevSpec = nullptr;
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index bf73ddfd1031..b26ec00cfedf 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -18,6 +18,7 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TokenKinds.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
@@ -26,6 +27,7 @@
#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/TimeProfiler.h"
+#include <optional>
using namespace clang;
@@ -226,7 +228,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
getCurScope(), InlineLoc, NamespaceLoc, IdentLoc, Ident,
- T.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl);
+ T.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl, false);
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, NamespcDecl,
NamespaceLoc, "parsing namespace");
@@ -253,9 +255,10 @@ void Parser::ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,
if (index == InnerNSs.size()) {
while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
Tok.isNot(tok::eof)) {
- ParsedAttributes Attrs(AttrFactory);
- MaybeParseCXX11Attributes(Attrs);
- ParseExternalDeclaration(Attrs);
+ ParsedAttributes DeclAttrs(AttrFactory);
+ MaybeParseCXX11Attributes(DeclAttrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);
}
// The caller is what called check -- we are simply calling
@@ -273,7 +276,7 @@ void Parser::ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,
Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
getCurScope(), InnerNSs[index].InlineLoc, InnerNSs[index].NamespaceLoc,
InnerNSs[index].IdentLoc, InnerNSs[index].Ident,
- Tracker.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl);
+ Tracker.getOpenLocation(), attrs, ImplicitUsingDirectiveDecl, true);
assert(!ImplicitUsingDirectiveDecl &&
"nested namespace definition cannot define anonymous namespace");
@@ -357,7 +360,11 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
ParsedAttributes DeclAttrs(AttrFactory);
- MaybeParseCXX11Attributes(DeclAttrs);
+ ParsedAttributes DeclSpecAttrs(AttrFactory);
+
+ while (MaybeParseCXX11Attributes(DeclAttrs) ||
+ MaybeParseGNUAttributes(DeclSpecAttrs))
+ ;
if (Tok.isNot(tok::l_brace)) {
// Reset the source range in DS, as the leading "extern"
@@ -366,7 +373,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
DS.SetRangeEnd(SourceLocation());
// ... but anyway remember that such an "extern" was seen.
DS.setExternInLinkageSpec(true);
- ParseExternalDeclaration(DeclAttrs, &DS);
+ ParseExternalDeclaration(DeclAttrs, DeclSpecAttrs, &DS);
return LinkageSpec ? Actions.ActOnFinishLinkageSpecification(
getCurScope(), LinkageSpec, SourceLocation())
: nullptr;
@@ -404,11 +411,11 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
case tok::r_brace:
if (!NestedModules)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
- ParsedAttributes Attrs(AttrFactory);
- MaybeParseCXX11Attributes(Attrs);
- ParseExternalDeclaration(Attrs);
+ ParsedAttributes DeclAttrs(AttrFactory);
+ MaybeParseCXX11Attributes(DeclAttrs);
+ ParseExternalDeclaration(DeclAttrs, DeclSpecAttrs);
continue;
}
@@ -438,9 +445,10 @@ Decl *Parser::ParseExportDeclaration() {
if (Tok.isNot(tok::l_brace)) {
// FIXME: Factor out a ParseExternalDeclarationWithAttrs.
- ParsedAttributes Attrs(AttrFactory);
- MaybeParseCXX11Attributes(Attrs);
- ParseExternalDeclaration(Attrs);
+ ParsedAttributes DeclAttrs(AttrFactory);
+ MaybeParseCXX11Attributes(DeclAttrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);
return Actions.ActOnFinishExportDecl(getCurScope(), ExportDecl,
SourceLocation());
}
@@ -457,9 +465,10 @@ Decl *Parser::ParseExportDeclaration() {
while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
Tok.isNot(tok::eof)) {
- ParsedAttributes Attrs(AttrFactory);
- MaybeParseCXX11Attributes(Attrs);
- ParseExternalDeclaration(Attrs);
+ ParsedAttributes DeclAttrs(AttrFactory);
+ MaybeParseCXX11Attributes(DeclAttrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);
}
T.consumeClose();
@@ -677,6 +686,8 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
///
/// using-enum-declaration: [C++20, dcl.enum]
/// 'using' elaborated-enum-specifier ;
+/// The terminal name of the elaborated-enum-specifier undergoes
+/// ordinary lookup
///
/// elaborated-enum-specifier:
/// 'enum' nested-name-specifier[opt] identifier
@@ -696,21 +707,47 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
DiagnoseCXX11AttributeExtension(PrefixAttrs);
- DeclSpec DS(AttrFactory);
- ParseEnumSpecifier(UELoc, DS, TemplateInfo, AS,
- // DSC_trailing has the semantics we desire
- DeclSpecContext::DSC_trailing);
-
if (TemplateInfo.Kind) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
<< 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+ CXXScopeSpec SS;
+ if (ParseOptionalCXXScopeSpecifier(SS, /*ParsedType=*/nullptr,
+ /*ObectHasErrors=*/false,
+ /*EnteringConttext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ /*IsTypename=*/false,
+ /*IdentifierInfo=*/nullptr,
+ /*OnlyNamespace=*/false,
+ /*InUsingDeclaration=*/true)) {
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+
+ if (Tok.is(tok::code_completion)) {
+ cutOffParsing();
+ Actions.CodeCompleteUsing(getCurScope());
+ return nullptr;
+ }
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_using_enum_expect_identifier)
+ << Tok.is(tok::kw_enum);
+ SkipUntil(tok::semi);
+ return nullptr;
+ }
+ IdentifierInfo *IdentInfo = Tok.getIdentifierInfo();
+ SourceLocation IdentLoc = ConsumeToken();
+ Decl *UED = Actions.ActOnUsingEnumDeclaration(
+ getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, &SS);
+ if (!UED) {
+ SkipUntil(tok::semi);
return nullptr;
}
- Decl *UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc,
- UELoc, DS);
DeclEnd = Tok.getLocation();
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
"using-enum declaration"))
@@ -934,10 +971,11 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd) {
if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11)
Diag(Tok, diag::ext_c11_feature) << Tok.getName();
if (Tok.is(tok::kw_static_assert)) {
- if (!getLangOpts().CPlusPlus)
- Diag(Tok, diag::ext_ms_static_assert)
- << FixItHint::CreateReplacement(Tok.getLocation(), "_Static_assert");
- else
+ if (!getLangOpts().CPlusPlus) {
+ if (!getLangOpts().C2x)
+ Diag(Tok, diag::ext_ms_static_assert) << FixItHint::CreateReplacement(
+ Tok.getLocation(), "_Static_assert");
+ } else
Diag(Tok, diag::warn_cxx98_compat_static_assert);
}
@@ -1021,7 +1059,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
EndLoc = Tok.getAnnotationEndLoc();
// Unfortunately, we don't know the LParen source location as the annotated
// token doesn't have it.
- DS.setTypeofParensRange(SourceRange(SourceLocation(), EndLoc));
+ DS.setTypeArgumentRange(SourceRange(SourceLocation(), EndLoc));
ConsumeAnnotationToken();
if (Result.isInvalid()) {
DS.SetTypeSpecError();
@@ -1085,7 +1123,7 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
// Match the ')'
T.consumeClose();
- DS.setTypeofParensRange(T.getRange());
+ DS.setTypeArgumentRange(T.getRange());
if (T.getCloseLocation().isInvalid()) {
DS.SetTypeSpecError();
// FIXME: this should return the location of the last token
@@ -1142,35 +1180,48 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
PP.AnnotateCachedTokens(Tok);
}
-void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
- assert(Tok.is(tok::kw___underlying_type) &&
- "Not an underlying type specifier");
+DeclSpec::TST Parser::TypeTransformTokToDeclSpec() {
+ switch (Tok.getKind()) {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
+ case tok::kw___##Trait: \
+ return DeclSpec::TST_##Trait;
+#include "clang/Basic/TransformTypeTraits.def"
+ default:
+ llvm_unreachable("passed in an unhandled type transformation built-in");
+ }
+}
+bool Parser::MaybeParseTypeTransformTypeSpecifier(DeclSpec &DS) {
+ if (!NextToken().is(tok::l_paren)) {
+ Tok.setKind(tok::identifier);
+ return false;
+ }
+ DeclSpec::TST TypeTransformTST = TypeTransformTokToDeclSpec();
SourceLocation StartLoc = ConsumeToken();
+
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after, "__underlying_type",
- tok::r_paren)) {
- return;
- }
+ if (T.expectAndConsume(diag::err_expected_lparen_after, Tok.getName(),
+ tok::r_paren))
+ return true;
TypeResult Result = ParseTypeName();
if (Result.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
- return;
+ return true;
}
- // Match the ')'
T.consumeClose();
if (T.getCloseLocation().isInvalid())
- return;
+ return true;
const char *PrevSpec = nullptr;
unsigned DiagID;
- if (DS.SetTypeSpecType(DeclSpec::TST_underlyingType, StartLoc, PrevSpec,
- DiagID, Result.get(),
+ if (DS.SetTypeSpecType(TypeTransformTST, StartLoc, PrevSpec, DiagID,
+ Result.get(),
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
- DS.setTypeofParensRange(T.getRange());
+ DS.setTypeArgumentRange(T.getRange());
+ return true;
}
/// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a
@@ -1230,7 +1281,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->mightBeType()) {
- AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/ true);
+ AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::No,
+ /*IsClassName=*/true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TypeResult Type = getTypeAnnotation(Tok);
@@ -1272,7 +1324,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
return true;
if (Tok.is(tok::annot_template_id) &&
takeTemplateIdAnnotation(Tok)->mightBeType())
- AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/ true);
+ AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::No,
+ /*IsClassName=*/true);
// If we didn't end up with a typename token, there's nothing more we
// can do.
@@ -1293,7 +1346,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
*Id, IdLoc, getCurScope(), &SS, /*isClassName=*/true, false, nullptr,
/*IsCtorOrDtorName=*/false,
/*WantNontrivialTypeSourceInfo=*/true,
- /*IsClassTemplateDeductionContext*/ false, &CorrectedII);
+ /*IsClassTemplateDeductionContext=*/false, ImplicitTypenameContext::No,
+ &CorrectedII);
if (!Type) {
Diag(IdLoc, diag::err_expected_class_name);
return true;
@@ -1525,28 +1579,63 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier) &&
!Tok.isAnnotation() && Tok.getIdentifierInfo() &&
Tok.isOneOf(
- tok::kw___is_abstract, tok::kw___is_aggregate,
- tok::kw___is_arithmetic, tok::kw___is_array, tok::kw___is_assignable,
- tok::kw___is_base_of, tok::kw___is_class, tok::kw___is_complete_type,
- tok::kw___is_compound, tok::kw___is_const, tok::kw___is_constructible,
- tok::kw___is_convertible, tok::kw___is_convertible_to,
- tok::kw___is_destructible, tok::kw___is_empty, tok::kw___is_enum,
- tok::kw___is_floating_point, tok::kw___is_final,
- tok::kw___is_function, tok::kw___is_fundamental,
- tok::kw___is_integral, tok::kw___is_interface_class,
- tok::kw___is_literal, tok::kw___is_lvalue_expr,
- tok::kw___is_lvalue_reference, tok::kw___is_member_function_pointer,
- tok::kw___is_member_object_pointer, tok::kw___is_member_pointer,
- tok::kw___is_nothrow_assignable, tok::kw___is_nothrow_constructible,
- tok::kw___is_nothrow_destructible, tok::kw___is_object,
- tok::kw___is_pod, tok::kw___is_pointer, tok::kw___is_polymorphic,
- tok::kw___is_reference, tok::kw___is_rvalue_expr,
- tok::kw___is_rvalue_reference, tok::kw___is_same, tok::kw___is_scalar,
- tok::kw___is_sealed, tok::kw___is_signed,
- tok::kw___is_standard_layout, tok::kw___is_trivial,
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
+#include "clang/Basic/TransformTypeTraits.def"
+ tok::kw___is_abstract,
+ tok::kw___is_aggregate,
+ tok::kw___is_arithmetic,
+ tok::kw___is_array,
+ tok::kw___is_assignable,
+ tok::kw___is_base_of,
+ tok::kw___is_bounded_array,
+ tok::kw___is_class,
+ tok::kw___is_complete_type,
+ tok::kw___is_compound,
+ tok::kw___is_const,
+ tok::kw___is_constructible,
+ tok::kw___is_convertible,
+ tok::kw___is_convertible_to,
+ tok::kw___is_destructible,
+ tok::kw___is_empty,
+ tok::kw___is_enum,
+ tok::kw___is_floating_point,
+ tok::kw___is_final,
+ tok::kw___is_function,
+ tok::kw___is_fundamental,
+ tok::kw___is_integral,
+ tok::kw___is_interface_class,
+ tok::kw___is_literal,
+ tok::kw___is_lvalue_expr,
+ tok::kw___is_lvalue_reference,
+ tok::kw___is_member_function_pointer,
+ tok::kw___is_member_object_pointer,
+ tok::kw___is_member_pointer,
+ tok::kw___is_nothrow_assignable,
+ tok::kw___is_nothrow_constructible,
+ tok::kw___is_nothrow_destructible,
+ tok::kw___is_nullptr,
+ tok::kw___is_object,
+ tok::kw___is_pod,
+ tok::kw___is_pointer,
+ tok::kw___is_polymorphic,
+ tok::kw___is_reference,
+ tok::kw___is_referenceable,
+ tok::kw___is_rvalue_expr,
+ tok::kw___is_rvalue_reference,
+ tok::kw___is_same,
+ tok::kw___is_scalar,
+ tok::kw___is_scoped_enum,
+ tok::kw___is_sealed,
+ tok::kw___is_signed,
+ tok::kw___is_standard_layout,
+ tok::kw___is_trivial,
tok::kw___is_trivially_assignable,
- tok::kw___is_trivially_constructible, tok::kw___is_trivially_copyable,
- tok::kw___is_union, tok::kw___is_unsigned, tok::kw___is_void,
+ tok::kw___is_trivially_constructible,
+ tok::kw___is_trivially_copyable,
+ tok::kw___is_unbounded_array,
+ tok::kw___is_union,
+ tok::kw___is_unsigned,
+ tok::kw___is_void,
tok::kw___is_volatile))
// GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
// name of struct templates, but some are keywords in GCC >= 4.3
@@ -1845,6 +1934,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Create the tag portion of the class or class template.
DeclResult TagOrTempResult = true; // invalid
TypeResult TypeResult = true; // invalid
+ UsingShadowDecl *FoundUsing = nullptr;
bool Owned = false;
Sema::SkipBodyInfo SkipBody;
@@ -1914,8 +2004,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// "template<>", so that we treat this construct as a class
// template specialization.
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None,
- LAngleLoc, nullptr));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
+ std::nullopt, LAngleLoc, nullptr));
TemplateParams = &FakedParamLists;
}
}
@@ -1985,7 +2075,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
DSC == DeclSpecContext::DSC_type_specifier,
DSC == DeclSpecContext::DSC_template_param ||
DSC == DeclSpecContext::DSC_template_type_arg,
- &SkipBody);
+ OffsetOfState, FoundUsing, &SkipBody);
// If ActOnTag said the type was dependent, try again with the
// less common call.
@@ -2044,7 +2134,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else if (!TagOrTempResult.isInvalid()) {
Result = DS.SetTypeSpecType(
TagType, StartLoc, NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec,
- DiagID, TagOrTempResult.get(), Owned, Policy);
+ DiagID, FoundUsing ? FoundUsing : TagOrTempResult.get(), Owned, Policy);
} else {
DS.SetTypeSpecError();
return;
@@ -3103,7 +3193,11 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
"Data member initializer not starting with '=' or '{'");
EnterExpressionEvaluationContext Context(
- Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, D);
+ Actions,
+ isa_and_present<FieldDecl>(D)
+ ? Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed
+ : Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
+ D);
if (TryConsumeToken(tok::equal, EqualLoc)) {
if (Tok.is(tok::kw_delete)) {
// In principle, an initializer of '= delete p;' is legal, but it will
@@ -3242,7 +3336,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
// yet.
if (getLangOpts().OpenCL && !NextToken().is(tok::colon))
return ParseCXXClassMemberDeclaration(AS, AccessAttrs);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_public:
case tok::kw_protected: {
if (getLangOpts().HLSL)
@@ -3688,7 +3782,8 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
? takeTemplateIdAnnotation(Tok)
: nullptr;
if (TemplateId && TemplateId->mightBeType()) {
- AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/ true);
+ AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::No,
+ /*IsClassName=*/true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TemplateTypeTy = getTypeAnnotation(Tok);
ConsumeAnnotationToken();
@@ -3721,7 +3816,6 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// Parse the optional expression-list.
ExprVector ArgExprs;
- CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&] {
if (TemplateTypeTy.isInvalid())
return QualType();
@@ -3731,8 +3825,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
CalledSignatureHelp = true;
return PreferredType;
};
- if (Tok.isNot(tok::r_paren) &&
- ParseExpressionList(ArgExprs, CommaLocs, [&] {
+ if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, [&] {
PreferredType.enterFunctionArgument(Tok.getLocation(),
RunSignatureHelp);
})) {
@@ -3980,7 +4073,7 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) {
Actions.ActOnStartTrailingRequiresClause(getCurScope(), D);
- llvm::Optional<Sema::CXXThisScopeRAII> ThisScope;
+ std::optional<Sema::CXXThisScopeRAII> ThisScope;
InitCXXThisScopeForDeclaratorIfRelevant(D, D.getDeclSpec(), ThisScope);
TrailingRequiresClause =
@@ -4405,8 +4498,6 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
Diag(Tok.getLocation(), diag::err_expected) << tok::colon;
}
- llvm::SmallDenseMap<IdentifierInfo *, SourceLocation, 4> SeenAttrs;
-
bool AttrParsed = false;
while (!Tok.isOneOf(tok::r_square, tok::semi, tok::eof)) {
if (AttrParsed) {
@@ -4717,7 +4808,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
<< Result.IsIfExists;
// Fall through to skip.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case IEB_Skip:
Braces.skipToEnd();
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index a6a946d7f31b..392ed29467a9 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -30,6 +30,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
/// Simple precedence-based parser for binary/ternary operators.
@@ -208,14 +209,14 @@ Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) {
return Actions.ActOnConstantExpression(Res);
}
-ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
+ExprResult Parser::ParseConstantExpression() {
// C++03 [basic.def.odr]p2:
// An expression is potentially evaluated unless it appears where an
// integral constant expression is required (see 5.19) [...].
// C++98 and C++11 have no such rule, but this is only a defect in C++98.
EnterExpressionEvaluationContext ConstantEvaluated(
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- return ParseConstantExpressionInExprEvalContext(isTypeCast);
+ return ParseConstantExpressionInExprEvalContext(NotTypeCast);
}
ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
@@ -943,9 +944,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
ParenParseOption ParenExprType;
switch (ParseKind) {
case CastParseKind::UnaryExprOnly:
- if (!getLangOpts().CPlusPlus)
- ParenExprType = CompoundLiteral;
- LLVM_FALLTHROUGH;
+ assert(getLangOpts().CPlusPlus && "not possible to get here in C");
+ [[fallthrough]];
case CastParseKind::AnyCastExpr:
ParenExprType = ParenParseOption::CastExpr;
break;
@@ -1004,7 +1004,12 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
break;
case tok::kw_nullptr:
- Diag(Tok, diag::warn_cxx98_compat_nullptr);
+ if (getLangOpts().CPlusPlus)
+ Diag(Tok, diag::warn_cxx98_compat_nullptr);
+ else
+ Diag(Tok, getLangOpts().C2x ? diag::warn_c17_compat_nullptr
+ : diag::ext_c_nullptr);
+
Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
break;
@@ -1038,9 +1043,10 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
isVectorLiteral, NotPrimaryExpression);
- case tok::identifier: { // primary-expression: identifier
- // unqualified-id: identifier
- // constant: enumeration-constant
+ case tok::identifier:
+ ParseIdentifier: { // primary-expression: identifier
+ // unqualified-id: identifier
+ // constant: enumeration-constant
// Turn a potentially qualified name into a annot_typename or
// annot_cxxscope if it would be valid. This handles things like x::y, etc.
if (getLangOpts().CPlusPlus) {
@@ -1068,6 +1074,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
REVERTIBLE_TYPE_TRAIT(__is_array);
REVERTIBLE_TYPE_TRAIT(__is_assignable);
REVERTIBLE_TYPE_TRAIT(__is_base_of);
+ REVERTIBLE_TYPE_TRAIT(__is_bounded_array);
REVERTIBLE_TYPE_TRAIT(__is_class);
REVERTIBLE_TYPE_TRAIT(__is_complete_type);
REVERTIBLE_TYPE_TRAIT(__is_compound);
@@ -1093,15 +1100,18 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
+ REVERTIBLE_TYPE_TRAIT(__is_nullptr);
REVERTIBLE_TYPE_TRAIT(__is_object);
REVERTIBLE_TYPE_TRAIT(__is_pod);
REVERTIBLE_TYPE_TRAIT(__is_pointer);
REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
REVERTIBLE_TYPE_TRAIT(__is_reference);
+ REVERTIBLE_TYPE_TRAIT(__is_referenceable);
REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
REVERTIBLE_TYPE_TRAIT(__is_same);
REVERTIBLE_TYPE_TRAIT(__is_scalar);
+ REVERTIBLE_TYPE_TRAIT(__is_scoped_enum);
REVERTIBLE_TYPE_TRAIT(__is_sealed);
REVERTIBLE_TYPE_TRAIT(__is_signed);
REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
@@ -1109,10 +1119,14 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
+ REVERTIBLE_TYPE_TRAIT(__is_unbounded_array);
REVERTIBLE_TYPE_TRAIT(__is_union);
REVERTIBLE_TYPE_TRAIT(__is_unsigned);
REVERTIBLE_TYPE_TRAIT(__is_void);
REVERTIBLE_TYPE_TRAIT(__is_volatile);
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
+ REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait));
+#include "clang/Basic/TransformTypeTraits.def"
#undef REVERTIBLE_TYPE_TRAIT
#undef RTT_JOIN
}
@@ -1357,7 +1371,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// Special treatment because of member pointers
SourceLocation SavedLoc = ConsumeToken();
PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc);
- Res = ParseCastExpression(AnyCastExpr, true);
+
+ Res = ParseCastExpression(AnyCastExpr, /*isAddressOfOperand=*/true);
if (!Res.isInvalid()) {
Expr *Arg = Res.get();
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg);
@@ -1382,7 +1397,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
Res = ParseCastExpression(AnyCastExpr);
if (!Res.isInvalid()) {
Expr *Arg = Res.get();
- Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg);
+ Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg,
+ isAddressOfOperand);
if (Res.isInvalid())
Res = Actions.CreateRecoveryExpr(SavedLoc, Arg->getEndLoc(), Arg);
}
@@ -1413,7 +1429,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')'
if (!getLangOpts().C11)
Diag(Tok, diag::ext_c11_feature) << Tok.getName();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_alignof: // unary-expression: 'alignof' '(' type-id ')'
case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
// unary-expression: '__alignof' '(' type-name ')'
@@ -1502,7 +1518,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
Ty.get(), nullptr);
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::annot_decltype:
case tok::kw_char:
@@ -1595,7 +1611,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
/*ObjectHasErrors=*/false,
/*EnteringContext=*/false);
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::Yes);
return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
isTypeCast, isVectorLiteral,
NotPrimaryExpression);
@@ -1614,14 +1630,14 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
// translate it into a type and continue parsing as a cast
// expression.
CXXScopeSpec SS;
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::Yes);
return ParseCastExpression(ParseKind, isAddressOfOperand,
NotCastExpr, isTypeCast, isVectorLiteral,
NotPrimaryExpression);
}
// Fall through to treat the template-id as an id-expression.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
@@ -1739,6 +1755,17 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
PreferredType.get(Tok.getLocation()));
return ExprError();
}
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+ // HACK: libstdc++ uses some of the transform-type-traits as alias
+ // templates, so we need to work around this.
+ if (!NextToken().is(tok::l_paren)) {
+ Tok.setKind(tok::identifier);
+ Diag(Tok, diag::ext_keyword_as_ident)
+ << Tok.getIdentifierInfo()->getName() << 0;
+ goto ParseIdentifier;
+ }
+ goto ExpectedExpression;
case tok::l_square:
if (getLangOpts().CPlusPlus11) {
if (getLangOpts().ObjC) {
@@ -1764,8 +1791,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
Res = ParseObjCMessageExpression();
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
+ ExpectedExpression:
NotCastExpr = true;
return ExprError();
}
@@ -1795,7 +1823,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
if (Tok.isAtStartOfLine())
return Res;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::period:
case tok::arrow:
break;
@@ -1883,7 +1911,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
break;
}
// Fall through; this isn't a message send.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default: // Not a postfix-expression suffix.
return LHS;
@@ -1934,14 +1962,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
ArgExprs.push_back(Idx.get());
}
} else if (Tok.isNot(tok::r_square)) {
- CommaLocsTy CommaLocs;
- if (ParseExpressionList(ArgExprs, CommaLocs)) {
+ if (ParseExpressionList(ArgExprs)) {
LHS = Actions.CorrectDelayedTyposInExpr(LHS);
HasError = true;
}
- assert(
- (ArgExprs.empty() || ArgExprs.size() == CommaLocs.size() + 1) &&
- "Unexpected number of commas!");
}
}
@@ -2003,10 +2027,9 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (OpKind == tok::lesslessless) {
ExprVector ExecConfigExprs;
- CommaLocsTy ExecConfigCommaLocs;
SourceLocation OpenLoc = ConsumeToken();
- if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
+ if (ParseSimpleExpressionList(ExecConfigExprs)) {
(void)Actions.CorrectDelayedTyposInExpr(LHS);
LHS = ExprError();
}
@@ -2046,7 +2069,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
}
ExprVector ArgExprs;
- CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&]() -> QualType {
QualType PreferredType = Actions.ProduceCallSignatureHelp(
LHS.get(), ArgExprs, PT.getOpenLocation());
@@ -2055,7 +2077,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
};
if (OpKind == tok::l_paren || !LHS.isInvalid()) {
if (Tok.isNot(tok::r_paren)) {
- if (ParseExpressionList(ArgExprs, CommaLocs, [&] {
+ if (ParseExpressionList(ArgExprs, [&] {
PreferredType.enterFunctionArgument(Tok.getLocation(),
RunSignatureHelp);
})) {
@@ -2093,9 +2115,6 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
PT.consumeClose();
LHS = ExprError();
} else {
- assert(
- (ArgExprs.size() == 0 || ArgExprs.size() - 1 == CommaLocs.size()) &&
- "Unexpected number of commas!");
Expr *Fn = LHS.get();
SourceLocation RParLoc = Tok.getLocation();
LHS = Actions.ActOnCallExpr(getCurScope(), Fn, Loc, ArgExprs, RParLoc,
@@ -2271,6 +2290,13 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
/// typeof ( expressions )
/// typeof ( type-name )
/// [GNU/C++] typeof unary-expression
+/// [C2x] typeof-specifier:
+/// typeof '(' typeof-specifier-argument ')'
+/// typeof_unqual '(' typeof-specifier-argument ')'
+///
+/// typeof-specifier-argument:
+/// expression
+/// type-name
///
/// [OpenCL 1.1 6.11.12] vec_step built-in function:
/// vec_step ( expressions )
@@ -2282,8 +2308,9 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
ParsedType &CastTy,
SourceRange &CastRange) {
- assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof,
- tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step,
+ assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual, tok::kw_sizeof,
+ tok::kw___alignof, tok::kw_alignof, tok::kw__Alignof,
+ tok::kw_vec_step,
tok::kw___builtin_omp_required_simd_align) &&
"Not a typeof/sizeof/alignof/vec_step expression!");
@@ -2319,7 +2346,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
}
isCastExpr = false;
- if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) {
+ if (OpTok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual) &&
+ !getLangOpts().CPlusPlus) {
Diag(Tok, diag::err_expected_after) << OpTok.getIdentifierInfo()
<< tok::l_paren;
return ExprError();
@@ -2345,7 +2373,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
return ExprEmpty();
}
- if (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) {
+ if (getLangOpts().CPlusPlus ||
+ !OpTok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual)) {
// GNU typeof in C requires the expression to be parenthesized. Not so for
// sizeof/alignof or in C++. Therefore, the parenthesized expression is
// the start of a unary-expression, but doesn't include any postfix
@@ -2563,10 +2592,21 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
}
case tok::kw___builtin_offsetof: {
SourceLocation TypeLoc = Tok.getLocation();
- TypeResult Ty = ParseTypeName();
- if (Ty.isInvalid()) {
- SkipUntil(tok::r_paren, StopAtSemi);
- return ExprError();
+ auto OOK = Sema::OffsetOfKind::OOK_Builtin;
+ if (Tok.getLocation().isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
+ Tok.getLocation(), PP.getSourceManager(), getLangOpts());
+ if (MacroName == "offsetof")
+ OOK = Sema::OffsetOfKind::OOK_Macro;
+ }
+ TypeResult Ty;
+ {
+ OffsetOfStateRAIIObject InOffsetof(*this, OOK);
+ Ty = ParseTypeName();
+ if (Ty.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return ExprError();
+ }
}
if (ExpectAndConsume(tok::comma)) {
@@ -2589,6 +2629,12 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken();
+ enum class Kind { MemberAccess, ArraySubscript };
+ auto DiagExt = [&](SourceLocation Loc, Kind K) {
+ Diag(Loc, diag::ext_offsetof_member_designator)
+ << (K == Kind::ArraySubscript) << (OOK == Sema::OOK_Macro);
+ };
+
// FIXME: This loop leaks the index expressions on error.
while (true) {
if (Tok.is(tok::period)) {
@@ -2602,9 +2648,9 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
SkipUntil(tok::r_paren, StopAtSemi);
return ExprError();
}
+ DiagExt(Comps.back().LocStart, Kind::MemberAccess);
Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
Comps.back().LocEnd = ConsumeToken();
-
} else if (Tok.is(tok::l_square)) {
if (CheckProhibitedCXX11Attribute())
return ExprError();
@@ -2620,6 +2666,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
SkipUntil(tok::r_paren, StopAtSemi);
return Res;
}
+ DiagExt(Comps.back().LocStart, Kind::ArraySubscript);
Comps.back().U.E = Res.get();
ST.consumeClose();
@@ -3089,11 +3136,9 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
} else if (isTypeCast) {
// Parse the expression-list.
InMessageExpressionRAIIObject InMessage(*this, false);
-
ExprVector ArgExprs;
- CommaLocsTy CommaLocs;
- if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) {
+ if (!ParseSimpleExpressionList(ArgExprs)) {
// FIXME: If we ever support comma expressions as operands to
// fold-expressions, we'll need to allow multiple ArgExprs here.
if (ExprType >= FoldExpr && ArgExprs.size() == 1 &&
@@ -3142,7 +3187,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
InMessageExpressionRAIIObject InMessage(*this, false);
Result = ParseExpression(MaybeTypeCast);
- if (!getLangOpts().CPlusPlus && MaybeTypeCast && Result.isUsable()) {
+ if (!getLangOpts().CPlusPlus && Result.isUsable()) {
// Correct typos in non-C++ code earlier so that implicit-cast-like
// expressions are parsed correctly.
Result = Actions.CorrectDelayedTyposInExpr(Result);
@@ -3263,7 +3308,7 @@ ExprResult Parser::ParseGenericSelectionExpression() {
}
SourceLocation DefaultLoc;
- TypeVector Types;
+ SmallVector<ParsedType, 12> Types;
ExprVector Exprs;
do {
ParsedType Ty;
@@ -3392,7 +3437,6 @@ ExprResult Parser::ParseFoldExpression(ExprResult LHS,
/// [C++0x] braced-init-list
/// \endverbatim
bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
- SmallVectorImpl<SourceLocation> &CommaLocs,
llvm::function_ref<void()> ExpressionStarts,
bool FailImmediatelyOnInvalidExpr,
bool EarlyTypoCorrection) {
@@ -3436,8 +3480,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
break;
// Move to the next argument, remember where the comma was.
Token Comma = Tok;
- CommaLocs.push_back(ConsumeToken());
-
+ ConsumeToken();
checkPotentialAngleBracketDelimiter(Comma);
}
if (SawError) {
@@ -3459,9 +3502,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
/// assignment-expression
/// simple-expression-list , assignment-expression
/// \endverbatim
-bool
-Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
- SmallVectorImpl<SourceLocation> &CommaLocs) {
+bool Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr *> &Exprs) {
while (true) {
ExprResult Expr = ParseAssignmentExpression();
if (Expr.isInvalid())
@@ -3469,13 +3510,14 @@ Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
Exprs.push_back(Expr.get());
- if (Tok.isNot(tok::comma))
+ // We might be parsing the LHS of a fold-expression. If we reached the fold
+ // operator, stop.
+ if (Tok.isNot(tok::comma) || NextToken().is(tok::ellipsis))
return false;
// Move to the next argument, remember where the comma was.
Token Comma = Tok;
- CommaLocs.push_back(ConsumeToken());
-
+ ConsumeToken();
checkPotentialAngleBracketDelimiter(Comma);
}
}
@@ -3589,8 +3631,8 @@ ExprResult Parser::ParseBlockLiteralExpression() {
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
- /*DeclsInPrototype=*/None, CaretLoc,
- CaretLoc, ParamInfo),
+ /*DeclsInPrototype=*/std::nullopt,
+ CaretLoc, CaretLoc, ParamInfo),
CaretLoc);
MaybeParseGNUAttributes(ParamInfo);
@@ -3671,7 +3713,7 @@ static bool CheckAvailabilitySpecList(Parser &P,
/// availability-spec:
/// '*'
/// identifier version-tuple
-Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
+std::optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
if (Tok.is(tok::star)) {
return AvailabilitySpec(ConsumeToken());
} else {
@@ -3679,11 +3721,11 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
if (Tok.is(tok::code_completion)) {
cutOffParsing();
Actions.CodeCompleteAvailabilityPlatformName();
- return None;
+ return std::nullopt;
}
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_avail_query_expected_platform_name);
- return None;
+ return std::nullopt;
}
IdentifierLoc *PlatformIdentifier = ParseIdentifierLoc();
@@ -3691,7 +3733,7 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
VersionTuple Version = ParseVersionTuple(VersionRange);
if (Version.empty())
- return None;
+ return std::nullopt;
StringRef GivenPlatform = PlatformIdentifier->Ident->getName();
StringRef Platform =
@@ -3701,7 +3743,7 @@ Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
Diag(PlatformIdentifier->Loc,
diag::err_avail_query_unrecognized_platform_name)
<< GivenPlatform;
- return None;
+ return std::nullopt;
}
return AvailabilitySpec(Version, Platform, PlatformIdentifier->Loc,
@@ -3723,7 +3765,7 @@ ExprResult Parser::ParseAvailabilityCheckExpr(SourceLocation BeginLoc) {
SmallVector<AvailabilitySpec, 4> AvailSpecs;
bool HasError = false;
while (true) {
- Optional<AvailabilitySpec> Spec = ParseAvailabilitySpec();
+ std::optional<AvailabilitySpec> Spec = ParseAvailabilitySpec();
if (!Spec)
HasError = true;
else
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 9bd89eddb455..7f09120574a7 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
@@ -21,6 +22,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <numeric>
@@ -979,11 +981,10 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
InitKind = LambdaCaptureInitKind::DirectInit;
ExprVector Exprs;
- CommaLocsTy Commas;
if (Tentative) {
Parens.skipToEnd();
*Tentative = LambdaIntroducerTentativeParse::Incomplete;
- } else if (ParseExpressionList(Exprs, Commas)) {
+ } else if (ParseExpressionList(Exprs)) {
Parens.skipToEnd();
Init = ExprError();
} else {
@@ -1156,51 +1157,66 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
static void tryConsumeLambdaSpecifierToken(Parser &P,
SourceLocation &MutableLoc,
+ SourceLocation &StaticLoc,
SourceLocation &ConstexprLoc,
SourceLocation &ConstevalLoc,
SourceLocation &DeclEndLoc) {
assert(MutableLoc.isInvalid());
+ assert(StaticLoc.isInvalid());
assert(ConstexprLoc.isInvalid());
+ assert(ConstevalLoc.isInvalid());
// Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc
// to the final of those locations. Emit an error if we have multiple
// copies of those keywords and recover.
+ auto ConsumeLocation = [&P, &DeclEndLoc](SourceLocation &SpecifierLoc,
+ int DiagIndex) {
+ if (SpecifierLoc.isValid()) {
+ P.Diag(P.getCurToken().getLocation(),
+ diag::err_lambda_decl_specifier_repeated)
+ << DiagIndex
+ << FixItHint::CreateRemoval(P.getCurToken().getLocation());
+ }
+ SpecifierLoc = P.ConsumeToken();
+ DeclEndLoc = SpecifierLoc;
+ };
+
while (true) {
switch (P.getCurToken().getKind()) {
- case tok::kw_mutable: {
- if (MutableLoc.isValid()) {
- P.Diag(P.getCurToken().getLocation(),
- diag::err_lambda_decl_specifier_repeated)
- << 0 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
- }
- MutableLoc = P.ConsumeToken();
- DeclEndLoc = MutableLoc;
- break /*switch*/;
- }
+ case tok::kw_mutable:
+ ConsumeLocation(MutableLoc, 0);
+ break;
+ case tok::kw_static:
+ ConsumeLocation(StaticLoc, 1);
+ break;
case tok::kw_constexpr:
- if (ConstexprLoc.isValid()) {
- P.Diag(P.getCurToken().getLocation(),
- diag::err_lambda_decl_specifier_repeated)
- << 1 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
- }
- ConstexprLoc = P.ConsumeToken();
- DeclEndLoc = ConstexprLoc;
- break /*switch*/;
+ ConsumeLocation(ConstexprLoc, 2);
+ break;
case tok::kw_consteval:
- if (ConstevalLoc.isValid()) {
- P.Diag(P.getCurToken().getLocation(),
- diag::err_lambda_decl_specifier_repeated)
- << 2 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
- }
- ConstevalLoc = P.ConsumeToken();
- DeclEndLoc = ConstevalLoc;
- break /*switch*/;
+ ConsumeLocation(ConstevalLoc, 3);
+ break;
default:
return;
}
}
}
+static void addStaticToLambdaDeclSpecifier(Parser &P, SourceLocation StaticLoc,
+ DeclSpec &DS) {
+ if (StaticLoc.isValid()) {
+ P.Diag(StaticLoc, !P.getLangOpts().CPlusPlus2b
+ ? diag::err_static_lambda
+ : diag::warn_cxx20_compat_static_lambda);
+ const char *PrevSpec = nullptr;
+ unsigned DiagID = 0;
+ DS.SetStorageClassSpec(P.getActions(), DeclSpec::SCS_static, StaticLoc,
+ PrevSpec, DiagID,
+ P.getActions().getASTContext().getPrintingPolicy());
+ assert(PrevSpec == nullptr && DiagID == 0 &&
+ "Static cannot have been set previously!");
+ }
+}
+
static void
addConstexprToLambdaDeclSpecifier(Parser &P, SourceLocation ConstexprLoc,
DeclSpec &DS) {
@@ -1231,6 +1247,24 @@ static void addConstevalToLambdaDeclSpecifier(Parser &P,
}
}
+static void DiagnoseStaticSpecifierRestrictions(Parser &P,
+ SourceLocation StaticLoc,
+ SourceLocation MutableLoc,
+ const LambdaIntroducer &Intro) {
+ if (StaticLoc.isInvalid())
+ return;
+
+ // [expr.prim.lambda.general] p4
+ // The lambda-specifier-seq shall not contain both mutable and static.
+ // If the lambda-specifier-seq contains static, there shall be no
+ // lambda-capture.
+ if (MutableLoc.isValid())
+ P.Diag(StaticLoc, diag::err_static_mutable_lambda);
+ if (Intro.hasLambdaCapture()) {
+ P.Diag(StaticLoc, diag::err_static_lambda_captures);
+ }
+}
+
/// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
/// expression.
ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
@@ -1256,7 +1290,22 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
if (getLangOpts().CUDA) {
// In CUDA code, GNU attributes are allowed to appear immediately after the
// "[...]", even if there is no "(...)" before the lambda body.
- MaybeParseGNUAttributes(D);
+ //
+ // Note that we support __noinline__ as a keyword in this mode and thus
+ // it has to be separately handled.
+ while (true) {
+ if (Tok.is(tok::kw___noinline__)) {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
+ SourceLocation AttrNameLoc = ConsumeToken();
+ Attr.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0,
+ ParsedAttr::AS_Keyword);
+ } else if (Tok.is(tok::kw___attribute))
+ ParseGNUAttributes(Attr, nullptr, &D);
+ else
+ break;
+ }
+
+ D.takeAttributes(Attr);
}
// Helper to emit a warning if we see a CUDA host/device/global attribute
@@ -1330,14 +1379,18 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// the mutable specifier to be compatible with MSVC.
MaybeParseAttributes(PAKM_GNU | PAKM_Declspec, Attr);
- // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update
- // the DeclEndLoc.
+ // Parse lambda specifiers and update the DeclEndLoc.
SourceLocation MutableLoc;
+ SourceLocation StaticLoc;
SourceLocation ConstexprLoc;
SourceLocation ConstevalLoc;
- tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
- ConstevalLoc, DeclEndLoc);
+ tryConsumeLambdaSpecifierToken(*this, MutableLoc, StaticLoc,
+ ConstexprLoc, ConstevalLoc, DeclEndLoc);
+
+ DiagnoseStaticSpecifierRestrictions(*this, StaticLoc, MutableLoc,
+ Intro);
+ addStaticToLambdaDeclSpecifier(*this, StaticLoc, DS);
addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
// Parse exception-specification[opt].
@@ -1390,8 +1443,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DynamicExceptions.size(),
NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr,
/*ExceptionSpecTokens*/ nullptr,
- /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D,
- TrailingReturnType, TrailingReturnTypeLoc, &DS),
+ /*DeclsInPrototype=*/std::nullopt, LParenLoc, FunLocalRangeEnd,
+ D, TrailingReturnType, TrailingReturnTypeLoc, &DS),
std::move(Attr), DeclEndLoc);
};
@@ -1412,8 +1465,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Actions.RecordParsingTemplateParameterDepth(
CurTemplateDepthTracker.getOriginalDepth());
- ParseParameterDeclarationClause(D.getContext(), Attr, ParamInfo,
- EllipsisLoc);
+ ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc);
// For a generic lambda, each 'auto' within the parameter declaration
// clause creates a template type parameter, so increment the depth.
// If we've parsed any explicit template parameters, then the depth will
@@ -1433,10 +1485,11 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
if (Tok.is(tok::kw_requires))
ParseTrailingRequiresClause(D);
} else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
- tok::kw_constexpr, tok::kw_consteval,
+ tok::kw_constexpr, tok::kw_consteval, tok::kw_static,
tok::kw___private, tok::kw___global, tok::kw___local,
tok::kw___constant, tok::kw___generic,
- tok::kw_requires, tok::kw_noexcept) ||
+ tok::kw_groupshared, tok::kw_requires,
+ tok::kw_noexcept) ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
if (!getLangOpts().CPlusPlus2b)
// It's common to forget that one needs '()' before 'mutable', an
@@ -1520,7 +1573,8 @@ ExprResult Parser::ParseCXXCasts() {
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
- ParseSpecifierQualifierList(DS);
+ ParseSpecifierQualifierList(DS, /*AccessSpecifier=*/AS_none,
+ DeclSpecContext::DSC_type_specifier);
// Parse the abstract-declarator, if present.
Declarator DeclaratorInfo(DS, ParsedAttributesView::none(),
@@ -1874,7 +1928,6 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
PreferredType.enterTypeCast(Tok.getLocation(), TypeRep.get());
ExprVector Exprs;
- CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&]() {
QualType PreferredType;
@@ -1887,7 +1940,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
};
if (Tok.isNot(tok::r_paren)) {
- if (ParseExpressionList(Exprs, CommaLocs, [&] {
+ if (ParseExpressionList(Exprs, [&] {
PreferredType.enterFunctionArgument(Tok.getLocation(),
RunSignatureHelp);
})) {
@@ -1905,8 +1958,6 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
if (!TypeRep)
return ExprError();
- assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
- "Unexpected number of commas!");
return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(),
Exprs, T.getCloseLocation(),
/*ListInitialization=*/false);
@@ -2318,8 +2369,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
/// type-specifier-seq: [C++ 8.1]
/// type-specifier type-specifier-seq[opt]
///
-bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
- ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_type_specifier);
+bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS, DeclaratorContext Context) {
+ ParseSpecifierQualifierList(DS, AS_none,
+ getDeclSpecContextFromDeclaratorContext(Context));
DS.Finish(Actions, Actions.getASTContext().getPrintingPolicy());
return false;
}
@@ -2735,7 +2787,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// Parse the type-specifier-seq.
DeclSpec DS(AttrFactory);
- if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType?
+ if (ParseCXXTypeSpecifierSeq(
+ DS, DeclaratorContext::ConversionId)) // FIXME: ObjectType?
return true;
// Parse the conversion-declarator, which is merely a sequence of
@@ -2819,6 +2872,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
// identifier
// template-id (when it hasn't already been annotated)
if (Tok.is(tok::identifier)) {
+ ParseIdentifier:
// Consume the identifier.
IdentifierInfo *Id = Tok.getIdentifierInfo();
SourceLocation IdLoc = ConsumeToken();
@@ -3053,9 +3107,20 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType,
return false;
}
- Diag(Tok, diag::err_expected_unqualified_id)
- << getLangOpts().CPlusPlus;
- return true;
+ switch (Tok.getKind()) {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+ if (!NextToken().is(tok::l_paren)) {
+ Tok.setKind(tok::identifier);
+ Diag(Tok, diag::ext_keyword_as_ident)
+ << Tok.getIdentifierInfo()->getName() << 0;
+ goto ParseIdentifier;
+ }
+ [[fallthrough]];
+ default:
+ Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
+ return true;
+ }
}
/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate
@@ -3170,7 +3235,6 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
T.consumeOpen();
ConstructorLParen = T.getOpenLocation();
if (Tok.isNot(tok::r_paren)) {
- CommaLocsTy CommaLocs;
auto RunSignatureHelp = [&]() {
ParsedType TypeRep =
Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
@@ -3186,7 +3250,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
CalledSignatureHelp = true;
return PreferredType;
};
- if (ParseExpressionList(ConstructorArgs, CommaLocs, [&] {
+ if (ParseExpressionList(ConstructorArgs, [&] {
PreferredType.enterFunctionArgument(Tok.getLocation(),
RunSignatureHelp);
})) {
@@ -3285,9 +3349,7 @@ bool Parser::ParseExpressionListOrTypeId(
}
// It's not a type, it has to be an expression list.
- // Discard the comma locations - ActOnCXXNew has enough parameters.
- CommaLocsTy CommaLocs;
- return ParseExpressionList(PlacementArgs, CommaLocs);
+ return ParseExpressionList(PlacementArgs);
}
/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used
@@ -3447,6 +3509,10 @@ ExprResult Parser::ParseRequiresExpression() {
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
ParseScope BodyScope(this, Scope::DeclScope);
+ // Create a separate diagnostic pool for RequiresExprBodyDecl.
+ // Dependent diagnostics are attached to this Decl and non-depenedent
+ // diagnostics are surfaced after this parse.
+ ParsingDeclRAIIObject ParsingBodyDecl(*this, ParsingDeclRAIIObject::NoParent);
RequiresExprBodyDecl *Body = Actions.ActOnStartRequiresExpr(
RequiresKWLoc, LocalParameterDecls, getCurScope());
@@ -3684,6 +3750,7 @@ ExprResult Parser::ParseRequiresExpression() {
}
Braces.consumeClose();
Actions.ActOnFinishRequiresExpr();
+ ParsingBodyDecl.complete(Body);
return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls,
Requirements, Braces.getCloseLocation());
}
@@ -3724,14 +3791,6 @@ static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) {
}
}
-static unsigned TypeTraitArity(tok::TokenKind kind) {
- switch (kind) {
- default: llvm_unreachable("Not a known type trait");
-#define TYPE_TRAIT(N,Spelling,K) case tok::kw_##Spelling: return N;
-#include "clang/Basic/TokenKinds.def"
- }
-}
-
/// Parse the built-in type-trait pseudo-functions that allow
/// implementation of the TR1/C++11 type traits templates.
///
@@ -3745,7 +3804,6 @@ static unsigned TypeTraitArity(tok::TokenKind kind) {
///
ExprResult Parser::ParseTypeTrait() {
tok::TokenKind Kind = Tok.getKind();
- unsigned Arity = TypeTraitArity(Kind);
SourceLocation Loc = ConsumeToken();
@@ -3780,18 +3838,6 @@ ExprResult Parser::ParseTypeTrait() {
SourceLocation EndLoc = Parens.getCloseLocation();
- if (Arity && Args.size() != Arity) {
- Diag(EndLoc, diag::err_type_trait_arity)
- << Arity << 0 << (Arity > 1) << (int)Args.size() << SourceRange(Loc);
- return ExprError();
- }
-
- if (!Arity && Args.empty()) {
- Diag(EndLoc, diag::err_type_trait_arity)
- << 1 << 1 << 1 << (int)Args.size() << SourceRange(Loc);
- return ExprError();
- }
-
return Actions.ActOnTypeTrait(TypeTraitFromTokKind(Kind), Loc, Args, EndLoc);
}
diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
index ed1f81dc4ee8..ebda84de6a97 100644
--- a/clang/lib/Parse/ParseHLSL.cpp
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -10,33 +10,191 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
using namespace clang;
+static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG,
+ SourceLocation BufferLoc,
+ bool IsCBuffer, Parser &P) {
+ // The parse is failed, just return false.
+ if (!DG)
+ return false;
+ DeclGroupRef Decls = DG.get();
+ bool IsValid = true;
+ // Only allow function, variable, record decls inside HLSLBuffer.
+ for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) {
+ Decl *D = *I;
+ if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D))
+ continue;
+
+ // FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer.
+ if (isa<HLSLBufferDecl, NamespaceDecl>(D)) {
+ P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
+ << IsCBuffer;
+ IsValid = false;
+ continue;
+ }
+
+ IsValid = false;
+ P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer)
+ << IsCBuffer;
+ }
+ return IsValid;
+}
+
+Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) {
+ assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) &&
+ "Not a cbuffer or tbuffer!");
+ bool IsCBuffer = Tok.is(tok::kw_cbuffer);
+ SourceLocation BufferLoc = ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'.
+
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok, diag::err_expected) << tok::identifier;
+ return nullptr;
+ }
+
+ IdentifierInfo *Identifier = Tok.getIdentifierInfo();
+ SourceLocation IdentifierLoc = ConsumeToken();
+
+ ParsedAttributes Attrs(AttrFactory);
+ MaybeParseHLSLSemantics(Attrs, nullptr);
+
+ ParseScope BufferScope(this, Scope::DeclScope);
+ BalancedDelimiterTracker T(*this, tok::l_brace);
+ if (T.consumeOpen()) {
+ Diag(Tok, diag::err_expected) << tok::l_brace;
+ return nullptr;
+ }
+
+ Decl *D = Actions.ActOnStartHLSLBuffer(getCurScope(), IsCBuffer, BufferLoc,
+ Identifier, IdentifierLoc,
+ T.getOpenLocation());
+
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ // FIXME: support attribute on constants inside cbuffer/tbuffer.
+ ParsedAttributes DeclAttrs(AttrFactory);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+
+ DeclGroupPtrTy Result =
+ ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs);
+ if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer,
+ *this)) {
+ T.skipToEnd();
+ DeclEnd = T.getCloseLocation();
+ BufferScope.Exit();
+ Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
+ return nullptr;
+ }
+ }
+
+ T.consumeClose();
+ DeclEnd = T.getCloseLocation();
+ BufferScope.Exit();
+ Actions.ActOnFinishHLSLBuffer(D, DeclEnd);
+
+ Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs);
+ return D;
+}
+
+static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc,
+ Token Tok, ArgsVector &ArgExprs,
+ Parser &P, ASTContext &Ctx,
+ Preprocessor &PP) {
+ StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength());
+ SourceLocation EndNumLoc = Tok.getEndLoc();
+
+ P.ConsumeToken(); // consume constant.
+ std::string FixedArg = ArgStr.str() + Num.str();
+ P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number)
+ << FixedArg
+ << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg);
+ ArgsUnion &Slot = ArgExprs.back();
+ Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg));
+}
+
void Parser::ParseHLSLSemantics(ParsedAttributes &Attrs,
SourceLocation *EndLoc) {
+ // FIXME: HLSLSemantic is shared for Semantic and resource binding which is
+ // confusing. Need a better name to avoid misunderstanding. Issue
+ // https://github.com/llvm/llvm-project/issues/57882
assert(Tok.is(tok::colon) && "Not a HLSL Semantic");
ConsumeToken();
- if (!Tok.is(tok::identifier)) {
+ IdentifierInfo *II = nullptr;
+ if (Tok.is(tok::kw_register))
+ II = PP.getIdentifierInfo("register");
+ else if (Tok.is(tok::identifier))
+ II = Tok.getIdentifierInfo();
+
+ if (!II) {
Diag(Tok.getLocation(), diag::err_expected_semantic_identifier);
return;
}
- IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation Loc = ConsumeToken();
if (EndLoc)
*EndLoc = Tok.getLocation();
ParsedAttr::Kind AttrKind =
ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLSemantic);
- if (AttrKind == ParsedAttr::UnknownAttribute) {
+ ArgsVector ArgExprs;
+ switch (AttrKind) {
+ case ParsedAttr::AT_HLSLResourceBinding: {
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) {
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ StringRef SlotStr = Tok.getIdentifierInfo()->getName();
+ SourceLocation SlotLoc = Tok.getLocation();
+ ArgExprs.push_back(ParseIdentifierLoc());
+
+ // Add numeric_constant for fix-it.
+ if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant))
+ fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this,
+ Actions.Context, PP);
+
+ if (Tok.is(tok::comma)) {
+ ConsumeToken(); // consume comma
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ StringRef SpaceStr = Tok.getIdentifierInfo()->getName();
+ SourceLocation SpaceLoc = Tok.getLocation();
+ ArgExprs.push_back(ParseIdentifierLoc());
+
+ // Add numeric_constant for fix-it.
+ if (SpaceStr.equals("space") && Tok.is(tok::numeric_constant))
+ fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this,
+ Actions.Context, PP);
+ }
+ if (ExpectAndConsume(tok::r_paren, diag::err_expected)) {
+ SkipUntil(tok::r_paren, StopAtSemi); // skip through )
+ return;
+ }
+ } break;
+ case ParsedAttr::UnknownAttribute:
Diag(Loc, diag::err_unknown_hlsl_semantic) << II;
return;
+ case ParsedAttr::AT_HLSLSV_GroupIndex:
+ case ParsedAttr::AT_HLSLSV_DispatchThreadID:
+ break;
+ default:
+ llvm_unreachable("invalid HLSL Semantic");
+ break;
}
- Attrs.addNew(II, Loc, nullptr, SourceLocation(), nullptr, 0,
- ParsedAttr::AS_HLSLSemantic);
+
+ Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(),
+ ArgExprs.size(), ParsedAttr::AS_HLSLSemantic);
}
diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp
index fd0faba9c1c1..af0c3b47958d 100644
--- a/clang/lib/Parse/ParseInit.cpp
+++ b/clang/lib/Parse/ParseInit.cpp
@@ -451,7 +451,7 @@ ExprResult Parser::ParseBraceInitializer() {
if (!getLangOpts().CPlusPlus)
Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
// Match the '}'.
- return Actions.ActOnInitList(LBraceLoc, None, ConsumeBrace());
+ return Actions.ActOnInitList(LBraceLoc, std::nullopt, ConsumeBrace());
}
// Enter an appropriate expression evaluation context for an initializer list.
@@ -565,7 +565,7 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
Diag(Result.KeywordLoc, diag::warn_microsoft_dependent_exists)
<< Result.IsIfExists;
// Fall through to skip.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case IEB_Skip:
Braces.skipToEnd();
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 734c66f65dc2..079bf9a9c08c 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ODRDiagsEmitter.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
@@ -45,7 +46,11 @@ void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
/// [OBJC] objc-protocol-definition
/// [OBJC] objc-method-definition
/// [OBJC] '@' 'end'
-Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives(ParsedAttributes &Attrs) {
+Parser::DeclGroupPtrTy
+Parser::ParseObjCAtDirectives(ParsedAttributes &DeclAttrs,
+ ParsedAttributes &DeclSpecAttrs) {
+ DeclAttrs.takeAllFrom(DeclSpecAttrs);
+
SourceLocation AtLoc = ConsumeToken(); // the "@"
if (Tok.is(tok::code_completion)) {
@@ -54,17 +59,29 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives(ParsedAttributes &Attrs) {
return nullptr;
}
+ switch (Tok.getObjCKeywordID()) {
+ case tok::objc_interface:
+ case tok::objc_protocol:
+ case tok::objc_implementation:
+ break;
+ default:
+ llvm::for_each(DeclAttrs, [this](const auto &Attr) {
+ if (Attr.isGNUAttribute())
+ Diag(Tok.getLocation(), diag::err_objc_unexpected_attr);
+ });
+ }
+
Decl *SingleDecl = nullptr;
switch (Tok.getObjCKeywordID()) {
case tok::objc_class:
return ParseObjCAtClassDeclaration(AtLoc);
case tok::objc_interface:
- SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, Attrs);
+ SingleDecl = ParseObjCAtInterfaceDeclaration(AtLoc, DeclAttrs);
break;
case tok::objc_protocol:
- return ParseObjCAtProtocolDeclaration(AtLoc, Attrs);
+ return ParseObjCAtProtocolDeclaration(AtLoc, DeclAttrs);
case tok::objc_implementation:
- return ParseObjCAtImplementationDeclaration(AtLoc, Attrs);
+ return ParseObjCAtImplementationDeclaration(AtLoc, DeclAttrs);
case tok::objc_end:
return ParseObjCAtEndDeclaration(AtLoc);
case tok::objc_compatibility_alias:
@@ -353,17 +370,30 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
Actions.ActOnTypedefedProtocols(protocols, protocolLocs,
superClassId, superClassLoc);
+ Sema::SkipBodyInfo SkipBody;
ObjCInterfaceDecl *ClsType = Actions.ActOnStartClassInterface(
getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,
superClassLoc, typeArgs,
SourceRange(typeArgsLAngleLoc, typeArgsRAngleLoc), protocols.data(),
- protocols.size(), protocolLocs.data(), EndProtoLoc, attrs);
+ protocols.size(), protocolLocs.data(), EndProtoLoc, attrs, &SkipBody);
if (Tok.is(tok::l_brace))
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
+ if (SkipBody.CheckSameAsPrevious) {
+ auto *PreviousDef = cast<ObjCInterfaceDecl>(SkipBody.Previous);
+ if (Actions.ActOnDuplicateODRHashDefinition(ClsType, PreviousDef)) {
+ ClsType->mergeDuplicateDefinitionWithCommon(PreviousDef->getDefinition());
+ } else {
+ ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),
+ getPreprocessor().getLangOpts());
+ DiagsEmitter.diagnoseMismatch(PreviousDef, ClsType);
+ ClsType->setInvalidDecl();
+ }
+ }
+
return ClsType;
}
@@ -650,7 +680,8 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
if (Tok.is(tok::r_brace))
break;
- ParsedAttributes EmptyAttrs(AttrFactory);
+ ParsedAttributes EmptyDeclAttrs(AttrFactory);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
// Since we call ParseDeclarationOrFunctionDefinition() instead of
// ParseExternalDeclaration() below (so that this doesn't parse nested
@@ -658,13 +689,14 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
SourceLocation DeclEnd;
ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
- allTUVariables.push_back(ParseDeclaration(
- DeclaratorContext::File, DeclEnd, EmptyAttrs, EmptyDeclSpecAttrs));
+ allTUVariables.push_back(ParseDeclaration(DeclaratorContext::File,
+ DeclEnd, EmptyDeclAttrs,
+ EmptyDeclSpecAttrs));
continue;
}
- allTUVariables.push_back(
- ParseDeclarationOrFunctionDefinition(EmptyAttrs));
+ allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(
+ EmptyDeclAttrs, EmptyDeclSpecAttrs));
continue;
}
@@ -2088,11 +2120,23 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
/*consumeLastToken=*/true))
return nullptr;
- Decl *ProtoType = Actions.ActOnStartProtocolInterface(
+ Sema::SkipBodyInfo SkipBody;
+ ObjCProtocolDecl *ProtoType = Actions.ActOnStartProtocolInterface(
AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(),
- ProtocolLocs.data(), EndProtoLoc, attrs);
+ ProtocolLocs.data(), EndProtoLoc, attrs, &SkipBody);
ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType);
+ if (SkipBody.CheckSameAsPrevious) {
+ auto *PreviousDef = cast<ObjCProtocolDecl>(SkipBody.Previous);
+ if (Actions.ActOnDuplicateODRHashDefinition(ProtoType, PreviousDef)) {
+ ProtoType->mergeDuplicateDefinitionWithCommon(
+ PreviousDef->getDefinition());
+ } else {
+ ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(),
+ getPreprocessor().getLangOpts());
+ DiagsEmitter.diagnoseMismatch(PreviousDef, ProtoType);
+ }
+ }
return Actions.ConvertDeclToDeclGroup(ProtoType);
}
@@ -2223,9 +2267,11 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc,
{
ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
while (!ObjCImplParsing.isFinished() && !isEofOrEom()) {
- ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
+ ParsedAttributes DeclAttrs(AttrFactory);
+ MaybeParseCXX11Attributes(DeclAttrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ if (DeclGroupPtrTy DGP =
+ ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs)) {
DeclGroupRef DG = DGP.get();
DeclsInGroup.append(DG.begin(), DG.end());
}
@@ -3168,14 +3214,14 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
if (Tok.is(tok::code_completion)) {
cutOffParsing();
if (SuperLoc.isValid())
- Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc, None,
- false);
+ Actions.CodeCompleteObjCSuperMessage(getCurScope(), SuperLoc,
+ std::nullopt, false);
else if (ReceiverType)
- Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, None,
- false);
+ Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType,
+ std::nullopt, false);
else
Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr,
- None, false);
+ std::nullopt, false);
return ExprError();
}
@@ -3507,9 +3553,8 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// We have a valid expression. Collect it in a vector so we can
// build the argument list.
- ObjCDictionaryElement Element = {
- KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None
- };
+ ObjCDictionaryElement Element = {KeyExpr.get(), ValueExpr.get(),
+ EllipsisLoc, std::nullopt};
Elements.push_back(Element);
if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 5f53f9d684e7..a31ceaeebd80 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -25,6 +25,7 @@
#include "llvm/ADT/UniqueVector.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPContext.h"
+#include <optional>
using namespace clang;
using namespace llvm::omp;
@@ -198,8 +199,8 @@ static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) {
if (DKind == OMPD_unknown)
return OMPD_unknown;
- for (unsigned I = 0; I < llvm::array_lengthof(F); ++I) {
- if (DKind != F[I][0])
+ for (const auto &I : F) {
+ if (DKind != I[0])
continue;
Tok = P.getPreprocessor().LookAhead(0);
@@ -210,9 +211,9 @@ static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) {
if (SDKind == OMPD_unknown)
continue;
- if (SDKind == F[I][1]) {
+ if (SDKind == I[1]) {
P.ConsumeToken();
- DKind = F[I][2];
+ DKind = I[2];
}
}
return unsigned(DKind) < llvm::omp::Directive_enumSize
@@ -259,7 +260,7 @@ static DeclarationName parseOpenMPReductionId(Parser &P) {
case tok::identifier: // identifier
if (!WithOperator)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier);
P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
@@ -475,7 +476,6 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
T.consumeOpen();
ExprVector Exprs;
- CommaLocsTy CommaLocs;
SourceLocation LParLoc = T.getOpenLocation();
auto RunSignatureHelp = [this, OmpPrivParm, LParLoc, &Exprs]() {
@@ -485,7 +485,7 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
CalledSignatureHelp = true;
return PreferredType;
};
- if (ParseExpressionList(Exprs, CommaLocs, [&] {
+ if (ParseExpressionList(Exprs, [&] {
PreferredType.enterFunctionArgument(Tok.getLocation(),
RunSignatureHelp);
})) {
@@ -499,9 +499,6 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
if (!T.consumeClose())
RLoc = T.getCloseLocation();
- assert(!Exprs.empty() && Exprs.size() - 1 == CommaLocs.size() &&
- "Unexpected number of commas!");
-
ExprResult Initializer =
Actions.ActOnParenListExpr(T.getOpenLocation(), RLoc, Exprs);
Actions.AddInitializerToDecl(OmpPrivParm, Initializer.get(),
@@ -1419,7 +1416,7 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo();
SmallVector<Expr *, 6> AdjustNothing;
SmallVector<Expr *, 6> AdjustNeedDevicePtr;
- SmallVector<OMPDeclareVariantAttr::InteropType, 3> AppendArgs;
+ SmallVector<OMPInteropInfo, 3> AppendArgs;
SourceLocation AdjustArgsLoc, AppendArgsLoc;
// At least one clause is required.
@@ -1487,7 +1484,7 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
ConsumeToken();
}
- Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
+ std::optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
Actions.checkOpenMPDeclareVariantFunction(
Ptr, AssociatedFunction.get(), TI, AppendArgs.size(),
SourceRange(Loc, Tok.getLocation()));
@@ -1502,56 +1499,8 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
(void)ConsumeAnnotationToken();
}
-/// Parse a list of interop-types. These are 'target' and 'targetsync'. Both
-/// are allowed but duplication of either is not meaningful.
-static Optional<OMPDeclareVariantAttr::InteropType>
-parseInteropTypeList(Parser &P) {
- const Token &Tok = P.getCurToken();
- bool HasError = false;
- bool IsTarget = false;
- bool IsTargetSync = false;
-
- while (Tok.is(tok::identifier)) {
- if (Tok.getIdentifierInfo()->isStr("target")) {
- // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
- // Each interop-type may be specified on an action-clause at most
- // once.
- if (IsTarget)
- P.Diag(Tok, diag::warn_omp_more_one_interop_type) << "target";
- IsTarget = true;
- } else if (Tok.getIdentifierInfo()->isStr("targetsync")) {
- if (IsTargetSync)
- P.Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync";
- IsTargetSync = true;
- } else {
- HasError = true;
- P.Diag(Tok, diag::err_omp_expected_interop_type);
- }
- P.ConsumeToken();
-
- if (!Tok.is(tok::comma))
- break;
- P.ConsumeToken();
- }
- if (HasError)
- return None;
-
- if (!IsTarget && !IsTargetSync) {
- P.Diag(Tok, diag::err_omp_expected_interop_type);
- return None;
- }
-
- // As of OpenMP 5.1,there are two interop-types, "target" and
- // "targetsync". Either or both are allowed for a single interop.
- if (IsTarget && IsTargetSync)
- return OMPDeclareVariantAttr::Target_TargetSync;
- if (IsTarget)
- return OMPDeclareVariantAttr::Target;
- return OMPDeclareVariantAttr::TargetSync;
-}
-
bool Parser::parseOpenMPAppendArgs(
- SmallVectorImpl<OMPDeclareVariantAttr::InteropType> &InterOpTypes) {
+ SmallVectorImpl<OMPInteropInfo> &InteropInfos) {
bool HasError = false;
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
@@ -1568,18 +1517,17 @@ bool Parser::parseOpenMPAppendArgs(
if (IT.expectAndConsume(diag::err_expected_lparen_after, "interop"))
return true;
- // Parse the interop-types.
- if (Optional<OMPDeclareVariantAttr::InteropType> IType =
- parseInteropTypeList(*this))
- InterOpTypes.push_back(*IType);
- else
+ OMPInteropInfo InteropInfo;
+ if (ParseOMPInteropInfo(InteropInfo, OMPC_append_args))
HasError = true;
+ else
+ InteropInfos.push_back(InteropInfo);
IT.consumeClose();
if (Tok.is(tok::comma))
ConsumeToken();
}
- if (!HasError && InterOpTypes.empty()) {
+ if (!HasError && InteropInfos.empty()) {
HasError = true;
Diag(Tok.getLocation(), diag::err_omp_unexpected_append_op);
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
@@ -1676,6 +1624,42 @@ bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc,
return false;
}
+/// <clause> [clause[ [,] clause] ... ]
+///
+/// clauses: for error directive
+/// 'at' '(' compilation | execution ')'
+/// 'severity' '(' fatal | warning ')'
+/// 'message' '(' msg-string ')'
+/// ....
+void Parser::ParseOpenMPClauses(OpenMPDirectiveKind DKind,
+ SmallVectorImpl<OMPClause *> &Clauses,
+ SourceLocation Loc) {
+ SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>,
+ llvm::omp::Clause_enumSize + 1>
+ FirstClauses(llvm::omp::Clause_enumSize + 1);
+ while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ OpenMPClauseKind CKind = Tok.isAnnotation()
+ ? OMPC_unknown
+ : getOpenMPClauseKind(PP.getSpelling(Tok));
+ Actions.StartOpenMPClause(CKind);
+ OMPClause *Clause = ParseOpenMPClause(
+ DKind, CKind, !FirstClauses[unsigned(CKind)].getInt());
+ SkipUntil(tok::comma, tok::identifier, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ FirstClauses[unsigned(CKind)].setInt(true);
+ if (Clause != nullptr)
+ Clauses.push_back(Clause);
+ if (Tok.is(tok::annot_pragma_openmp_end)) {
+ Actions.EndOpenMPClause();
+ break;
+ }
+ // Skip ',' if any.
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ Actions.EndOpenMPClause();
+ }
+}
+
/// `omp assumes` or `omp begin/end assumes` <clause> [[,]<clause>]...
/// where
///
@@ -1798,7 +1782,7 @@ struct SimpleClauseData {
};
} // anonymous namespace
-static Optional<SimpleClauseData>
+static std::optional<SimpleClauseData>
parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) {
const Token &Tok = P.getCurToken();
SourceLocation Loc = Tok.getLocation();
@@ -1807,7 +1791,7 @@ parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) {
BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
getOpenMPClauseName(Kind).data()))
- return llvm::None;
+ return std::nullopt;
unsigned Type = getOpenMPSimpleClauseType(
Kind, Tok.isAnnotation() ? "" : P.getPreprocessor().getSpelling(Tok),
@@ -1850,9 +1834,21 @@ void Parser::ParseOMPDeclareTargetClauses(
<< getOpenMPClauseName(OMPC_indirect) << 0;
break;
}
- bool IsToOrLinkClause =
+ bool IsToEnterOrLinkClause =
OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT);
- assert((!IsDeviceTypeClause || !IsToOrLinkClause) && "Cannot be both!");
+ assert((!IsDeviceTypeClause || !IsToEnterOrLinkClause) &&
+ "Cannot be both!");
+
+ // Starting with OpenMP 5.2 the `to` clause has been replaced by the
+ // `enter` clause.
+ if (getLangOpts().OpenMP >= 52 && ClauseName == "to") {
+ Diag(Tok, diag::err_omp_declare_target_unexpected_to_clause);
+ break;
+ }
+ if (getLangOpts().OpenMP <= 51 && ClauseName == "enter") {
+ Diag(Tok, diag::err_omp_declare_target_unexpected_enter_clause);
+ break;
+ }
if (!IsDeviceTypeClause && !IsIndirectClause &&
DTCI.Kind == OMPD_begin_declare_target) {
@@ -1860,16 +1856,18 @@ void Parser::ParseOMPDeclareTargetClauses(
<< ClauseName << (getLangOpts().OpenMP >= 51 ? 3 : 0);
break;
}
- if (!IsDeviceTypeClause && !IsToOrLinkClause && !IsIndirectClause) {
- Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
+ if (!IsDeviceTypeClause && !IsToEnterOrLinkClause && !IsIndirectClause) {
+ Diag(Tok, getLangOpts().OpenMP >= 52
+ ? diag::err_omp_declare_target_unexpected_clause_52
+ : diag::err_omp_declare_target_unexpected_clause)
<< ClauseName
- << (getLangOpts().OpenMP >= 51 ? 4
- : getLangOpts().OpenMP >= 50 ? 2
- : 1);
+ << (getLangOpts().OpenMP >= 51
+ ? 4
+ : getLangOpts().OpenMP >= 50 ? 2 : 1);
break;
}
- if (IsToOrLinkClause || IsIndirectClause)
+ if (IsToEnterOrLinkClause || IsIndirectClause)
HasToOrLinkOrIndirectClause = true;
if (IsIndirectClause) {
@@ -1879,16 +1877,16 @@ void Parser::ParseOMPDeclareTargetClauses(
}
// Parse 'device_type' clause and go to next clause if any.
if (IsDeviceTypeClause) {
- Optional<SimpleClauseData> DevTypeData =
+ std::optional<SimpleClauseData> DevTypeData =
parseOpenMPSimpleClause(*this, OMPC_device_type);
if (DevTypeData) {
if (DeviceTypeLoc.isValid()) {
// We already saw another device_type clause, diagnose it.
- Diag(DevTypeData.value().Loc,
+ Diag(DevTypeData->Loc,
diag::warn_omp_more_one_device_type_clause);
break;
}
- switch (static_cast<OpenMPDeviceType>(DevTypeData.value().Type)) {
+ switch (static_cast<OpenMPDeviceType>(DevTypeData->Type)) {
case OMPC_DEVICE_TYPE_any:
DTCI.DT = OMPDeclareTargetDeclAttr::DT_Any;
break;
@@ -1933,7 +1931,9 @@ void Parser::ParseOMPDeclareTargetClauses(
}
if (!HasIdentifier && Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok,
- diag::err_omp_declare_target_unexpected_clause_after_implicit_to);
+ getLangOpts().OpenMP >= 52
+ ? diag::err_omp_declare_target_wrong_clause_after_implicit_enter
+ : diag::err_omp_declare_target_wrong_clause_after_implicit_to);
break;
}
@@ -1948,7 +1948,10 @@ void Parser::ParseOMPDeclareTargetClauses(
// For declare target require at least 'to' or 'link' to be present.
if (DTCI.Kind == OMPD_declare_target && RequiresToOrLinkOrIndirectClause &&
!HasToOrLinkOrIndirectClause)
- Diag(DTCI.Loc, diag::err_omp_declare_target_missing_to_or_link_clause)
+ Diag(DTCI.Loc,
+ getLangOpts().OpenMP >= 52
+ ? diag::err_omp_declare_target_missing_enter_or_link_clause
+ : diag::err_omp_declare_target_missing_to_or_link_clause)
<< (getLangOpts().OpenMP >= 51 ? 1 : 0);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
@@ -2173,6 +2176,14 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ConsumeAnnotationToken();
return Actions.ActOnOpenMPRequiresDirective(StartLoc, Clauses);
}
+ case OMPD_error: {
+ SmallVector<OMPClause *, 1> Clauses;
+ SourceLocation StartLoc = ConsumeToken();
+ ParseOpenMPClauses(DKind, Clauses, StartLoc);
+ Actions.ActOnOpenMPErrorDirective(Clauses, StartLoc, SourceLocation(),
+ /*InExContext = */ false);
+ break;
+ }
case OMPD_assumes:
case OMPD_begin_assumes:
ParseOpenMPAssumesDirective(DKind, ConsumeToken());
@@ -2294,9 +2305,10 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
// Here we expect to see some function declaration.
if (AS == AS_none) {
assert(TagType == DeclSpec::TST_unspecified);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
ParsingDeclSpec PDS(*this);
- Ptr = ParseExternalDeclaration(Attrs, &PDS);
+ Ptr = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs, &PDS);
} else {
Ptr =
ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType, Tag);
@@ -2459,8 +2471,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
/// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
/// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
/// 'parallel for' | 'parallel sections' | 'parallel master' | 'task' |
-/// 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' |
-/// 'atomic' | 'for simd' | 'parallel for simd' | 'target' | 'target
+/// 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'error'
+/// | 'atomic' | 'for simd' | 'parallel for simd' | 'target' | 'target
/// data' | 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' |
/// 'master taskloop' | 'master taskloop simd' | 'parallel master
/// taskloop' | 'parallel master taskloop simd' | 'distribute' | 'target
@@ -2746,6 +2758,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
case OMPD_depobj:
case OMPD_scan:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -2758,10 +2771,14 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
ParsedStmtContext()) {
Diag(Tok, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind) << 0;
+ if (DKind == OMPD_error) {
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
+ }
}
HasAssociatedStatement = false;
// Fall through for further analysis.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPD_parallel:
case OMPD_simd:
case OMPD_tile:
@@ -2945,7 +2962,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
DKind == OMPD_target_exit_data) {
Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
AssociatedStmt = (Sema::CompoundScopeRAII(Actions),
- Actions.ActOnCompoundStmt(Loc, Loc, llvm::None,
+ Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt,
/*isStmtExpr=*/false));
AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
}
@@ -3177,6 +3194,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_filter:
case OMPC_partial:
case OMPC_align:
+ case OMPC_message:
+ case OMPC_ompx_dyn_cgroup_mem:
// OpenMP [2.5, Restrictions]
// At most one num_threads clause can appear on the directive.
// OpenMP [2.8.1, simd construct, Restrictions]
@@ -3202,6 +3221,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
// OpenMP 5.1, 2.3.6 dispatch Construct, Restrictions.
// At most one novariants clause can appear on a dispatch directive.
// At most one nocontext clause can appear on a dispatch directive.
+ // OpenMP [5.1, error directive, Restrictions]
+ // At most one message clause can appear on the directive
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
@@ -3211,13 +3232,16 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
if ((CKind == OMPC_ordered || CKind == OMPC_partial) &&
PP.LookAhead(/*N=*/0).isNot(tok::l_paren))
Clause = ParseOpenMPClause(CKind, WrongDirective);
+ else if (CKind == OMPC_grainsize || CKind == OMPC_num_tasks)
+ Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);
else
Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);
break;
case OMPC_default:
case OMPC_proc_bind:
case OMPC_atomic_default_mem_order:
- case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
case OMPC_bind:
// OpenMP [2.14.3.1, Restrictions]
// Only a single default clause may be specified on a parallel, task or
@@ -3227,9 +3251,12 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
// OpenMP [5.0, Requires directive, Restrictions]
// At most one atomic_default_mem_order clause can appear
// on the directive
+ // OpenMP [5.1, error directive, Restrictions]
+ // At most one at clause can appear on the directive
+ // At most one severity clause can appear on the directive
// OpenMP 5.1, 2.11.7 loop Construct, Restrictions.
// At most one bind clause can appear on a loop directive.
- if (!FirstClause && CKind != OMPC_order) {
+ if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
ErrorFound = true;
@@ -3241,19 +3268,22 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_schedule:
case OMPC_dist_schedule:
case OMPC_defaultmap:
+ case OMPC_order:
// OpenMP [2.7.1, Restrictions, p. 3]
// Only one schedule clause can appear on a loop directive.
// OpenMP 4.5 [2.10.4, Restrictions, p. 106]
// At most one defaultmap clause can appear on the directive.
// OpenMP 5.0 [2.12.5, target construct, Restrictions]
// At most one device clause can appear on the directive.
+ // OpenMP 5.1 [2.11.3, order clause, Restrictions]
+ // At most one order clause may appear on a construct.
if ((getLangOpts().OpenMP < 50 || CKind != OMPC_defaultmap) &&
- !FirstClause) {
+ (CKind != OMPC_order || getLangOpts().OpenMP >= 51) && !FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
ErrorFound = true;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPC_if:
Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);
break;
@@ -3351,7 +3381,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
Clause = ParseOpenMPClause(CKind, WrongDirective);
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPC_init:
case OMPC_use:
Clause = ParseOpenMPInteropClause(CKind, WrongDirective);
@@ -3496,6 +3526,90 @@ bool Parser::ParseOpenMPIndirectClause(Sema::DeclareTargetContextInfo &DTCI,
return false;
}
+/// Parses a comma-separated list of interop-types and a prefer_type list.
+///
+bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo,
+ OpenMPClauseKind Kind) {
+ const Token &Tok = getCurToken();
+ bool HasError = false;
+ bool IsTarget = false;
+ bool IsTargetSync = false;
+
+ while (Tok.is(tok::identifier)) {
+ // Currently prefer_type is only allowed with 'init' and it must be first.
+ bool PreferTypeAllowed = Kind == OMPC_init &&
+ InteropInfo.PreferTypes.empty() && !IsTarget &&
+ !IsTargetSync;
+ if (Tok.getIdentifierInfo()->isStr("target")) {
+ // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
+ // Each interop-type may be specified on an action-clause at most
+ // once.
+ if (IsTarget)
+ Diag(Tok, diag::warn_omp_more_one_interop_type) << "target";
+ IsTarget = true;
+ ConsumeToken();
+ } else if (Tok.getIdentifierInfo()->isStr("targetsync")) {
+ if (IsTargetSync)
+ Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync";
+ IsTargetSync = true;
+ ConsumeToken();
+ } else if (Tok.getIdentifierInfo()->isStr("prefer_type") &&
+ PreferTypeAllowed) {
+ ConsumeToken();
+ BalancedDelimiterTracker PT(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type"))
+ HasError = true;
+
+ while (Tok.isNot(tok::r_paren)) {
+ SourceLocation Loc = Tok.getLocation();
+ ExprResult LHS = ParseCastExpression(AnyCastExpr);
+ ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr(
+ ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+ PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,
+ /*DiscardedValue=*/false);
+ if (PTExpr.isUsable()) {
+ InteropInfo.PreferTypes.push_back(PTExpr.get());
+ } else {
+ HasError = true;
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ }
+
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ }
+ PT.consumeClose();
+ } else {
+ HasError = true;
+ Diag(Tok, diag::err_omp_expected_interop_type);
+ ConsumeToken();
+ }
+ if (!Tok.is(tok::comma))
+ break;
+ ConsumeToken();
+ }
+
+ if (!HasError && !IsTarget && !IsTargetSync) {
+ Diag(Tok, diag::err_omp_expected_interop_type);
+ HasError = true;
+ }
+
+ if (Kind == OMPC_init) {
+ if (Tok.isNot(tok::colon) && (IsTarget || IsTargetSync))
+ Diag(Tok, diag::warn_pragma_expected_colon) << "interop types";
+ if (Tok.is(tok::colon))
+ ConsumeToken();
+ }
+
+ // As of OpenMP 5.1,there are two interop-types, "target" and
+ // "targetsync". Either or both are allowed for a single interop.
+ InteropInfo.IsTarget = IsTarget;
+ InteropInfo.IsTargetSync = IsTargetSync;
+
+ return HasError;
+}
+
/// Parsing of OpenMP clauses that use an interop-var.
///
/// init-clause:
@@ -3528,57 +3642,10 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,
getOpenMPClauseName(Kind).data()))
return nullptr;
- bool IsTarget = false;
- bool IsTargetSync = false;
- SmallVector<Expr *, 4> Prefs;
-
- if (Kind == OMPC_init) {
-
- // Parse optional interop-modifier.
- if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "prefer_type") {
- ConsumeToken();
- BalancedDelimiterTracker PT(*this, tok::l_paren,
- tok::annot_pragma_openmp_end);
- if (PT.expectAndConsume(diag::err_expected_lparen_after, "prefer_type"))
- return nullptr;
-
- while (Tok.isNot(tok::r_paren)) {
- SourceLocation Loc = Tok.getLocation();
- ExprResult LHS = ParseCastExpression(AnyCastExpr);
- ExprResult PTExpr = Actions.CorrectDelayedTyposInExpr(
- ParseRHSOfBinaryExpression(LHS, prec::Conditional));
- PTExpr = Actions.ActOnFinishFullExpr(PTExpr.get(), Loc,
- /*DiscardedValue=*/false);
- if (PTExpr.isUsable())
- Prefs.push_back(PTExpr.get());
- else
- SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
- StopBeforeMatch);
-
- if (Tok.is(tok::comma))
- ConsumeToken();
- }
- PT.consumeClose();
- }
-
- if (!Prefs.empty()) {
- if (Tok.is(tok::comma))
- ConsumeToken();
- else
- Diag(Tok, diag::err_omp_expected_punc_after_interop_mod);
- }
-
- // Parse the interop-types.
- if (Optional<OMPDeclareVariantAttr::InteropType> IType =
- parseInteropTypeList(*this)) {
- IsTarget = IType != OMPDeclareVariantAttr::TargetSync;
- IsTargetSync = IType != OMPDeclareVariantAttr::Target;
- if (Tok.isNot(tok::colon))
- Diag(Tok, diag::warn_pragma_expected_colon) << "interop types";
- }
- if (Tok.is(tok::colon))
- ConsumeToken();
- }
+ bool InteropError = false;
+ OMPInteropInfo InteropInfo;
+ if (Kind == OMPC_init)
+ InteropError = ParseOMPInteropInfo(InteropInfo, OMPC_init);
// Parse the variable.
SourceLocation VarLoc = Tok.getLocation();
@@ -3594,14 +3661,12 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,
if (!T.consumeClose())
RLoc = T.getCloseLocation();
- if (ParseOnly || !InteropVarExpr.isUsable() ||
- (Kind == OMPC_init && !IsTarget && !IsTargetSync))
+ if (ParseOnly || !InteropVarExpr.isUsable() || InteropError)
return nullptr;
if (Kind == OMPC_init)
- return Actions.ActOnOpenMPInitClause(InteropVarExpr.get(), Prefs, IsTarget,
- IsTargetSync, Loc, T.getOpenLocation(),
- VarLoc, RLoc);
+ return Actions.ActOnOpenMPInitClause(InteropVarExpr.get(), InteropInfo, Loc,
+ T.getOpenLocation(), VarLoc, RLoc);
if (Kind == OMPC_use)
return Actions.ActOnOpenMPUseClause(InteropVarExpr.get(), Loc,
T.getOpenLocation(), VarLoc, RLoc);
@@ -3630,24 +3695,24 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,
///
OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind,
bool ParseOnly) {
- llvm::Optional<SimpleClauseData> Val = parseOpenMPSimpleClause(*this, Kind);
+ std::optional<SimpleClauseData> Val = parseOpenMPSimpleClause(*this, Kind);
if (!Val || ParseOnly)
return nullptr;
if (getLangOpts().OpenMP < 51 && Kind == OMPC_default &&
- (static_cast<DefaultKind>(Val.value().Type) == OMP_DEFAULT_private ||
- static_cast<DefaultKind>(Val.value().Type) ==
+ (static_cast<DefaultKind>(Val->Type) == OMP_DEFAULT_private ||
+ static_cast<DefaultKind>(Val->Type) ==
OMP_DEFAULT_firstprivate)) {
- Diag(Val.value().LOpen, diag::err_omp_invalid_dsa)
- << getOpenMPClauseName(static_cast<DefaultKind>(Val.value().Type) ==
+ Diag(Val->LOpen, diag::err_omp_invalid_dsa)
+ << getOpenMPClauseName(static_cast<DefaultKind>(Val->Type) ==
OMP_DEFAULT_private
? OMPC_private
: OMPC_firstprivate)
<< getOpenMPClauseName(OMPC_default) << "5.1";
return nullptr;
}
- return Actions.ActOnOpenMPSimpleClause(Kind, Val.value().Type,
- Val.value().TypeLoc, Val.value().LOpen,
- Val.value().Loc, Val.value().RLoc);
+ return Actions.ActOnOpenMPSimpleClause(Kind, Val->Type,
+ Val->TypeLoc, Val->LOpen,
+ Val->Loc, Val->RLoc);
}
/// Parsing of OpenMP clauses like 'ordered'.
@@ -3801,6 +3866,34 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,
Arg.push_back(OMPC_DEFAULTMAP_unknown);
KLoc.push_back(SourceLocation());
}
+ } else if (Kind == OMPC_order) {
+ enum { Modifier, OrderKind, NumberOfElements };
+ Arg.resize(NumberOfElements);
+ KLoc.resize(NumberOfElements);
+ Arg[Modifier] = OMPC_ORDER_MODIFIER_unknown;
+ Arg[OrderKind] = OMPC_ORDER_unknown;
+ unsigned KindModifier = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());
+ if (KindModifier > OMPC_ORDER_unknown) {
+ // Parse 'modifier'
+ Arg[Modifier] = KindModifier;
+ KLoc[Modifier] = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+ // Parse ':'
+ if (Tok.is(tok::colon))
+ ConsumeAnyToken();
+ else
+ Diag(Tok, diag::warn_pragma_expected_colon) << "order modifier";
+ KindModifier = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts());
+ }
+ Arg[OrderKind] = KindModifier;
+ KLoc[OrderKind] = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
} else if (Kind == OMPC_device) {
// Only target executable directives support extended device construct.
if (isOpenMPTargetExecutionDirective(DKind) && getLangOpts().OpenMP >= 50 &&
@@ -3816,6 +3909,60 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,
Arg.push_back(OMPC_DEVICE_unknown);
KLoc.emplace_back();
}
+ } else if (Kind == OMPC_grainsize) {
+ // Parse optional <grainsize modifier> ':'
+ OpenMPGrainsizeClauseModifier Modifier =
+ static_cast<OpenMPGrainsizeClauseModifier>(getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),
+ getLangOpts()));
+ if (getLangOpts().OpenMP >= 51) {
+ if (NextToken().is(tok::colon)) {
+ Arg.push_back(Modifier);
+ KLoc.push_back(Tok.getLocation());
+ // Parse modifier
+ ConsumeAnyToken();
+ // Parse ':'
+ ConsumeAnyToken();
+ } else {
+ if (Modifier == OMPC_GRAINSIZE_strict) {
+ Diag(Tok, diag::err_modifier_expected_colon) << "strict";
+ // Parse modifier
+ ConsumeAnyToken();
+ }
+ Arg.push_back(OMPC_GRAINSIZE_unknown);
+ KLoc.emplace_back();
+ }
+ } else {
+ Arg.push_back(OMPC_GRAINSIZE_unknown);
+ KLoc.emplace_back();
+ }
+ } else if (Kind == OMPC_num_tasks) {
+ // Parse optional <num_tasks modifier> ':'
+ OpenMPNumTasksClauseModifier Modifier =
+ static_cast<OpenMPNumTasksClauseModifier>(getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok),
+ getLangOpts()));
+ if (getLangOpts().OpenMP >= 51) {
+ if (NextToken().is(tok::colon)) {
+ Arg.push_back(Modifier);
+ KLoc.push_back(Tok.getLocation());
+ // Parse modifier
+ ConsumeAnyToken();
+ // Parse ':'
+ ConsumeAnyToken();
+ } else {
+ if (Modifier == OMPC_NUMTASKS_strict) {
+ Diag(Tok, diag::err_modifier_expected_colon) << "strict";
+ // Parse modifier
+ ConsumeAnyToken();
+ }
+ Arg.push_back(OMPC_NUMTASKS_unknown);
+ KLoc.emplace_back();
+ }
+ } else {
+ Arg.push_back(OMPC_NUMTASKS_unknown);
+ KLoc.emplace_back();
+ }
} else {
assert(Kind == OMPC_if);
KLoc.push_back(Tok.getLocation());
@@ -3838,7 +3985,8 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind,
bool NeedAnExpression = (Kind == OMPC_schedule && DelimLoc.isValid()) ||
(Kind == OMPC_dist_schedule && DelimLoc.isValid()) ||
- Kind == OMPC_if || Kind == OMPC_device;
+ Kind == OMPC_if || Kind == OMPC_device ||
+ Kind == OMPC_grainsize || Kind == OMPC_num_tasks;
if (NeedAnExpression) {
SourceLocation ELoc = Tok.getLocation();
ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast));
@@ -3984,7 +4132,8 @@ bool Parser::parseMapTypeModifiers(Sema::OpenMPVarListDataTy &Data) {
if (PP.LookAhead(0).is(tok::colon))
return false;
Diag(Tok, diag::err_omp_unknown_map_type_modifier)
- << (getLangOpts().OpenMP >= 51 ? 1 : 0)
+ << (getLangOpts().OpenMP >= 51 ? (getLangOpts().OpenMP >= 52 ? 2 : 1)
+ : 0)
<< getLangOpts().OpenMPExtensions;
ConsumeToken();
}
@@ -4173,6 +4322,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
return true;
bool HasIterator = false;
+ bool InvalidIterator = false;
bool NeedRParenForLinear = false;
BalancedDelimiterTracker LinearT(*this, tok::l_paren,
tok::annot_pragma_openmp_end);
@@ -4278,6 +4428,23 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Data.ColonLoc = ConsumeToken();
}
} else if (Kind == OMPC_map) {
+ // Handle optional iterator map modifier.
+ if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {
+ HasIterator = true;
+ EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
+ Data.MapTypeModifiers.push_back(OMPC_MAP_MODIFIER_iterator);
+ Data.MapTypeModifiersLoc.push_back(Tok.getLocation());
+ ExprResult IteratorRes = ParseOpenMPIteratorsExpr();
+ Data.IteratorExpr = IteratorRes.get();
+ // Parse ','
+ ExpectAndConsume(tok::comma);
+ if (getLangOpts().OpenMP < 52) {
+ Diag(Tok, diag::err_omp_unknown_map_type_modifier)
+ << (getLangOpts().OpenMP >= 51 ? 1 : 0)
+ << getLangOpts().OpenMPExtensions;
+ InvalidIterator = true;
+ }
+ }
// Handle map type for map clause.
ColonProtectionRAIIObject ColonRAII(*this);
@@ -4307,6 +4474,12 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
}
if (Data.ExtraModifier == OMPC_MAP_unknown) {
Data.ExtraModifier = OMPC_MAP_tofrom;
+ if (getLangOpts().OpenMP >= 52) {
+ if (DKind == OMPD_target_enter_data)
+ Data.ExtraModifier = OMPC_MAP_to;
+ else if (DKind == OMPD_target_exit_data)
+ Data.ExtraModifier = OMPC_MAP_from;
+ }
Data.IsMapTypeImplicit = true;
}
@@ -4469,7 +4642,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
ExitScope();
return (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) ||
(MustHaveTail && !Data.DepModOrTailExpr) || InvalidReductionId ||
- IsInvalidMapperModifier;
+ IsInvalidMapperModifier || InvalidIterator;
}
/// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 74fa70379858..658853d42b74 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -22,6 +22,7 @@
#include "clang/Sema/Scope.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSwitch.h"
+#include <optional>
using namespace clang;
namespace {
@@ -449,6 +450,9 @@ void Parser::initializePragmaHandlers() {
PP.AddPragmaHandler(MSCodeSeg.get());
MSSection = std::make_unique<PragmaMSPragma>("section");
PP.AddPragmaHandler(MSSection.get());
+ MSStrictGuardStackCheck =
+ std::make_unique<PragmaMSPragma>("strict_gs_check");
+ PP.AddPragmaHandler(MSStrictGuardStackCheck.get());
MSFunction = std::make_unique<PragmaMSPragma>("function");
PP.AddPragmaHandler(MSFunction.get());
MSAllocText = std::make_unique<PragmaMSPragma>("alloc_text");
@@ -567,6 +571,8 @@ void Parser::resetPragmaHandlers() {
MSCodeSeg.reset();
PP.RemovePragmaHandler(MSSection.get());
MSSection.reset();
+ PP.RemovePragmaHandler(MSStrictGuardStackCheck.get());
+ MSStrictGuardStackCheck.reset();
PP.RemovePragmaHandler(MSFunction.get());
MSFunction.reset();
PP.RemovePragmaHandler(MSAllocText.get());
@@ -936,6 +942,7 @@ void Parser::HandlePragmaMSPragma() {
.Case("code_seg", &Parser::HandlePragmaMSSegment)
.Case("section", &Parser::HandlePragmaMSSection)
.Case("init_seg", &Parser::HandlePragmaMSInitSeg)
+ .Case("strict_gs_check", &Parser::HandlePragmaMSStrictGuardStackCheck)
.Case("function", &Parser::HandlePragmaMSFunction)
.Case("alloc_text", &Parser::HandlePragmaMSAllocText)
.Case("optimize", &Parser::HandlePragmaMSOptimize);
@@ -1175,6 +1182,59 @@ bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
return true;
}
+// #pragma strict_gs_check(pop)
+// #pragma strict_gs_check(push, "on" | "off")
+// #pragma strict_gs_check("on" | "off")
+bool Parser::HandlePragmaMSStrictGuardStackCheck(
+ StringRef PragmaName, SourceLocation PragmaLocation) {
+ if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen,
+ PragmaName))
+ return false;
+
+ Sema::PragmaMsStackAction Action = Sema::PSK_Set;
+ if (Tok.is(tok::identifier)) {
+ StringRef PushPop = Tok.getIdentifierInfo()->getName();
+ if (PushPop == "push") {
+ PP.Lex(Tok);
+ Action = Sema::PSK_Push;
+ if (ExpectAndConsume(tok::comma, diag::warn_pragma_expected_punc,
+ PragmaName))
+ return false;
+ } else if (PushPop == "pop") {
+ PP.Lex(Tok);
+ Action = Sema::PSK_Pop;
+ }
+ }
+
+ bool Value = false;
+ if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) {
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (II && II->isStr("off")) {
+ PP.Lex(Tok);
+ Value = false;
+ } else if (II && II->isStr("on")) {
+ PP.Lex(Tok);
+ Value = true;
+ } else {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action)
+ << PragmaName;
+ return false;
+ }
+ }
+
+ // Finish the pragma: ')' $
+ if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen,
+ PragmaName))
+ return false;
+
+ if (ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol,
+ PragmaName))
+ return false;
+
+ Actions.ActOnPragmaMSStrictGuardStackCheck(PragmaLocation, Action, Value);
+ return true;
+}
+
bool Parser::HandlePragmaMSAllocText(StringRef PragmaName,
SourceLocation PragmaLocation) {
Token FirstTok = Tok;
@@ -1234,17 +1294,11 @@ bool Parser::HandlePragmaMSAllocText(StringRef PragmaName,
return true;
}
-namespace {
-struct PragmaLoopHintInfo {
- Token PragmaName;
- Token Option;
- ArrayRef<Token> Toks;
-};
-} // end anonymous namespace
-
static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
StringRef Str = PragmaName.getIdentifierInfo()->getName();
- std::string ClangLoopStr = (llvm::Twine("clang loop ") + Str).str();
+ std::string ClangLoopStr("clang loop ");
+ if (Str == "loop" && Option.getIdentifierInfo())
+ ClangLoopStr += Option.getIdentifierInfo()->getName();
return std::string(llvm::StringSwitch<StringRef>(Str)
.Case("loop", ClangLoopStr)
.Case("unroll_and_jam", Str)
@@ -1528,8 +1582,8 @@ bool Parser::ParsePragmaAttributeSubjectMatchRuleSet(
Diag(Tok, diag::err_pragma_attribute_expected_subject_identifier);
return true;
}
- std::pair<Optional<attr::SubjectMatchRule>,
- Optional<attr::SubjectMatchRule> (*)(StringRef, bool)>
+ std::pair<std::optional<attr::SubjectMatchRule>,
+ std::optional<attr::SubjectMatchRule> (*)(StringRef, bool)>
Rule = isAttributeSubjectMatchRule(Name);
if (!Rule.first) {
Diag(Tok, diag::err_pragma_attribute_unknown_subject_rule) << Name;
@@ -3119,10 +3173,10 @@ struct TokFPAnnotValue {
enum FlagKinds { Contract, Reassociate, Exceptions, EvalMethod };
enum FlagValues { On, Off, Fast };
- llvm::Optional<LangOptions::FPModeKind> ContractValue;
- llvm::Optional<LangOptions::FPModeKind> ReassociateValue;
- llvm::Optional<LangOptions::FPExceptionModeKind> ExceptionsValue;
- llvm::Optional<LangOptions::FPEvalMethodKind> EvalMethodValue;
+ std::optional<LangOptions::FPModeKind> ContractValue;
+ std::optional<LangOptions::FPModeKind> ReassociateValue;
+ std::optional<LangOptions::FPExceptionModeKind> ExceptionsValue;
+ std::optional<LangOptions::FPEvalMethodKind> EvalMethodValue;
};
} // end anonymous namespace
@@ -3144,13 +3198,13 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
auto FlagKind =
- llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagKinds>>(
+ llvm::StringSwitch<std::optional<TokFPAnnotValue::FlagKinds>>(
OptionInfo->getName())
.Case("contract", TokFPAnnotValue::Contract)
.Case("reassociate", TokFPAnnotValue::Reassociate)
.Case("exceptions", TokFPAnnotValue::Exceptions)
.Case("eval_method", TokFPAnnotValue::EvalMethod)
- .Default(None);
+ .Default(std::nullopt);
if (!FlagKind) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option)
<< /*MissingOption=*/false << OptionInfo;
@@ -3178,12 +3232,12 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
if (FlagKind == TokFPAnnotValue::Contract) {
AnnotValue->ContractValue =
- llvm::StringSwitch<llvm::Optional<LangOptions::FPModeKind>>(
+ llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
II->getName())
.Case("on", LangOptions::FPModeKind::FPM_On)
.Case("off", LangOptions::FPModeKind::FPM_Off)
.Case("fast", LangOptions::FPModeKind::FPM_Fast)
- .Default(llvm::None);
+ .Default(std::nullopt);
if (!AnnotValue->ContractValue) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
@@ -3191,11 +3245,11 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
}
} else if (FlagKind == TokFPAnnotValue::Reassociate) {
AnnotValue->ReassociateValue =
- llvm::StringSwitch<llvm::Optional<LangOptions::FPModeKind>>(
+ llvm::StringSwitch<std::optional<LangOptions::FPModeKind>>(
II->getName())
.Case("on", LangOptions::FPModeKind::FPM_On)
.Case("off", LangOptions::FPModeKind::FPM_Off)
- .Default(llvm::None);
+ .Default(std::nullopt);
if (!AnnotValue->ReassociateValue) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
@@ -3203,12 +3257,12 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
}
} else if (FlagKind == TokFPAnnotValue::Exceptions) {
AnnotValue->ExceptionsValue =
- llvm::StringSwitch<llvm::Optional<LangOptions::FPExceptionModeKind>>(
+ llvm::StringSwitch<std::optional<LangOptions::FPExceptionModeKind>>(
II->getName())
.Case("ignore", LangOptions::FPE_Ignore)
.Case("maytrap", LangOptions::FPE_MayTrap)
.Case("strict", LangOptions::FPE_Strict)
- .Default(llvm::None);
+ .Default(std::nullopt);
if (!AnnotValue->ExceptionsValue) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
@@ -3216,12 +3270,12 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
}
} else if (FlagKind == TokFPAnnotValue::EvalMethod) {
AnnotValue->EvalMethodValue =
- llvm::StringSwitch<llvm::Optional<LangOptions::FPEvalMethodKind>>(
+ llvm::StringSwitch<std::optional<LangOptions::FPEvalMethodKind>>(
II->getName())
.Case("source", LangOptions::FPEvalMethodKind::FEM_Source)
.Case("double", LangOptions::FPEvalMethodKind::FEM_Double)
.Case("extended", LangOptions::FPEvalMethodKind::FEM_Extended)
- .Default(llvm::None);
+ .Default(std::nullopt);
if (!AnnotValue->EvalMethodValue) {
PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
<< PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
@@ -3371,7 +3425,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
ValueList.push_back(EOFTok); // Terminates expression for parsing.
markAsReinjectedForRelexing(ValueList);
- Info.Toks = llvm::makeArrayRef(ValueList).copy(PP.getPreprocessorAllocator());
+ Info.Toks = llvm::ArrayRef(ValueList).copy(PP.getPreprocessorAllocator());
Info.PragmaName = PragmaName;
Info.Option = Option;
@@ -3871,7 +3925,7 @@ void PragmaAttributeHandler::HandlePragma(Preprocessor &PP,
markAsReinjectedForRelexing(AttributeTokens);
Info->Tokens =
- llvm::makeArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator());
+ llvm::ArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator());
}
if (Tok.isNot(tok::eod))
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 1f6c74aeae7e..1c8441fafc48 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/Attributes.h"
#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/TokenKinds.h"
#include "clang/Parse/LoopHint.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
@@ -21,6 +22,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
@@ -36,8 +38,8 @@ StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc,
// We may get back a null statement if we found a #pragma. Keep going until
// we get an actual statement.
+ StmtVector Stmts;
do {
- StmtVector Stmts;
Res = ParseStatementOrDeclaration(Stmts, StmtCtx, TrailingElseLoc);
} while (!Res.isInvalid() && !Res.get());
@@ -188,7 +190,8 @@ Retry:
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
return StmtError();
- case tok::identifier: {
+ case tok::identifier:
+ ParseIdentifier: {
Token Next = NextToken();
if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
// Both C++11 and GNU attributes preceding the label appertain to the
@@ -222,7 +225,7 @@ Retry:
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
default: {
@@ -261,7 +264,19 @@ Retry:
return StmtError();
}
- return ParseExprStatement(StmtCtx);
+ switch (Tok.getKind()) {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+ if (NextToken().is(tok::less)) {
+ Tok.setKind(tok::identifier);
+ Diag(Tok, diag::ext_keyword_as_ident)
+ << Tok.getIdentifierInfo()->getName() << 0;
+ goto ParseIdentifier;
+ }
+ [[fallthrough]];
+ default:
+ return ParseExprStatement(StmtCtx);
+ }
}
case tok::kw___attribute: {
@@ -448,7 +463,7 @@ Retry:
// processing a #pragma omp clause.
ProhibitAttributes(CXX11Attrs);
ProhibitAttributes(GNUAttrs);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::annot_attr_openmp:
// Do not prohibit attributes if they were OpenMP attributes.
return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx);
@@ -665,9 +680,12 @@ StmtResult Parser::ParseSEHLeaveStatement() {
/// ParseLabeledStatement - We have an identifier and a ':' after it.
///
+/// label:
+/// identifier ':'
+/// [GNU] identifier ':' attributes[opt]
+///
/// labeled-statement:
-/// identifier ':' statement
-/// [GNU] identifier ':' attributes[opt] statement
+/// label statement
///
StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
ParsedStmtContext StmtCtx) {
@@ -711,6 +729,12 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
}
}
+ // The label may have no statement following it
+ if (SubStmt.isUnset() && Tok.is(tok::r_brace)) {
+ DiagnoseLabelAtEndOfCompoundStatement();
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
+ }
+
// If we've not parsed a statement yet, parse one now.
if (!SubStmt.isInvalid() && !SubStmt.isUsable())
SubStmt = ParseStatement(nullptr, StmtCtx);
@@ -741,7 +765,7 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
// otherwise in the same context as the labeled-statement.
StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
- // It is very very common for code to contain many case statements recursively
+ // It is very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
// case 1:
// case 2:
@@ -851,18 +875,13 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
// If we found a non-case statement, start by parsing it.
StmtResult SubStmt;
- if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
+ if (Tok.is(tok::r_brace)) {
+ // "switch (X) { case 4: }", is valid and is treated as if label was
+ // followed by a null statement.
+ DiagnoseLabelAtEndOfCompoundStatement();
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
} else {
- // Nicely diagnose the common error "switch (X) { case 4: }", which is
- // not valid. If ColonLoc doesn't point to a valid text location, there was
- // another parsing error, so avoid producing extra diagnostics.
- if (ColonLoc.isValid()) {
- SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
- << FixItHint::CreateInsertion(AfterColonLoc, " ;");
- }
- SubStmt = StmtError();
+ SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
}
// Install the body into the most deeply-nested case.
@@ -908,15 +927,13 @@ StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) {
StmtResult SubStmt;
- if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
+ if (Tok.is(tok::r_brace)) {
+ // "switch (X) {... default: }", is valid and is treated as if label was
+ // followed by a null statement.
+ DiagnoseLabelAtEndOfCompoundStatement();
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
} else {
- // Diagnose the common error "switch (X) {... default: }", which is
- // not valid.
- SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
- << FixItHint::CreateInsertion(AfterColonLoc, " ;");
- SubStmt = true;
+ SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
}
// Broken sub-stmt shouldn't prevent forming the case statement properly.
@@ -956,7 +973,7 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
///
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
unsigned ScopeFlags) {
- assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
+ assert(Tok.is(tok::l_brace) && "Not a compound stmt!");
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
@@ -1033,6 +1050,18 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
}
+void Parser::DiagnoseLabelAtEndOfCompoundStatement() {
+ if (getLangOpts().CPlusPlus) {
+ Diag(Tok, getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx20_compat_label_end_of_compound_statement
+ : diag::ext_cxx_label_end_of_compound_statement);
+ } else {
+ Diag(Tok, getLangOpts().C2x
+ ? diag::warn_c2x_compat_label_end_of_compound_statement
+ : diag::ext_c_label_end_of_compound_statement);
+ }
+}
+
/// Consume any extra semi-colons resulting in null statements,
/// returning true if any tok::semi were consumed.
bool Parser::ConsumeNullStmt(StmtVector &Stmts) {
@@ -1082,10 +1111,10 @@ StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) {
return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult);
}
-/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
-/// ActOnCompoundStmt action. This expects the '{' to be the current token, and
-/// consume the '}' at the end of the block. It does not manipulate the scope
-/// stack.
+/// ParseCompoundStatementBody - Parse a sequence of statements optionally
+/// followed by a label and invoke the ActOnCompoundStmt action. This expects
+/// the '{' to be the current token, and consume the '}' at the end of the
+/// block. It does not manipulate the scope stack.
StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
Tok.getLocation(),
@@ -1242,20 +1271,20 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
/// should try to recover harder. It returns false if the condition is
/// successfully parsed. Note that a successful parse can still have semantic
/// errors in the condition.
-/// Additionally, if LParenLoc and RParenLoc are non-null, it will assign
-/// the location of the outer-most '(' and ')', respectively, to them.
+/// Additionally, it will assign the location of the outer-most '(' and ')',
+/// to LParenLoc and RParenLoc, respectively.
bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
Sema::ConditionResult &Cond,
SourceLocation Loc,
- Sema::ConditionKind CK, bool MissingOK,
- SourceLocation *LParenLoc,
- SourceLocation *RParenLoc) {
+ Sema::ConditionKind CK,
+ SourceLocation &LParenLoc,
+ SourceLocation &RParenLoc) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
SourceLocation Start = Tok.getLocation();
if (getLangOpts().CPlusPlus) {
- Cond = ParseCXXCondition(InitStmt, Loc, CK, MissingOK);
+ Cond = ParseCXXCondition(InitStmt, Loc, CK, false);
} else {
ExprResult CondExpr = ParseExpression();
@@ -1264,7 +1293,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
Cond = Sema::ConditionError();
else
Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK,
- MissingOK);
+ /*MissingOK=*/false);
}
// If the parser was confused by the condition and we don't have a ')', try to
@@ -1284,18 +1313,13 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
Actions.PreferredConditionType(CK));
if (!CondExpr.isInvalid())
Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK,
- MissingOK);
+ /*MissingOK=*/false);
}
// Either the condition is valid or the rparen is present.
T.consumeClose();
-
- if (LParenLoc != nullptr) {
- *LParenLoc = T.getOpenLocation();
- }
- if (RParenLoc != nullptr) {
- *RParenLoc = T.getCloseLocation();
- }
+ LParenLoc = T.getOpenLocation();
+ RParenLoc = T.getCloseLocation();
// Check for extraneous ')'s to catch things like "if (foo())) {". We know
// that all callers are looking for a statement after the condition, so ")"
@@ -1465,13 +1489,13 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
Sema::ConditionResult Cond;
SourceLocation LParen;
SourceLocation RParen;
- llvm::Optional<bool> ConstexprCondition;
+ std::optional<bool> ConstexprCondition;
if (!IsConsteval) {
if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
IsConstexpr ? Sema::ConditionKind::ConstexprIf
: Sema::ConditionKind::Boolean,
- /*MissingOK=*/false, &LParen, &RParen))
+ LParen, RParen))
return StmtError();
if (IsConstexpr)
@@ -1666,8 +1690,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
SourceLocation LParen;
SourceLocation RParen;
if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc,
- Sema::ConditionKind::Switch,
- /*MissingOK=*/false, &LParen, &RParen))
+ Sema::ConditionKind::Switch, LParen, RParen))
return StmtError();
StmtResult Switch = Actions.ActOnStartOfSwitchStmt(
@@ -1757,8 +1780,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
SourceLocation LParen;
SourceLocation RParen;
if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc,
- Sema::ConditionKind::Boolean,
- /*MissingOK=*/false, &LParen, &RParen))
+ Sema::ConditionKind::Boolean, LParen, RParen))
return StmtError();
// C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
@@ -2430,7 +2452,8 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
// If the function body could not be parsed, make a bogus compoundstmt.
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
+ FnBody =
+ Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, std::nullopt, false);
}
BodyScope.Exit();
@@ -2467,7 +2490,8 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
// compound statement as the body.
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
+ FnBody =
+ Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, std::nullopt, false);
}
BodyScope.Exit();
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index e32ea6003b84..6fc67b6965dd 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -289,8 +289,14 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
LateParsedAttrList LateParsedAttrs(true);
if (DeclaratorInfo.isFunctionDeclarator()) {
- if (Tok.is(tok::kw_requires))
+ if (Tok.is(tok::kw_requires)) {
+ CXXScopeSpec &ScopeSpec = DeclaratorInfo.getCXXScopeSpec();
+ DeclaratorScopeObj DeclScopeObj(*this, ScopeSpec);
+ if (ScopeSpec.isValid() &&
+ Actions.ShouldEnterDeclaratorScope(getCurScope(), ScopeSpec))
+ DeclScopeObj.EnterDeclaratorScope();
ParseTrailingRequiresClause(DeclaratorInfo);
+ }
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
}
@@ -335,8 +341,8 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
// Recover as if it were an explicit specialization.
TemplateParameterLists FakedParamLists;
FakedParamLists.push_back(Actions.ActOnTemplateParameterList(
- 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, None,
- LAngleLoc, nullptr));
+ 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc,
+ std::nullopt, LAngleLoc, nullptr));
return ParseFunctionDefinition(
DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists,
@@ -386,7 +392,7 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
SourceLocation BoolKWLoc;
if (TryConsumeToken(tok::kw_bool, BoolKWLoc))
- Diag(Tok.getLocation(), diag::ext_concept_legacy_bool_keyword) <<
+ Diag(Tok.getLocation(), diag::err_concept_legacy_bool_keyword) <<
FixItHint::CreateRemoval(SourceLocation(BoolKWLoc));
DiagnoseAndSkipCXX11Attributes();
@@ -868,27 +874,39 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
/// template parameters.
///
/// type-parameter: [C++ temp.param]
-/// 'template' '<' template-parameter-list '>' type-parameter-key
-/// ...[opt] identifier[opt]
-/// 'template' '<' template-parameter-list '>' type-parameter-key
-/// identifier[opt] = id-expression
+/// template-head type-parameter-key ...[opt] identifier[opt]
+/// template-head type-parameter-key identifier[opt] = id-expression
/// type-parameter-key:
/// 'class'
/// 'typename' [C++1z]
-NamedDecl *
-Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
+/// template-head: [C++2a]
+/// 'template' '<' template-parameter-list '>'
+/// requires-clause[opt]
+NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
+ unsigned Position) {
assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
// Handle the template <...> part.
SourceLocation TemplateLoc = ConsumeToken();
SmallVector<NamedDecl*,8> TemplateParams;
SourceLocation LAngleLoc, RAngleLoc;
+ ExprResult OptionalRequiresClauseConstraintER;
{
MultiParseScope TemplateParmScope(*this);
if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams,
LAngleLoc, RAngleLoc)) {
return nullptr;
}
+ if (TryConsumeToken(tok::kw_requires)) {
+ OptionalRequiresClauseConstraintER =
+ Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression(
+ /*IsTrailingRequiresClause=*/false));
+ if (!OptionalRequiresClauseConstraintER.isUsable()) {
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater,
+ StopAtSemi | StopBeforeMatch);
+ return nullptr;
+ }
+ }
}
// Provide an ExtWarn if the C++1z feature of using 'typename' here is used.
@@ -950,11 +968,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true);
- TemplateParameterList *ParamList =
- Actions.ActOnTemplateParameterList(Depth, SourceLocation(),
- TemplateLoc, LAngleLoc,
- TemplateParams,
- RAngleLoc, nullptr);
+ TemplateParameterList *ParamList = Actions.ActOnTemplateParameterList(
+ Depth, SourceLocation(), TemplateLoc, LAngleLoc, TemplateParams,
+ RAngleLoc, OptionalRequiresClauseConstraintER.get());
// Grab a default argument (if available).
// Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
@@ -1414,12 +1430,15 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
///
/// \param SS The scope specifier appearing before the template-id, if any.
///
+/// \param AllowImplicitTypename whether this is a context where T::type
+/// denotes a dependent type.
/// \param IsClassName Is this template-id appearing in a context where we
/// know it names a class, such as in an elaborated-type-specifier or
/// base-specifier? ('typename' and 'template' are unneeded and disallowed
/// in those contexts.)
-void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
- bool IsClassName) {
+void Parser::AnnotateTemplateIdTokenAsType(
+ CXXScopeSpec &SS, ImplicitTypenameContext AllowImplicitTypename,
+ bool IsClassName) {
assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
@@ -1437,7 +1456,7 @@ void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS,
TemplateId->Template, TemplateId->Name,
TemplateId->TemplateNameLoc, TemplateId->LAngleLoc,
TemplateArgsPtr, TemplateId->RAngleLoc,
- /*IsCtorOrDtorName*/ false, IsClassName);
+ /*IsCtorOrDtorName=*/false, IsClassName, AllowImplicitTypename);
// Create the new "type" annotation token.
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Type);
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 512993a5278e..785749bff65a 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -46,7 +46,10 @@ using namespace clang;
/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt]
/// namespace-name ';'
///
-bool Parser::isCXXDeclarationStatement() {
+bool Parser::isCXXDeclarationStatement(
+ bool DisambiguatingWithExpression /*=false*/) {
+ assert(getLangOpts().CPlusPlus && "Must be called for C++ only.");
+
switch (Tok.getKind()) {
// asm-definition
case tok::kw_asm:
@@ -59,6 +62,42 @@ bool Parser::isCXXDeclarationStatement() {
case tok::kw_static_assert:
case tok::kw__Static_assert:
return true;
+ case tok::identifier: {
+ if (DisambiguatingWithExpression) {
+ RevertingTentativeParsingAction TPA(*this);
+ // Parse the C++ scope specifier.
+ CXXScopeSpec SS;
+ ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
+ /*ObjectHasErrors=*/false,
+ /*EnteringContext=*/true);
+
+ switch (Tok.getKind()) {
+ case tok::identifier: {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ bool isDeductionGuide =
+ Actions.isDeductionGuideName(getCurScope(), *II, Tok.getLocation(),
+ /*Template=*/nullptr);
+ if (Actions.isCurrentClassName(*II, getCurScope(), &SS) ||
+ isDeductionGuide) {
+ if (isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(),
+ isDeductionGuide,
+ DeclSpec::FriendSpecified::No))
+ return true;
+ }
+ break;
+ }
+ case tok::kw_operator:
+ return true;
+ case tok::annot_cxxscope: // Check if this is a dtor.
+ if (NextToken().is(tok::tilde))
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ [[fallthrough]];
// simple-declaration
default:
return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false);
@@ -111,8 +150,8 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
// a case.
bool InvalidAsDeclaration = false;
- TPResult TPR = isCXXDeclarationSpecifier(TPResult::False,
- &InvalidAsDeclaration);
+ TPResult TPR = isCXXDeclarationSpecifier(
+ ImplicitTypenameContext::No, TPResult::False, &InvalidAsDeclaration);
if (TPR != TPResult::Ambiguous)
return TPR != TPResult::False; // Returns true for TPResult::True or
// TPResult::Error.
@@ -158,10 +197,12 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
ConsumeToken();
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_typeof:
case tok::kw___attribute:
- case tok::kw___underlying_type: {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+ {
ConsumeToken();
if (Tok.isNot(tok::l_paren))
return TPResult::Error;
@@ -203,7 +244,7 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() {
case tok::annot_cxxscope:
ConsumeAnnotationToken();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
ConsumeAnyToken();
@@ -231,7 +272,7 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
// simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
// overwhelmingly common case that the next token is a '('.
if (Tok.isNot(tok::l_paren)) {
- TPResult TPR = isCXXDeclarationSpecifier();
+ TPResult TPR = isCXXDeclarationSpecifier(ImplicitTypenameContext::No);
if (TPR == TPResult::Ambiguous)
return TPResult::True;
if (TPR == TPResult::True || TPR == TPResult::Error)
@@ -440,7 +481,8 @@ bool Parser::isEnumBase(bool AllowSemi) {
// FIXME: We could disallow non-type decl-specifiers here, but it makes no
// difference: those specifiers are ill-formed regardless of the
// interpretation.
- TPResult R = isCXXDeclarationSpecifier(/*BracedCastResult*/ TPResult::True,
+ TPResult R = isCXXDeclarationSpecifier(ImplicitTypenameContext::No,
+ /*BracedCastResult=*/TPResult::True,
&InvalidAsDeclSpec);
if (R == TPResult::Ambiguous) {
// We either have a decl-specifier followed by '(' or an undeclared
@@ -454,7 +496,8 @@ bool Parser::isEnumBase(bool AllowSemi) {
return true;
// A second decl-specifier unambiguously indicatges an enum-base.
- R = isCXXDeclarationSpecifier(TPResult::True, &InvalidAsDeclSpec);
+ R = isCXXDeclarationSpecifier(ImplicitTypenameContext::No, TPResult::True,
+ &InvalidAsDeclSpec);
}
return R != TPResult::False;
@@ -485,7 +528,7 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement,
if (CanBeInitStatement && Tok.is(tok::kw_using))
return ConditionOrInitStatement::InitStmtDecl;
- if (State.update(isCXXDeclarationSpecifier()))
+ if (State.update(isCXXDeclarationSpecifier(ImplicitTypenameContext::No)))
return State.result();
// It might be a declaration; we need tentative parsing.
@@ -571,7 +614,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
// type. The resolution is that any construct that could possibly be a type-id
// in its syntactic context shall be considered a type-id.
- TPResult TPR = isCXXDeclarationSpecifier();
+ TPResult TPR = isCXXDeclarationSpecifier(ImplicitTypenameContext::No);
if (TPR != TPResult::Ambiguous)
return TPR != TPResult::False; // Returns true for TPResult::True or
// TPResult::Error.
@@ -932,7 +975,7 @@ Parser::TPResult Parser::TryParseOperatorId() {
// Maybe this is a conversion-function-id.
bool AnyDeclSpecifiers = false;
while (true) {
- TPResult TPR = isCXXDeclarationSpecifier();
+ TPResult TPR = isCXXDeclarationSpecifier(ImplicitTypenameContext::No);
if (TPR == TPResult::Error)
return TPR;
if (TPR == TPResult::False) {
@@ -1037,10 +1080,11 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
} else if (Tok.is(tok::l_paren)) {
ConsumeParen();
if (mayBeAbstract &&
- (Tok.is(tok::r_paren) || // 'int()' is a function.
- // 'int(...)' is a function.
+ (Tok.is(tok::r_paren) || // 'int()' is a function.
+ // 'int(...)' is a function.
(Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) ||
- isDeclarationSpecifier())) { // 'int(int)' is a function.
+ isDeclarationSpecifier(
+ ImplicitTypenameContext::No))) { // 'int(int)' is a function.
// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
// exception-specification[opt]
TPResult TPR = TryParseFunctionDeclarator();
@@ -1245,19 +1289,37 @@ public:
/// [GNU] restrict
///
Parser::TPResult
-Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
+Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
+ Parser::TPResult BracedCastResult,
bool *InvalidAsDeclSpec) {
- auto IsPlaceholderSpecifier = [&] (TemplateIdAnnotation *TemplateId,
- int Lookahead) {
+ auto IsPlaceholderSpecifier = [&](TemplateIdAnnotation *TemplateId,
+ int Lookahead) {
// We have a placeholder-constraint (we check for 'auto' or 'decltype' to
// distinguish 'C<int>;' from 'C<int> auto c = 1;')
return TemplateId->Kind == TNK_Concept_template &&
- GetLookAheadToken(Lookahead + 1).isOneOf(tok::kw_auto, tok::kw_decltype,
- // If we have an identifier here, the user probably forgot the
- // 'auto' in the placeholder constraint, e.g. 'C<int> x = 2;'
- // This will be diagnosed nicely later, so disambiguate as a
- // declaration.
- tok::identifier);
+ (GetLookAheadToken(Lookahead + 1)
+ .isOneOf(tok::kw_auto, tok::kw_decltype,
+ // If we have an identifier here, the user probably
+ // forgot the 'auto' in the placeholder constraint,
+ // e.g. 'C<int> x = 2;' This will be diagnosed nicely
+ // later, so disambiguate as a declaration.
+ tok::identifier,
+ // CVR qualifierslikely the same situation for the
+ // user, so let this be diagnosed nicely later. We
+ // cannot handle references here, as `C<int> & Other`
+ // and `C<int> && Other` are both legal.
+ tok::kw_const, tok::kw_volatile, tok::kw_restrict) ||
+ // While `C<int> && Other` is legal, doing so while not specifying a
+ // template argument is NOT, so see if we can fix up in that case at
+ // minimum. Concepts require at least 1 template parameter, so we
+ // can count on the argument count.
+ // FIXME: In the future, we migth be able to have SEMA look up the
+ // declaration for this concept, and see how many template
+ // parameters it has. If the concept isn't fully specified, it is
+ // possibly a situation where we want deduction, such as:
+ // `BinaryConcept<int> auto f = bar();`
+ (TemplateId->NumArgs == 0 &&
+ GetLookAheadToken(Lookahead + 1).isOneOf(tok::amp, tok::ampamp)));
};
switch (Tok.getKind()) {
case tok::identifier: {
@@ -1288,7 +1350,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// template template argument, we'll undo this when checking the
// validity of the argument.
if (getLangOpts().CPlusPlus17) {
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
return TPResult::Error;
if (Tok.isNot(tok::identifier))
break;
@@ -1309,7 +1371,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// a missing 'typename' keyword. Don't use TryAnnotateName in this case,
// since it will annotate as a primary expression, and we want to use the
// "missing 'typename'" logic.
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
return TPResult::Error;
// If annotation failed, assume it's a non-type.
// FIXME: If this happens due to an undeclared identifier, treat it as
@@ -1319,30 +1381,33 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
}
// We annotated this token as something. Recurse to handle whatever we got.
- return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec);
+ return isCXXDeclarationSpecifier(AllowImplicitTypename, BracedCastResult,
+ InvalidAsDeclSpec);
}
case tok::kw_typename: // typename T::type
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(ImplicitTypenameContext::Yes))
return TPResult::Error;
- return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec);
+ return isCXXDeclarationSpecifier(ImplicitTypenameContext::Yes,
+ BracedCastResult, InvalidAsDeclSpec);
case tok::coloncolon: { // ::foo::bar
const Token &Next = NextToken();
if (Next.isOneOf(tok::kw_new, // ::new
tok::kw_delete)) // ::delete
return TPResult::False;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case tok::kw___super:
case tok::kw_decltype:
// Annotate typenames and C++ scope specifiers. If we get one, just
// recurse to handle whatever we get.
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
return TPResult::Error;
- return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec);
+ return isCXXDeclarationSpecifier(AllowImplicitTypename, BracedCastResult,
+ InvalidAsDeclSpec);
// decl-specifier:
// storage-class-specifier
@@ -1401,7 +1466,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw_private:
if (!getLangOpts().OpenCL)
return TPResult::False;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw___private:
case tok::kw___local:
case tok::kw___global:
@@ -1414,6 +1479,9 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// OpenCL pipe
case tok::kw_pipe:
+ // HLSL address space qualifiers
+ case tok::kw_groupshared:
+
// GNU
case tok::kw_restrict:
case tok::kw__Complex:
@@ -1472,14 +1540,14 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (TemplateId->Kind != TNK_Type_template)
return TPResult::False;
CXXScopeSpec SS;
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
assert(Tok.is(tok::annot_typename));
goto case_typename;
}
case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
// We've already annotated a scope; try to annotate a type.
- if (TryAnnotateTypeOrScopeToken())
+ if (TryAnnotateTypeOrScopeToken(AllowImplicitTypename))
return TPResult::Error;
if (!Tok.is(tok::annot_typename)) {
if (Tok.is(tok::annot_cxxscope) &&
@@ -1510,8 +1578,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
bool isIdentifier = Tok.is(tok::identifier);
TPResult TPR = TPResult::False;
if (!isIdentifier)
- TPR = isCXXDeclarationSpecifier(BracedCastResult,
- InvalidAsDeclSpec);
+ TPR = isCXXDeclarationSpecifier(
+ AllowImplicitTypename, BracedCastResult, InvalidAsDeclSpec);
if (isIdentifier ||
TPR == TPResult::True || TPR == TPResult::Error)
@@ -1537,7 +1605,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()) {
+ switch (TryAnnotateName(/*CCC=*/nullptr, AllowImplicitTypename)) {
case ANK_Error:
return TPResult::Error;
case ANK_TentativeDecl:
@@ -1567,13 +1635,14 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// Annotated it, check again.
assert(Tok.isNot(tok::annot_cxxscope) ||
NextToken().isNot(tok::identifier));
- return isCXXDeclarationSpecifier(BracedCastResult, InvalidAsDeclSpec);
+ return isCXXDeclarationSpecifier(AllowImplicitTypename,
+ BracedCastResult, InvalidAsDeclSpec);
}
}
return TPResult::False;
}
// If that succeeded, fallthrough into the generic simple-type-id case.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// The ambiguity resides in a simple-type-specifier/typename-specifier
// followed by a '('. The '(' could either be the start of:
@@ -1616,7 +1685,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
return TPResult::True;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_char:
case tok::kw_wchar_t:
@@ -1682,8 +1751,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
return TPResult::True;
}
- // C++0x type traits support
- case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
return TPResult::True;
// C11 _Atomic
@@ -1721,7 +1790,8 @@ bool Parser::isCXXDeclarationSpecifierAType() {
case tok::annot_template_id:
case tok::annot_typename:
case tok::kw_typeof:
- case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
return true;
// elaborated-type-specifier
@@ -1825,7 +1895,8 @@ Parser::TPResult Parser::TryParseProtocolQualifiers() {
/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
/// exception-specification[opt]
///
-bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
+bool Parser::isCXXFunctionDeclarator(
+ bool *IsAmbiguous, ImplicitTypenameContext AllowImplicitTypename) {
// C++ 8.2p1:
// The ambiguity arising from the similarity between a function-style cast and
@@ -1840,7 +1911,9 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
ConsumeParen();
bool InvalidAsDeclaration = false;
- TPResult TPR = TryParseParameterDeclarationClause(&InvalidAsDeclaration);
+ TPResult TPR = TryParseParameterDeclarationClause(
+ &InvalidAsDeclaration, /*VersusTemplateArgument=*/false,
+ AllowImplicitTypename);
if (TPR == TPResult::Ambiguous) {
if (Tok.isNot(tok::r_paren))
TPR = TPResult::False;
@@ -1884,9 +1957,9 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
/// attributes[opt] '=' assignment-expression
///
-Parser::TPResult
-Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
- bool VersusTemplateArgument) {
+Parser::TPResult Parser::TryParseParameterDeclarationClause(
+ bool *InvalidAsDeclaration, bool VersusTemplateArgument,
+ ImplicitTypenameContext AllowImplicitTypename) {
if (Tok.is(tok::r_paren))
return TPResult::Ambiguous;
@@ -1919,8 +1992,8 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
// decl-specifier-seq
// A parameter-declaration's initializer must be preceded by an '=', so
// decl-specifier-seq '{' is not a parameter in C++11.
- TPResult TPR = isCXXDeclarationSpecifier(TPResult::False,
- InvalidAsDeclaration);
+ TPResult TPR = isCXXDeclarationSpecifier(
+ AllowImplicitTypename, TPResult::False, InvalidAsDeclaration);
// A declaration-specifier (not followed by '(' or '{') means this can't be
// an expression, but it could still be a template argument.
if (TPR != TPResult::Ambiguous &&
@@ -1937,7 +2010,7 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration,
if (SeenType && Tok.is(tok::identifier))
return TPResult::True;
- TPR = isCXXDeclarationSpecifier(TPResult::False,
+ TPR = isCXXDeclarationSpecifier(AllowImplicitTypename, TPResult::False,
InvalidAsDeclaration);
if (TPR == TPResult::Error)
return TPR;
@@ -2099,9 +2172,9 @@ Parser::TPResult Parser::isTemplateArgumentList(unsigned TokensToSkip) {
// but one good distinguishing factor is that a "decl-specifier" not
// followed by '(' or '{' can't appear in an expression.
bool InvalidAsTemplateArgumentList = false;
- if (isCXXDeclarationSpecifier(TPResult::False,
- &InvalidAsTemplateArgumentList) ==
- TPResult::True)
+ if (isCXXDeclarationSpecifier(ImplicitTypenameContext::No, TPResult::False,
+ &InvalidAsTemplateArgumentList) ==
+ TPResult::True)
return TPResult::True;
if (InvalidAsTemplateArgumentList)
return TPResult::False;
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index fd044660845b..6db3dc3156fd 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -386,7 +386,7 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
case tok::semi:
if (HasFlagsSet(Flags, StopAtSemi))
return false;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
// Skip this token.
ConsumeAnyToken();
@@ -707,8 +707,7 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
// Late template parsing can begin.
Actions.SetLateTemplateParser(LateTemplateParserCallback, nullptr, this);
- if (!PP.isIncrementalProcessingEnabled())
- Actions.ActOnEndOfTranslationUnit();
+ Actions.ActOnEndOfTranslationUnit();
//else don't tell Sema that we ended parsing: more input might come.
return true;
@@ -731,10 +730,17 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
break;
}
- ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
+ ParsedAttributes DeclAttrs(AttrFactory);
+ ParsedAttributes DeclSpecAttrs(AttrFactory);
+ // GNU attributes are applied to the declaration specification while the
+ // standard attributes are applied to the declaration. We parse the two
+ // attribute sets into different containters so we can apply them during
+ // the regular parsing process.
+ while (MaybeParseCXX11Attributes(DeclAttrs) ||
+ MaybeParseGNUAttributes(DeclSpecAttrs))
+ ;
- Result = ParseExternalDeclaration(attrs);
+ Result = ParseExternalDeclaration(DeclAttrs, DeclSpecAttrs);
// An empty Result might mean a line with ';' or some parsing error, ignore
// it.
if (Result) {
@@ -744,6 +750,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
else if (ImportState == Sema::ModuleImportState::ImportAllowed)
// Non-imports disallow further imports.
ImportState = Sema::ModuleImportState::ImportFinished;
+ else if (ImportState ==
+ Sema::ModuleImportState::PrivateFragmentImportAllowed)
+ // Non-imports disallow further imports.
+ ImportState = Sema::ModuleImportState::PrivateFragmentImportFinished;
}
return false;
}
@@ -777,8 +787,10 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result,
///
/// [Modules-TS] module-import-declaration
///
-Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
- ParsingDeclSpec *DS) {
+Parser::DeclGroupPtrTy
+Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
+ ParsedAttributes &DeclSpecAttrs,
+ ParsingDeclSpec *DS) {
DestroyTemplateIdAnnotationsRAIIObj CleanupRAII(*this);
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -866,7 +878,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseExternalDeclaration(Attrs);
+ return ParseExternalDeclaration(Attrs, DeclSpecAttrs);
}
case tok::kw_asm: {
ProhibitAttributes(Attrs);
@@ -894,7 +906,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
break;
}
case tok::at:
- return ParseObjCAtDirectives(Attrs);
+ return ParseObjCAtDirectives(Attrs, DeclSpecAttrs);
case tok::minus:
case tok::plus:
if (!getLangOpts().ObjC) {
@@ -909,7 +921,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
if (CurParsedObjCImpl) {
// Code-complete Objective-C methods even without leading '-'/'+' prefix.
Actions.CodeCompleteObjCMethodDecl(getCurScope(),
- /*IsInstanceMethod=*/None,
+ /*IsInstanceMethod=*/std::nullopt,
/*ReturnType=*/nullptr);
}
Actions.CodeCompleteOrdinaryName(
@@ -932,7 +944,7 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
}
// This must be 'export template'. Parse it so we can diagnose our lack
// of support.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::kw_using:
case tok::kw_namespace:
case tok::kw_typedef:
@@ -942,10 +954,18 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
// A function definition cannot start with any of these keywords.
{
SourceLocation DeclEnd;
- ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
- EmptyDeclSpecAttrs);
+ DeclSpecAttrs);
+ }
+
+ case tok::kw_cbuffer:
+ case tok::kw_tbuffer:
+ if (getLangOpts().HLSL) {
+ SourceLocation DeclEnd;
+ return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
+ DeclSpecAttrs);
}
+ goto dont_know;
case tok::kw_static:
// Parse (then ignore) 'static' prior to a template instantiation. This is
@@ -954,9 +974,8 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 0;
SourceLocation DeclEnd;
- ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
- EmptyDeclSpecAttrs);
+ DeclSpecAttrs);
}
goto dont_know;
@@ -967,9 +986,8 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
// Inline namespaces. Allowed as an extension even in C++03.
if (NextKind == tok::kw_namespace) {
SourceLocation DeclEnd;
- ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
- EmptyDeclSpecAttrs);
+ DeclSpecAttrs);
}
// Parse (then ignore) 'inline' prior to a template instantiation. This is
@@ -978,9 +996,8 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored)
<< 1;
SourceLocation DeclEnd;
- ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs,
- EmptyDeclSpecAttrs);
+ DeclSpecAttrs);
}
}
goto dont_know;
@@ -1015,8 +1032,13 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
ConsumeToken();
return nullptr;
}
+ if (PP.isIncrementalProcessingEnabled() &&
+ !isDeclarationStatement(/*DisambiguatingWithExpression=*/true))
+ return ParseTopLevelStmtDecl();
+
// We can't tell whether this is a function-definition or declaration yet.
- return ParseDeclarationOrFunctionDefinition(Attrs, DS);
+ if (!SingleDecl)
+ return ParseDeclarationOrFunctionDefinition(Attrs, DeclSpecAttrs, DS);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1053,7 +1075,7 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
// Handle K&R C argument lists: int X(f) int f; {}
if (!getLangOpts().CPlusPlus &&
Declarator.getFunctionTypeInfo().isKNRPrototype())
- return isDeclarationSpecifier();
+ return isDeclarationSpecifier(ImplicitTypenameContext::No);
if (getLangOpts().CPlusPlus && Tok.is(tok::equal)) {
const Token &KW = NextToken();
@@ -1081,7 +1103,17 @@ bool Parser::isStartOfFunctionDefinition(const ParsingDeclarator &Declarator) {
/// [OMP] allocate-directive [TODO]
///
Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
- ParsedAttributes &Attrs, ParsingDeclSpec &DS, AccessSpecifier AS) {
+ ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs,
+ ParsingDeclSpec &DS, AccessSpecifier AS) {
+ // Because we assume that the DeclSpec has not yet been initialised, we simply
+ // overwrite the source range and attribute the provided leading declspec
+ // attributes.
+ assert(DS.getSourceRange().isInvalid() &&
+ "expected uninitialised source range");
+ DS.SetRangeStart(DeclSpecAttrs.Range.getBegin());
+ DS.SetRangeEnd(DeclSpecAttrs.Range.getEnd());
+ DS.takeAttributesFrom(DeclSpecAttrs);
+
MaybeParseMicrosoftAttributes(DS.getAttributes());
// Parse the common declaration-specifiers piece.
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS,
@@ -1180,9 +1212,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
}
Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
- ParsedAttributes &Attrs, ParsingDeclSpec *DS, AccessSpecifier AS) {
+ ParsedAttributes &Attrs, ParsedAttributes &DeclSpecAttrs,
+ ParsingDeclSpec *DS, AccessSpecifier AS) {
if (DS) {
- return ParseDeclOrFunctionDefInternal(Attrs, *DS, AS);
+ return ParseDeclOrFunctionDefInternal(Attrs, DeclSpecAttrs, *DS, AS);
} else {
ParsingDeclSpec PDS(*this);
// Must temporarily exit the objective-c container scope for
@@ -1190,7 +1223,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition(
// afterwards.
ObjCDeclContextSwitch ObjCDC(*this);
- return ParseDeclOrFunctionDefInternal(Attrs, PDS, AS);
+ return ParseDeclOrFunctionDefInternal(Attrs, DeclSpecAttrs, PDS, AS);
}
}
@@ -1462,7 +1495,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
Scope::FunctionDeclarationScope | Scope::DeclScope);
// Read all the argument declarations.
- while (isDeclarationSpecifier()) {
+ while (isDeclarationSpecifier(ImplicitTypenameContext::No)) {
SourceLocation DSStart = Tok.getLocation();
// Parse the common declaration-specifiers piece.
@@ -1675,8 +1708,12 @@ void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) {
///
/// \param CCC Indicates how to perform typo-correction for this name. If NULL,
/// no typo correction will be performed.
+/// \param AllowImplicitTypename Whether we are in a context where a dependent
+/// nested-name-specifier without typename is treated as a type (e.g.
+/// T::type).
Parser::AnnotatedNameKind
-Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
+Parser::TryAnnotateName(CorrectionCandidateCallback *CCC,
+ ImplicitTypenameContext AllowImplicitTypename) {
assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
const bool EnteringContext = false;
@@ -1690,7 +1727,8 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
return ANK_Error;
if (Tok.isNot(tok::identifier) || SS.isInvalid()) {
- if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation))
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+ AllowImplicitTypename))
return ANK_Error;
return ANK_Unresolved;
}
@@ -1700,10 +1738,11 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
// FIXME: Move the tentative declaration logic into ClassifyName so we can
// typo-correct to tentatively-declared identifiers.
- if (isTentativelyDeclared(Name)) {
+ if (isTentativelyDeclared(Name) && SS.isEmpty()) {
// Identifier has been tentatively declared, and thus cannot be resolved as
// an expression. Fall back to annotating it as a type.
- if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation))
+ if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+ AllowImplicitTypename))
return ANK_Error;
return Tok.is(tok::annot_typename) ? ANK_Success : ANK_TentativeDecl;
}
@@ -1830,7 +1869,7 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
AnnotateScopeToken(SS, !WasScopeAnnotation);
return ANK_TemplateName;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate:
case Sema::NC_UndeclaredTemplate: {
@@ -1899,7 +1938,8 @@ bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
///
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
-bool Parser::TryAnnotateTypeOrScopeToken() {
+bool Parser::TryAnnotateTypeOrScopeToken(
+ ImplicitTypenameContext AllowImplicitTypename) {
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) ||
Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id) ||
@@ -1916,7 +1956,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
if (getLangOpts().MSVCCompat && NextToken().is(tok::kw_typedef)) {
Token TypedefToken;
PP.Lex(TypedefToken);
- bool Result = TryAnnotateTypeOrScopeToken();
+ bool Result = TryAnnotateTypeOrScopeToken(AllowImplicitTypename);
PP.EnterToken(Tok, /*IsReinject=*/true);
Tok = TypedefToken;
if (!Result)
@@ -1942,7 +1982,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
Tok.is(tok::annot_decltype)) {
// Attempt to recover by skipping the invalid 'typename'
if (Tok.is(tok::annot_decltype) ||
- (!TryAnnotateTypeOrScopeToken() && Tok.isAnnotation())) {
+ (!TryAnnotateTypeOrScopeToken(AllowImplicitTypename) &&
+ Tok.isAnnotation())) {
unsigned DiagID = diag::err_expected_qualified_after_typename;
// MS compatibility: MSVC permits using known types with typename.
// e.g. "typedef typename T* pointer_type"
@@ -2008,22 +2049,24 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
/*EnteringContext*/ false))
return true;
- return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation);
+ return TryAnnotateTypeOrScopeTokenAfterScopeSpec(SS, !WasScopeAnnotation,
+ AllowImplicitTypename);
}
/// Try to annotate a type or scope token, having already parsed an
/// optional scope specifier. \p IsNewScope should be \c true unless the scope
/// specifier was extracted from an existing tok::annot_cxxscope annotation.
-bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
- bool IsNewScope) {
+bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(
+ CXXScopeSpec &SS, bool IsNewScope,
+ ImplicitTypenameContext AllowImplicitTypename) {
if (Tok.is(tok::identifier)) {
// Determine whether the identifier is a type name.
if (ParsedType Ty = Actions.getTypeName(
*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS,
false, NextToken().is(tok::period), nullptr,
/*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo*/true,
- /*IsClassTemplateDeductionContext*/true)) {
+ /*NonTrivialTypeSourceInfo=*/true,
+ /*IsClassTemplateDeductionContext=*/true, AllowImplicitTypename)) {
SourceLocation BeginLoc = Tok.getLocation();
if (SS.isNotEmpty()) // it was a C++ qualified type name.
BeginLoc = SS.getBeginLoc();
@@ -2060,9 +2103,9 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
}
if (!getLangOpts().CPlusPlus) {
- // If we're in C, we can't have :: tokens at all (the lexer won't return
- // them). If the identifier is not a type, then it can't be scope either,
- // just early exit.
+ // If we're in C, the only place we can have :: tokens is C2x
+ // attribute which is parsed elsewhere. If the identifier is not a type,
+ // then it can't be scope either, just early exit.
return false;
}
@@ -2109,7 +2152,7 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
// template-id annotation in a context where we weren't allowed
// to produce a type annotation token. Update the template-id
// annotation token to a type annotation token now.
- AnnotateTemplateIdTokenAsType(SS);
+ AnnotateTemplateIdTokenAsType(SS, AllowImplicitTypename);
return false;
}
}
@@ -2167,7 +2210,7 @@ bool Parser::isTokenEqualOrEqualTypo() {
Diag(Tok, diag::err_invalid_token_after_declarator_suggest_equal)
<< Kind
<< FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), "=");
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::equal:
return true;
}
@@ -2322,7 +2365,8 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
ParsedAttributes Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
- DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs);
+ ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);
+ DeclGroupPtrTy Result = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs);
if (Result && !getCurScope()->getParent())
Actions.getASTConsumer().HandleTopLevelDecl(Result.get());
}
@@ -2387,7 +2431,9 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
SourceLocation PrivateLoc = ConsumeToken();
DiagnoseAndSkipCXX11Attributes();
ExpectAndConsumeSemi(diag::err_private_module_fragment_expected_semi);
- ImportState = Sema::ModuleImportState::PrivateFragment;
+ ImportState = ImportState == Sema::ModuleImportState::ImportAllowed
+ ? Sema::ModuleImportState::PrivateFragmentImportAllowed
+ : Sema::ModuleImportState::PrivateFragmentImportFinished;
return Actions.ActOnPrivateModuleFragmentDecl(ModuleLoc, PrivateLoc);
}
@@ -2504,23 +2550,28 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
SeenError = false;
break;
case Sema::ModuleImportState::GlobalFragment:
- // We can only have pre-processor directives in the global module
- // fragment. We cannot import a named modules here, however we have a
- // header unit import.
- if (!HeaderUnit || HeaderUnit->Kind != Module::ModuleKind::ModuleHeaderUnit)
- Diag(ImportLoc, diag::err_import_in_wrong_fragment) << IsPartition << 0;
+ case Sema::ModuleImportState::PrivateFragmentImportAllowed:
+ // We can only have pre-processor directives in the global module fragment
+ // which allows pp-import, but not of a partition (since the global module
+ // does not have partitions).
+ // We cannot import a partition into a private module fragment, since
+ // [module.private.frag]/1 disallows private module fragments in a multi-
+ // TU module.
+ if (IsPartition || (HeaderUnit && HeaderUnit->Kind !=
+ Module::ModuleKind::ModuleHeaderUnit))
+ Diag(ImportLoc, diag::err_import_in_wrong_fragment)
+ << IsPartition
+ << (ImportState == Sema::ModuleImportState::GlobalFragment ? 0 : 1);
else
SeenError = false;
break;
case Sema::ModuleImportState::ImportFinished:
+ case Sema::ModuleImportState::PrivateFragmentImportFinished:
if (getLangOpts().CPlusPlusModules)
Diag(ImportLoc, diag::err_import_not_allowed_here);
else
SeenError = false;
break;
- case Sema::ModuleImportState::PrivateFragment:
- Diag(ImportLoc, diag::err_import_in_wrong_fragment) << IsPartition << 1;
- break;
}
if (SeenError) {
ExpectAndConsumeSemi(diag::err_module_expected_semi);
diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp
index 70ea2fcd3d04..083a9c09297e 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -488,14 +488,14 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) {
++TokOffs;
--TokLen;
// FALL THROUGH to chop the 8
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::wide_string_literal:
case tok::utf16_string_literal:
case tok::utf32_string_literal:
// Chop off the L, u, U or 8 prefix
++TokOffs;
--TokLen;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::string_literal:
// FIXME: Exclude the optional ud-suffix from the highlighted range.
HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 9780a0aba749..4530154ac944 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -16,8 +16,10 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtCXX.h"
@@ -29,6 +31,7 @@
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/Analyses/UnsafeBufferUsage.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
@@ -47,6 +50,7 @@
#include <algorithm>
#include <deque>
#include <iterator>
+#include <optional>
using namespace clang;
@@ -326,7 +330,7 @@ static void visitReachableThrows(
if (!Reachable[B->getBlockID()])
continue;
for (CFGElement &E : *B) {
- Optional<CFGStmt> S = E.getAs<CFGStmt>();
+ std::optional<CFGStmt> S = E.getAs<CFGStmt>();
if (!S)
continue;
if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt()))
@@ -1113,19 +1117,19 @@ namespace {
if (!ReachableBlocks.count(P)) {
for (const CFGElement &Elem : llvm::reverse(*P)) {
- if (Optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
- if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
- // Don't issue a warning for an unreachable fallthrough
- // attribute in template instantiations as it may not be
- // unreachable in all instantiations of the template.
- if (!IsTemplateInstantiation)
- S.Diag(AS->getBeginLoc(),
- diag::warn_unreachable_fallthrough_attr);
- markFallthroughVisited(AS);
- ++AnnotatedCnt;
- break;
- }
- // Don't care about other unreachable statements.
+ if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
+ if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
+ // Don't issue a warning for an unreachable fallthrough
+ // attribute in template instantiations as it may not be
+ // unreachable in all instantiations of the template.
+ if (!IsTemplateInstantiation)
+ S.Diag(AS->getBeginLoc(),
+ diag::warn_unreachable_fallthrough_attr);
+ markFallthroughVisited(AS);
+ ++AnnotatedCnt;
+ break;
+ }
+ // Don't care about other unreachable statements.
}
}
// If there are no unreachable statements, this may be a special
@@ -1198,7 +1202,7 @@ namespace {
if (const Stmt *Term = B.getTerminatorStmt())
return Term;
for (const CFGElement &Elem : llvm::reverse(B))
- if (Optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
+ if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>())
return CS->getStmt();
// Workaround to detect a statement thrown out by CFGBuilder:
// case X: {} case Y:
@@ -2139,6 +2143,71 @@ public:
} // namespace clang
//===----------------------------------------------------------------------===//
+// Unsafe buffer usage analysis.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
+ Sema &S;
+
+public:
+ UnsafeBufferUsageReporter(Sema &S) : S(S) {}
+
+ void handleUnsafeOperation(const Stmt *Operation,
+ bool IsRelatedToDecl) override {
+ SourceLocation Loc;
+ SourceRange Range;
+ unsigned MsgParam = 0;
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) {
+ Loc = ASE->getBase()->getExprLoc();
+ Range = ASE->getBase()->getSourceRange();
+ MsgParam = 2;
+ } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) {
+ BinaryOperator::Opcode Op = BO->getOpcode();
+ if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub ||
+ Op == BO_SubAssign) {
+ if (BO->getRHS()->getType()->isIntegerType()) {
+ Loc = BO->getLHS()->getExprLoc();
+ Range = BO->getLHS()->getSourceRange();
+ } else {
+ Loc = BO->getRHS()->getExprLoc();
+ Range = BO->getRHS()->getSourceRange();
+ }
+ MsgParam = 1;
+ }
+ } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) {
+ UnaryOperator::Opcode Op = UO->getOpcode();
+ if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc ||
+ Op == UO_PostDec) {
+ Loc = UO->getSubExpr()->getExprLoc();
+ Range = UO->getSubExpr()->getSourceRange();
+ MsgParam = 1;
+ }
+ } else {
+ Loc = Operation->getBeginLoc();
+ Range = Operation->getSourceRange();
+ }
+ if (IsRelatedToDecl)
+ S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range;
+ else
+ S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range;
+ }
+
+ // FIXME: rename to handleUnsafeVariable
+ void handleFixableVariable(const VarDecl *Variable,
+ FixItList &&Fixes) override {
+ const auto &D =
+ S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable);
+ D << Variable;
+ D << (Variable->getType()->isPointerType() ? 0 : 1);
+ D << Variable->getSourceRange();
+ for (const auto &F : Fixes)
+ D << F;
+ }
+};
+} // namespace
+
+//===----------------------------------------------------------------------===//
// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
// warnings on a function, method, or block.
//===----------------------------------------------------------------------===//
@@ -2269,7 +2338,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
}
// Install the logical handler.
- llvm::Optional<LogicalErrorHandler> LEH;
+ std::optional<LogicalErrorHandler> LEH;
if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
LEH.emplace(S);
AC.getCFGBuildOptions().Observer = &*LEH;
@@ -2430,6 +2499,13 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
if (S.getLangOpts().CPlusPlus && isNoexcept(FD))
checkThrowInNonThrowingFunc(S, FD, AC);
+ // Emit unsafe buffer usage warnings and fixits.
+ if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) ||
+ !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) {
+ UnsafeBufferUsageReporter R(S);
+ checkUnsafeBufferUsage(D, R);
+ }
+
// If none of the previous checks caused a CFG build, trigger one here
// for the logical error handler.
if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index e93be3e04dfe..b91291cfea0b 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -776,7 +776,7 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
// Do nothing: Patterns can come with cursor kinds!
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case RK_Declaration: {
// Set the availability based on attributes.
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index d4dc790c008a..d59778b5b614 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Sema.h"
@@ -238,7 +239,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
// is already used (consider a function returning a function pointer) or too
// small (function with too many parameters), go to the heap.
if (!TheDeclarator.InlineStorageUsed &&
- NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) {
+ NumParams <= std::size(TheDeclarator.InlineParams)) {
I.Fun.Params = TheDeclarator.InlineParams;
new (I.Fun.Params) ParamInfo[NumParams];
I.Fun.DeleteParams = false;
@@ -307,8 +308,7 @@ void Declarator::setDecompositionBindings(
// Allocate storage for bindings and stash them away.
if (Bindings.size()) {
- if (!InlineStorageUsed &&
- Bindings.size() <= llvm::array_lengthof(InlineBindings)) {
+ if (!InlineStorageUsed && Bindings.size() <= std::size(InlineBindings)) {
BindingGroup.Bindings = InlineBindings;
BindingGroup.DeleteBindings = false;
InlineStorageUsed = true;
@@ -384,13 +384,16 @@ bool Declarator::isDeclarationOfFunction() const {
return false;
case TST_decltype:
+ case TST_typeof_unqualExpr:
case TST_typeofExpr:
if (Expr *E = DS.getRepAsExpr())
return E->getType()->isFunctionType();
return false;
- case TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case TST_typename:
+ case TST_typeof_unqualType:
case TST_typeofType: {
QualType QT = DS.getRepAsType().get();
if (QT.isNull())
@@ -412,7 +415,7 @@ bool Declarator::isDeclarationOfFunction() const {
bool Declarator::isStaticMember() {
assert(getContext() == DeclaratorContext::Member);
return getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
- (getName().Kind == UnqualifiedIdKind::IK_OperatorFunctionId &&
+ (getName().getKind() == UnqualifiedIdKind::IK_OperatorFunctionId &&
CXXMethodDecl::isStaticOverloadedOperator(
getName().OperatorFunctionId.Operator));
}
@@ -572,11 +575,16 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_typename: return "type-name";
case DeclSpec::TST_typeofType:
case DeclSpec::TST_typeofExpr: return "typeof";
+ case DeclSpec::TST_typeof_unqualType:
+ case DeclSpec::TST_typeof_unqualExpr: return "typeof_unqual";
case DeclSpec::TST_auto: return "auto";
case DeclSpec::TST_auto_type: return "__auto_type";
case DeclSpec::TST_decltype: return "(decltype)";
case DeclSpec::TST_decltype_auto: return "decltype(auto)";
- case DeclSpec::TST_underlyingType: return "__underlying_type";
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
+ case DeclSpec::TST_##Trait: \
+ return "__" #Trait;
+#include "clang/Basic/TransformTypeTraits.def"
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_atomic: return "_Atomic";
case DeclSpec::TST_BFloat16: return "__bf16";
@@ -1109,9 +1117,8 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
}
/// Finish - This does final analysis of the declspec, rejecting things like
-/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
-/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
-/// DeclSpec is guaranteed self-consistent, even if an error occurred.
+/// "_Imaginary" (lacking an FP type). After calling this method, DeclSpec is
+/// guaranteed to be self-consistent, even if an error occurred.
void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp
index 56c2dd40bd9a..3ff4e75b5694 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -11,24 +11,391 @@
#include "clang/Sema/HLSLExternalSemaSource.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/HLSLRuntime.h"
+#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
+#include "llvm/Frontend/HLSL/HLSLResource.h"
+
+#include <functional>
using namespace clang;
+using namespace llvm::hlsl;
+
+namespace {
+
+struct TemplateParameterListBuilder;
+
+struct BuiltinTypeDeclBuilder {
+ CXXRecordDecl *Record = nullptr;
+ ClassTemplateDecl *Template = nullptr;
+ ClassTemplateDecl *PrevTemplate = nullptr;
+ NamespaceDecl *HLSLNamespace = nullptr;
+ llvm::StringMap<FieldDecl *> Fields;
+
+ BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
+ Record->startDefinition();
+ Template = Record->getDescribedClassTemplate();
+ }
+
+ BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
+ : HLSLNamespace(Namespace) {
+ ASTContext &AST = S.getASTContext();
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+
+ LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
+ CXXRecordDecl *PrevDecl = nullptr;
+ if (S.LookupQualifiedName(Result, HLSLNamespace)) {
+ NamedDecl *Found = Result.getFoundDecl();
+ if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
+ PrevDecl = TD->getTemplatedDecl();
+ PrevTemplate = TD;
+ } else
+ PrevDecl = dyn_cast<CXXRecordDecl>(Found);
+ assert(PrevDecl && "Unexpected lookup result type.");
+ }
+
+ if (PrevDecl && PrevDecl->isCompleteDefinition()) {
+ Record = PrevDecl;
+ return;
+ }
+
+ Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::TTK_Class,
+ HLSLNamespace, SourceLocation(),
+ SourceLocation(), &II, PrevDecl, true);
+ Record->setImplicit(true);
+ Record->setLexicalDeclContext(HLSLNamespace);
+ Record->setHasExternalLexicalStorage();
+
+ // Don't let anyone derive from built-in types.
+ Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
+ AttributeCommonInfo::AS_Keyword,
+ FinalAttr::Keyword_final));
+ }
+
+ ~BuiltinTypeDeclBuilder() {
+ if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
+ HLSLNamespace->addDecl(Record);
+ }
+
+ BuiltinTypeDeclBuilder &
+ addMemberVariable(StringRef Name, QualType Type,
+ AccessSpecifier Access = AccessSpecifier::AS_private) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Record->isBeingDefined() &&
+ "Definition must be started before adding members!");
+ ASTContext &AST = Record->getASTContext();
+
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+ TypeSourceInfo *MemTySource =
+ AST.getTrivialTypeSourceInfo(Type, SourceLocation());
+ auto *Field = FieldDecl::Create(
+ AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
+ nullptr, false, InClassInitStyle::ICIS_NoInit);
+ Field->setAccess(Access);
+ Field->setImplicit(true);
+ Record->addDecl(Field);
+ Fields[Name] = Field;
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &
+ addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ QualType Ty = Record->getASTContext().VoidPtrTy;
+ if (Template) {
+ if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
+ Template->getTemplateParameters()->getParam(0)))
+ Ty = Record->getASTContext().getPointerType(
+ QualType(TTD->getTypeForDecl(), 0));
+ }
+ return addMemberVariable("h", Ty, Access);
+ }
+
+ BuiltinTypeDeclBuilder &
+ annotateResourceClass(HLSLResourceAttr::ResourceClass RC,
+ HLSLResourceAttr::ResourceKind RK) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ Record->addAttr(
+ HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RC, RK));
+ return *this;
+ }
+
+ static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
+ StringRef Name) {
+ CXXScopeSpec SS;
+ IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
+ DeclarationNameInfo NameInfo =
+ DeclarationNameInfo(DeclarationName(&II), SourceLocation());
+ LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
+ S.LookupParsedName(R, S.getCurScope(), &SS, false);
+ assert(R.isSingleResult() &&
+ "Since this is a builtin it should always resolve!");
+ auto *VD = cast<ValueDecl>(R.getFoundDecl());
+ QualType Ty = VD->getType();
+ return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
+ VD, false, NameInfo, Ty, VK_PRValue);
+ }
+
+ static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
+ return IntegerLiteral::Create(
+ AST,
+ llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
+ static_cast<uint8_t>(RC)),
+ AST.UnsignedCharTy, SourceLocation());
+ }
+
+ BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
+ ResourceClass RC) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ ASTContext &AST = Record->getASTContext();
+
+ QualType ConstructorType =
+ AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
+
+ CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
+ DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
+ CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
+ AST, Record, SourceLocation(),
+ DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
+ AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
+ ExplicitSpecifier(), false, true, false,
+ ConstexprSpecKind::Unspecified);
+
+ DeclRefExpr *Fn =
+ lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle");
+
+ Expr *RCExpr = emitResourceClassExpr(AST, RC);
+ Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue,
+ SourceLocation(), FPOptionsOverride());
+
+ CXXThisExpr *This = new (AST) CXXThisExpr(
+ SourceLocation(),
+ Constructor->getThisType().getTypePtr()->getPointeeType(), true);
+ This->setValueKind(ExprValueKind::VK_LValue);
+ Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"],
+ Fields["h"]->getType(), VK_LValue,
+ OK_Ordinary);
+
+ // If the handle isn't a void pointer, cast the builtin result to the
+ // correct type.
+ if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) {
+ Call = CXXStaticCastExpr::Create(
+ AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr,
+ AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()),
+ FPOptionsOverride(), SourceLocation(), SourceLocation(),
+ SourceRange());
+ }
+
+ BinaryOperator *Assign = BinaryOperator::Create(
+ AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary,
+ SourceLocation(), FPOptionsOverride());
+
+ Constructor->setBody(
+ CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(),
+ SourceLocation(), SourceLocation()));
+ Constructor->setAccess(AccessSpecifier::AS_public);
+ Record->addDecl(Constructor);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ addArraySubscriptOperator(true);
+ addArraySubscriptOperator(false);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Fields.count("h") > 0 &&
+ "Subscript operator must be added after the handle.");
+
+ FieldDecl *Handle = Fields["h"];
+ ASTContext &AST = Record->getASTContext();
+
+ assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy &&
+ "Not yet supported for void pointer handles.");
+
+ QualType ElemTy =
+ QualType(Handle->getType()->getPointeeOrArrayElementType(), 0);
+ QualType ReturnTy = ElemTy;
+
+ FunctionProtoType::ExtProtoInfo ExtInfo;
+
+ // Subscript operators return references to elements, const makes the
+ // reference and method const so that the underlying data is not mutable.
+ ReturnTy = AST.getLValueReferenceType(ReturnTy);
+ if (IsConst) {
+ ExtInfo.TypeQuals.addConst();
+ ReturnTy.addConst();
+ }
+
+ QualType MethodTy =
+ AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
+ auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
+ auto *MethodDecl = CXXMethodDecl::Create(
+ AST, Record, SourceLocation(),
+ DeclarationNameInfo(
+ AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
+ SourceLocation()),
+ MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
+ SourceLocation());
+
+ IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
+ auto *IdxParam = ParmVarDecl::Create(
+ AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
+ &II, AST.UnsignedIntTy,
+ AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
+ SC_None, nullptr);
+ MethodDecl->setParams({IdxParam});
+
+ // Also add the parameter to the function prototype.
+ auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
+ FnProtoLoc.setParam(0, IdxParam);
+
+ auto *This = new (AST) CXXThisExpr(
+ SourceLocation(),
+ MethodDecl->getThisType().getTypePtr()->getPointeeType(), true);
+ This->setValueKind(ExprValueKind::VK_LValue);
+ auto *HandleAccess = MemberExpr::CreateImplicit(
+ AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);
+
+ auto *IndexExpr = DeclRefExpr::Create(
+ AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false,
+ DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()),
+ AST.UnsignedIntTy, VK_PRValue);
+
+ auto *Array =
+ new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue,
+ OK_Ordinary, SourceLocation());
+
+ auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr);
+
+ MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
+ SourceLocation(),
+ SourceLocation()));
+ MethodDecl->setLexicalDeclContext(Record);
+ MethodDecl->setAccess(AccessSpecifier::AS_public);
+ MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
+ AST, SourceRange(), AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::CXX11_clang_always_inline));
+ Record->addDecl(MethodDecl);
+
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &startDefinition() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ Record->startDefinition();
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &completeDefinition() {
+ if (Record->isCompleteDefinition())
+ return *this;
+ assert(Record->isBeingDefined() &&
+ "Definition must be started before completing it.");
+
+ Record->completeDefinition();
+ return *this;
+ }
+
+ TemplateParameterListBuilder addTemplateArgumentList();
+};
+
+struct TemplateParameterListBuilder {
+ BuiltinTypeDeclBuilder &Builder;
+ ASTContext &AST;
+ llvm::SmallVector<NamedDecl *> Params;
+
+ TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB)
+ : Builder(RB), AST(RB.Record->getASTContext()) {}
+
+ ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
+
+ TemplateParameterListBuilder &
+ addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
+ if (Builder.Record->isCompleteDefinition())
+ return *this;
+ unsigned Position = static_cast<unsigned>(Params.size());
+ auto *Decl = TemplateTypeParmDecl::Create(
+ AST, Builder.Record->getDeclContext(), SourceLocation(),
+ SourceLocation(), /* TemplateDepth */ 0, Position,
+ &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false,
+ /* ParameterPack */ false);
+ if (!DefaultValue.isNull())
+ Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue));
+
+ Params.emplace_back(Decl);
+ return *this;
+ }
+
+ BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
+ if (Params.empty())
+ return Builder;
+ auto *ParamList =
+ TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
+ Params, SourceLocation(), nullptr);
+ Builder.Template = ClassTemplateDecl::Create(
+ AST, Builder.Record->getDeclContext(), SourceLocation(),
+ DeclarationName(Builder.Record->getIdentifier()), ParamList,
+ Builder.Record);
+ Builder.Record->setDescribedClassTemplate(Builder.Template);
+ Builder.Template->setImplicit(true);
+ Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
+ // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
+ // make visible.
+ Builder.Template->setPreviousDecl(Builder.PrevTemplate);
+ Builder.Record->getDeclContext()->addDecl(Builder.Template);
+ Params.clear();
+
+ QualType T = Builder.Template->getInjectedClassNameSpecialization();
+ T = AST.getInjectedClassNameType(Builder.Record, T);
+
+ return Builder;
+ }
+};
+
+TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() {
+ return TemplateParameterListBuilder(*this);
+}
+} // namespace
HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
void HLSLExternalSemaSource::InitializeSema(Sema &S) {
SemaPtr = &S;
ASTContext &AST = SemaPtr->getASTContext();
+ // If the translation unit has external storage force external decls to load.
+ if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
+ (void)AST.getTranslationUnitDecl()->decls_begin();
+
IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
- HLSLNamespace =
- NamespaceDecl::Create(AST, AST.getTranslationUnitDecl(), false,
- SourceLocation(), SourceLocation(), &HLSL, nullptr);
+ LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
+ NamespaceDecl *PrevDecl = nullptr;
+ if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
+ PrevDecl = Result.getAsSingle<NamespaceDecl>();
+ HLSLNamespace = NamespaceDecl::Create(
+ AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
+ SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
HLSLNamespace->setImplicit(true);
+ HLSLNamespace->setHasExternalLexicalStorage();
AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
- defineHLSLVectorAlias();
+
+ // Force external decls in the HLSL namespace to load from the PCH.
+ (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
+ defineTrivialHLSLTypes();
+ forwardDeclareHLSLTypes();
// This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
// built in types inside a namespace, but we are planning to change that in
@@ -94,3 +461,53 @@ void HLSLExternalSemaSource::defineHLSLVectorAlias() {
Template->setLexicalDeclContext(Record->getDeclContext());
HLSLNamespace->addDecl(Template);
}
+
+void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
+ defineHLSLVectorAlias();
+
+ ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource")
+ .startDefinition()
+ .addHandleMember(AccessSpecifier::AS_public)
+ .completeDefinition()
+ .Record;
+}
+
+void HLSLExternalSemaSource::forwardDeclareHLSLTypes() {
+ CXXRecordDecl *Decl;
+ Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
+ .addTemplateArgumentList()
+ .addTypeParameter("element_type", SemaPtr->getASTContext().FloatTy)
+ .finalizeTemplateArgs()
+ .Record;
+ if (!Decl->isCompleteDefinition())
+ Completions.insert(
+ std::make_pair(Decl->getCanonicalDecl(),
+ std::bind(&HLSLExternalSemaSource::completeBufferType,
+ this, std::placeholders::_1)));
+}
+
+void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
+ if (!isa<CXXRecordDecl>(Tag))
+ return;
+ auto Record = cast<CXXRecordDecl>(Tag);
+
+ // If this is a specialization, we need to get the underlying templated
+ // declaration and complete that.
+ if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
+ Record = Record->getCanonicalDecl();
+ auto It = Completions.find(Record);
+ if (It == Completions.end())
+ return;
+ It->second(Record);
+}
+
+void HLSLExternalSemaSource::completeBufferType(CXXRecordDecl *Record) {
+ BuiltinTypeDeclBuilder(Record)
+ .addHandleMember()
+ .addDefaultHandleConstructor(*SemaPtr, ResourceClass::UAV)
+ .addArraySubscriptOperators()
+ .annotateResourceClass(HLSLResourceAttr::UAV,
+ HLSLResourceAttr::TypedBuffer)
+ .completeDefinition();
+}
diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp
index 9081714c893f..607dc3111e9d 100644
--- a/clang/lib/Sema/IdentifierResolver.cpp
+++ b/clang/lib/Sema/IdentifierResolver.cpp
@@ -99,7 +99,11 @@ IdentifierResolver::~IdentifierResolver() {
bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
bool AllowInlineNamespace) const {
Ctx = Ctx->getRedeclContext();
-
+ // The names for HLSL cbuffer/tbuffers only used by the CPU-side
+ // reflection API which supports querying bindings. It will not have name
+ // conflict with other Decls.
+ if (LangOpt.HLSL && isa<HLSLBufferDecl>(D))
+ return false;
if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) {
// Ignore the scopes associated within transparent declaration contexts.
while (S->getEntity() && S->getEntity()->isTransparentContext())
@@ -287,7 +291,7 @@ static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) {
// If the existing declaration is somewhere in the previous declaration
// chain of the new declaration, then prefer the new declaration.
- for (auto RD : New->redecls()) {
+ for (auto *RD : New->redecls()) {
if (RD == Existing)
return DMK_Replace;
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index 94f39e1eea6e..bd2ce9a93e7e 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -354,7 +354,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
BuildScopeInformation(Var, ParentScope);
++StmtsToSkip;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Stmt::GotoStmtClass:
// Remember both what scope a goto is in as well as the fact that we have
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 072775642d75..55e015487f3b 100644
--- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -16,24 +16,30 @@ using namespace clang;
char MultiplexExternalSemaSource::ID;
-///Constructs a new multiplexing external sema source and appends the
+/// Constructs a new multiplexing external sema source and appends the
/// given element to it.
///
-MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1,
- ExternalSemaSource &s2){
- Sources.push_back(&s1);
- Sources.push_back(&s2);
+MultiplexExternalSemaSource::MultiplexExternalSemaSource(
+ ExternalSemaSource *S1, ExternalSemaSource *S2) {
+ S1->Retain();
+ S2->Retain();
+ Sources.push_back(S1);
+ Sources.push_back(S2);
}
// pin the vtable here.
-MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {}
+MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {
+ for (auto *S : Sources)
+ S->Release();
+}
-///Appends new source to the source list.
+/// Appends new source to the source list.
///
///\param[in] source - An ExternalSemaSource.
///
-void MultiplexExternalSemaSource::addSource(ExternalSemaSource &source) {
- Sources.push_back(&source);
+void MultiplexExternalSemaSource::AddSource(ExternalSemaSource *Source) {
+ Source->Retain();
+ Sources.push_back(Source);
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td
index dc158454556a..0cceba090bd8 100644
--- a/clang/lib/Sema/OpenCLBuiltins.td
+++ b/clang/lib/Sema/OpenCLBuiltins.td
@@ -246,6 +246,7 @@ class ImageType<Type _Ty, string _AccessQualifier> :
let Extension = !cond(
!and(!eq(_Ty.Name, "image3d_t"), !eq(_AccessQualifier, "WO")) : TypeExtension<"cl_khr_3d_image_writes">,
!and(!eq(_Ty.Name, "image3d_t"), !eq(_AccessQualifier, "RW")) : TypeExtension<"cl_khr_3d_image_writes __opencl_c_read_write_images">,
+ !or(!eq(_Ty.Name, "image2d_depth_t"), !eq(_Ty.Name, "image2d_array_depth_t")) : TypeExtension<"cl_khr_depth_images">,
!eq(_AccessQualifier, "RW") : TypeExtension<"__opencl_c_read_write_images">,
true : _Ty.Extension);
}
diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp
index 4b9a694270c5..c1e39acb14ec 100644
--- a/clang/lib/Sema/ParsedAttr.cpp
+++ b/clang/lib/Sema/ParsedAttr.cpp
@@ -111,7 +111,7 @@ namespace {
const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
// If we have a ParsedAttrInfo for this ParsedAttr then return that.
- if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap))
+ if ((size_t)A.getParsedKind() < std::size(AttrInfoMap))
return *AttrInfoMap[A.getParsedKind()];
// If this is an ignored attribute then return an appropriate ParsedAttrInfo.
@@ -146,7 +146,7 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
}
ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() {
- return llvm::makeArrayRef(AttrInfoMap);
+ return llvm::ArrayRef(AttrInfoMap);
}
unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index 98260226dfd3..c995c7e65f4b 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -43,6 +43,9 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
0)
Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
+ // transmit the parent's 'order' flag, if exists
+ if (parent->getFlags() & OpenMPOrderClauseScope)
+ Flags |= OpenMPOrderClauseScope;
} else {
Depth = 0;
PrototypeDepth = 0;
@@ -91,7 +94,7 @@ void Scope::Init(Scope *parent, unsigned flags) {
UsingDirectives.clear();
Entity = nullptr;
ErrorTrap.reset();
- NRVO = None;
+ NRVO = std::nullopt;
}
bool Scope::containedInPrototypeScope() const {
@@ -156,11 +159,11 @@ void Scope::updateNRVOCandidate(VarDecl *VD) {
void Scope::applyNRVO() {
// There is no NRVO candidate in the current scope.
- if (!NRVO.hasValue())
+ if (!NRVO.has_value())
return;
if (*NRVO && isDeclScope(*NRVO))
- NRVO.getValue()->setNRVOVariable(true);
+ (*NRVO)->setNRVOVariable(true);
// It's necessary to propagate NRVO candidate to the parent scope for cases
// when the parent scope doesn't contain a return statement.
diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp
index cc7de16de2fd..e313052b3ab3 100644
--- a/clang/lib/Sema/ScopeInfo.cpp
+++ b/clang/lib/Sema/ScopeInfo.cpp
@@ -56,6 +56,7 @@ void FunctionScopeInfo::Clear() {
ModifiedNonNullParams.clear();
Blocks.clear();
ByrefBlockVars.clear();
+ AddrLabels.clear();
}
static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {
@@ -231,14 +232,14 @@ bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const {
}
void LambdaScopeInfo::visitPotentialCaptures(
- llvm::function_ref<void(VarDecl *, Expr *)> Callback) const {
+ llvm::function_ref<void(ValueDecl *, Expr *)> Callback) const {
for (Expr *E : PotentiallyCapturingExprs) {
if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
- Callback(cast<VarDecl>(DRE->getFoundDecl()), E);
+ Callback(cast<ValueDecl>(DRE->getFoundDecl()), E);
} else if (auto *ME = dyn_cast<MemberExpr>(E)) {
- Callback(cast<VarDecl>(ME->getMemberDecl()), E);
+ Callback(cast<ValueDecl>(ME->getMemberDecl()), E);
} else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) {
- for (VarDecl *VD : *FP)
+ for (ValueDecl *VD : *FP)
Callback(VD, E);
} else {
llvm_unreachable("unexpected expression in potential captures list");
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 08957ce9fada..0f0305422454 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -46,8 +46,10 @@
#include "clang/Sema/TemplateInstCallback.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/TimeProfiler.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -185,20 +187,19 @@ const uint64_t Sema::MaximumAlignment;
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter)
- : ExternalSource(nullptr), isMultiplexExternalSource(false),
- CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp),
- Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()),
- SourceMgr(PP.getSourceManager()), CollectStats(false),
- CodeCompleter(CodeCompleter), CurContext(nullptr),
+ : ExternalSource(nullptr), CurFPFeatures(pp.getLangOpts()),
+ LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
+ Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
+ CollectStats(false), CodeCompleter(CodeCompleter), CurContext(nullptr),
OriginalLexicalContext(nullptr), MSStructPragmaOn(false),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
VtorDispStack(LangOpts.getVtorDispMode()),
AlignPackStack(AlignPackInfo(getLangOpts().XLPragmaPack)),
DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
- CodeSegStack(nullptr), FpPragmaStack(FPOptionsOverride()),
- CurInitSeg(nullptr), VisContext(nullptr),
- PragmaAttributeCurrentTargetDecl(nullptr),
+ CodeSegStack(nullptr), StrictGuardStackCheckStack(false),
+ FpPragmaStack(FPOptionsOverride()), CurInitSeg(nullptr),
+ VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr),
IsBuildingRecoveryCallExpr(false), LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
@@ -473,10 +474,6 @@ Sema::~Sema() {
= dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
ExternalSema->ForgetSema();
- // If Sema's ExternalSource is the multiplexer - we own it.
- if (isMultiplexExternalSource)
- delete ExternalSource;
-
// Delete cached satisfactions.
std::vector<ConstraintSatisfaction *> Satisfactions;
Satisfactions.reserve(Satisfactions.size());
@@ -550,12 +547,10 @@ void Sema::addExternalSource(ExternalSemaSource *E) {
return;
}
- if (isMultiplexExternalSource)
- static_cast<MultiplexExternalSemaSource*>(ExternalSource)->addSource(*E);
- else {
- ExternalSource = new MultiplexExternalSemaSource(*ExternalSource, *E);
- isMultiplexExternalSource = true;
- }
+ if (auto *Ex = dyn_cast<MultiplexExternalSemaSource>(ExternalSource))
+ Ex->AddSource(E);
+ else
+ ExternalSource = new MultiplexExternalSemaSource(ExternalSource.get(), E);
}
/// Print out statistics about the semantic analysis.
@@ -570,22 +565,19 @@ void Sema::PrintStats() const {
void Sema::diagnoseNullableToNonnullConversion(QualType DstType,
QualType SrcType,
SourceLocation Loc) {
- Optional<NullabilityKind> ExprNullability = SrcType->getNullability(Context);
+ std::optional<NullabilityKind> ExprNullability = SrcType->getNullability();
if (!ExprNullability || (*ExprNullability != NullabilityKind::Nullable &&
*ExprNullability != NullabilityKind::NullableResult))
return;
- Optional<NullabilityKind> TypeNullability = DstType->getNullability(Context);
+ std::optional<NullabilityKind> TypeNullability = DstType->getNullability();
if (!TypeNullability || *TypeNullability != NullabilityKind::NonNull)
return;
Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType;
}
-void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
- if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant,
- E->getBeginLoc()))
- return;
+void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E) {
// nullptr only exists from C++11 on, so don't warn on its absence earlier.
if (!getLangOpts().CPlusPlus11)
return;
@@ -595,6 +587,10 @@ void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
if (E->IgnoreParenImpCasts()->getType()->isNullPtrType())
return;
+ if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant,
+ E->getBeginLoc()))
+ return;
+
// Don't diagnose the conversion from a 0 literal to a null pointer argument
// in a synthesized call to operator<=>.
if (!CodeSynthesisContexts.empty() &&
@@ -602,6 +598,12 @@ void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
CodeSynthesisContext::RewritingOperatorAsSpaceship)
return;
+ // Ignore null pointers in defaulted comparison operators.
+ FunctionDecl *FD = getCurFunctionDecl();
+ if (FD && FD->isDefaulted()) {
+ return;
+ }
+
// If it is a macro from system header, and if the macro name is not "NULL",
// do not warn.
SourceLocation MaybeMacroLoc = E->getBeginLoc();
@@ -1216,9 +1218,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// module declaration by now.
if (getLangOpts().getCompilingModule() ==
LangOptions::CMK_ModuleInterface &&
- (ModuleScopes.empty() ||
- !ModuleScopes.back().Module->isModulePurview()) &&
- !DiagnosedMissingModuleDeclaration) {
+ !isCurrentModulePurview() && !DiagnosedMissingModuleDeclaration) {
// FIXME: Make a better guess as to where to put the module declaration.
Diag(getSourceManager().getLocForStartOfFile(
getSourceManager().getMainFileID()),
@@ -1253,6 +1253,33 @@ void Sema::ActOnEndOfTranslationUnit() {
emitAndClearUnusedLocalTypedefWarnings();
}
+ // C++ standard modules. Diagnose cases where a function is declared inline
+ // in the module purview but has no definition before the end of the TU or
+ // the start of a Private Module Fragment (if one is present).
+ if (!PendingInlineFuncDecls.empty()) {
+ for (auto *D : PendingInlineFuncDecls) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ bool DefInPMF = false;
+ if (auto *FDD = FD->getDefinition()) {
+ assert(FDD->getOwningModule() &&
+ FDD->getOwningModule()->isModulePurview());
+ DefInPMF = FDD->getOwningModule()->isPrivateModule();
+ if (!DefInPMF)
+ continue;
+ }
+ Diag(FD->getLocation(), diag::err_export_inline_not_defined)
+ << DefInPMF;
+ // If we have a PMF it should be at the end of the ModuleScopes.
+ if (DefInPMF &&
+ ModuleScopes.back().Module->Kind == Module::PrivateModuleFragment) {
+ Diag(ModuleScopes.back().BeginLoc,
+ diag::note_private_module_fragment);
+ }
+ }
+ }
+ PendingInlineFuncDecls.clear();
+ }
+
// C99 6.9.2p2:
// A declaration of an identifier for an object that has file
// scope without an initializer, and without a storage-class
@@ -1266,8 +1293,8 @@ void Sema::ActOnEndOfTranslationUnit() {
// translation unit, with an initializer equal to 0.
llvm::SmallSet<VarDecl *, 32> Seen;
for (TentativeDefinitionsType::iterator
- T = TentativeDefinitions.begin(ExternalSource),
- TEnd = TentativeDefinitions.end();
+ T = TentativeDefinitions.begin(ExternalSource.get()),
+ TEnd = TentativeDefinitions.end();
T != TEnd; ++T) {
VarDecl *VD = (*T)->getActingDefinition();
@@ -1297,7 +1324,7 @@ void Sema::ActOnEndOfTranslationUnit() {
Consumer.CompleteTentativeDefinition(VD);
}
- for (auto D : ExternalDeclarations) {
+ for (auto *D : ExternalDeclarations) {
if (!D || D->isInvalidDecl() || D->getPreviousDecl() || !D->isUsed())
continue;
@@ -1311,8 +1338,9 @@ void Sema::ActOnEndOfTranslationUnit() {
if (!Diags.hasErrorOccurred() && TUKind != TU_Module) {
// Output warning for unused file scoped decls.
for (UnusedFileScopedDeclsType::iterator
- I = UnusedFileScopedDecls.begin(ExternalSource),
- E = UnusedFileScopedDecls.end(); I != E; ++I) {
+ I = UnusedFileScopedDecls.begin(ExternalSource.get()),
+ E = UnusedFileScopedDecls.end();
+ I != E; ++I) {
if (ShouldRemoveFromUnused(this, *I))
continue;
@@ -1470,7 +1498,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// eliminated. If it truly cannot be (for example, there is some reentrancy
// issue I am not seeing yet), then there should at least be a clarifying
// comment somewhere.
- if (Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
+ if (std::optional<TemplateDeductionInfo *> Info = isSFINAEContext()) {
switch (DiagnosticIDs::getDiagnosticSFINAEResponse(
Diags.getCurrentDiagID())) {
case DiagnosticIDs::SFINAE_Report:
@@ -1765,7 +1793,7 @@ void Sema::emitDeferredDiags() {
return;
DeferredDiagnosticsEmitter DDE(*this);
- for (auto D : DeclsToCheckForDeferredDiags)
+ for (auto *D : DeclsToCheckForDeferredDiags)
DDE.checkRecordedDecl(D);
}
@@ -2008,6 +2036,15 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
if (D)
targetDiag(D->getLocation(), diag::note_defined_here, FD) << D;
}
+
+ // Don't allow SVE types in functions without a SVE target.
+ if (Ty->isSVESizelessBuiltinType() && FD && FD->hasBody()) {
+ llvm::StringMap<bool> CallerFeatureMap;
+ Context.getFunctionFeatureMap(CallerFeatureMap, FD);
+ if (!Builtin::evaluateRequiredTargetFeatures(
+ "sve", CallerFeatureMap))
+ Diag(D->getLocation(), diag::err_sve_vector_in_non_sve_target) << Ty;
+ }
};
CheckType(Ty);
@@ -2448,7 +2485,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
if (IsMemExpr && !E.isTypeDependent()) {
Sema::TentativeAnalysisScope Trap(*this);
ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(),
- None, SourceLocation());
+ std::nullopt, SourceLocation());
if (R.isUsable()) {
ZeroArgCallReturnTy = R.get()->getType();
return true;
@@ -2512,6 +2549,9 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads,
if (FD->isMultiVersion() && FD->hasAttr<TargetAttr>() &&
!FD->getAttr<TargetAttr>()->isDefaultVersion())
continue;
+ if (FD->isMultiVersion() && FD->hasAttr<TargetVersionAttr>() &&
+ !FD->getAttr<TargetVersionAttr>()->isDefaultVersion())
+ continue;
}
S.Diag(Fn->getLocation(), diag::note_possible_target_of_call);
++ShownOverloads;
@@ -2598,7 +2638,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
// FIXME: Try this before emitting the fixit, and suppress diagnostics
// while doing so.
- E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), None,
+ E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), std::nullopt,
Range.getEnd().getLocWithOffset(1));
return true;
}
@@ -2659,3 +2699,26 @@ Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() {
S.FpPragmaStack.CurrentValue = OldOverrides;
S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod);
}
+
+bool Sema::isDeclaratorFunctionLike(Declarator &D) {
+ assert(D.getCXXScopeSpec().isSet() &&
+ "can only be called for qualified names");
+
+ auto LR = LookupResult(*this, D.getIdentifier(), D.getBeginLoc(),
+ LookupOrdinaryName, forRedeclarationInCurContext());
+ DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(),
+ !D.getDeclSpec().isFriendSpecified());
+ if (!DC)
+ return false;
+
+ LookupQualifiedName(LR, DC);
+ bool Result = std::all_of(LR.begin(), LR.end(), [](Decl *Dcl) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(Dcl)) {
+ ND = ND->getUnderlyingDecl();
+ return isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
+ isa<UsingDecl>(ND);
+ }
+ return false;
+ });
+ return Result;
+}
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 00d3efd19d7a..cbda62497e6a 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -1493,6 +1493,8 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) {
} else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) {
if (isa<DeclContext>(TD->getTemplatedDecl()))
DC = cast<DeclContext>(TD->getTemplatedDecl());
+ } else if (auto *RD = dyn_cast<RequiresExprBodyDecl>(D)) {
+ DC = RD;
}
EffectiveContext EC(DC);
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index c997d018a406..42f582724564 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -18,6 +18,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/SemaInternal.h"
+#include <optional>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -34,6 +35,7 @@ Sema::PragmaStackSentinelRAII::PragmaStackSentinelRAII(Sema &S,
S.BSSSegStack.SentinelAction(PSK_Push, SlotLabel);
S.ConstSegStack.SentinelAction(PSK_Push, SlotLabel);
S.CodeSegStack.SentinelAction(PSK_Push, SlotLabel);
+ S.StrictGuardStackCheckStack.SentinelAction(PSK_Push, SlotLabel);
}
}
@@ -44,6 +46,7 @@ Sema::PragmaStackSentinelRAII::~PragmaStackSentinelRAII() {
S.BSSSegStack.SentinelAction(PSK_Pop, SlotLabel);
S.ConstSegStack.SentinelAction(PSK_Pop, SlotLabel);
S.CodeSegStack.SentinelAction(PSK_Pop, SlotLabel);
+ S.StrictGuardStackCheckStack.SentinelAction(PSK_Pop, SlotLabel);
}
}
@@ -335,7 +338,7 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
AlignPackInfo::Mode ModeVal = CurVal.getAlignMode();
if (Alignment) {
- Optional<llvm::APSInt> Val;
+ std::optional<llvm::APSInt> Val;
Val = Alignment->getIntegerConstantExpr(Context);
// pack(0) is like pack(), which just works out since that is what
@@ -774,6 +777,17 @@ void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation,
Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName);
}
+/// Called on well formed \#pragma strict_gs_check().
+void Sema::ActOnPragmaMSStrictGuardStackCheck(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ bool Value) {
+ if (Action & PSK_Pop && StrictGuardStackCheckStack.Stack.empty())
+ Diag(PragmaLocation, diag::warn_pragma_pop_failed) << "strict_gs_check"
+ << "stack empty";
+
+ StrictGuardStackCheckStack.Act(PragmaLocation, Action, StringRef(), Value);
+}
+
/// Called on well formed \#pragma bss_seg().
void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation,
int SectionFlags, StringLiteral *SegmentName) {
@@ -872,12 +886,12 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
namespace {
-Optional<attr::SubjectMatchRule>
+std::optional<attr::SubjectMatchRule>
getParentAttrMatcherRule(attr::SubjectMatchRule Rule) {
using namespace attr;
switch (Rule) {
default:
- return None;
+ return std::nullopt;
#define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)
#define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \
case Value: \
@@ -947,7 +961,7 @@ void Sema::ActOnPragmaAttributeAttribute(
RulesToFirstSpecifiedNegatedSubRule;
for (const auto &Rule : Rules) {
attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
- Optional<attr::SubjectMatchRule> ParentRule =
+ std::optional<attr::SubjectMatchRule> ParentRule =
getParentAttrMatcherRule(MatchRule);
if (!ParentRule)
continue;
@@ -971,7 +985,7 @@ void Sema::ActOnPragmaAttributeAttribute(
bool IgnoreNegatedSubRules = false;
for (const auto &Rule : Rules) {
attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first);
- Optional<attr::SubjectMatchRule> ParentRule =
+ std::optional<attr::SubjectMatchRule> ParentRule =
getParentAttrMatcherRule(MatchRule);
if (!ParentRule)
continue;
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index bf4a226668f7..05ad42780e50 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -19,6 +19,7 @@
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -192,6 +193,9 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
case llvm::Triple::MacOSX:
ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
break;
+ case llvm::Triple::ShaderModel:
+ // Always enable availability diagnostics for shader models.
+ return true;
default:
// New targets should always warn about availability.
return Triple.getVendor() == llvm::Triple::Apple;
@@ -241,16 +245,16 @@ struct AttributeInsertion {
/// attribute argument.
/// \param SlotNames The vector that will be populated with slot names. In case
/// of unsuccessful parsing can contain invalid data.
-/// \returns A number of method parameters if parsing was successful, None
-/// otherwise.
-static Optional<unsigned>
+/// \returns A number of method parameters if parsing was successful,
+/// std::nullopt otherwise.
+static std::optional<unsigned>
tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
const LangOptions &LangOpts) {
// Accept replacements starting with - or + as valid ObjC method names.
if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
Name = Name.drop_front(1);
if (Name.empty())
- return None;
+ return std::nullopt;
Name.split(SlotNames, ':');
unsigned NumParams;
if (Name.back() == ':') {
@@ -260,7 +264,7 @@ tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
} else {
if (SlotNames.size() != 1)
// Not a valid method name, just a colon-separated string.
- return None;
+ return std::nullopt;
NumParams = 0;
}
// Verify all slot names are valid.
@@ -269,28 +273,28 @@ tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
if (S.empty())
continue;
if (!isValidAsciiIdentifier(S, AllowDollar))
- return None;
+ return std::nullopt;
}
return NumParams;
}
/// Returns a source location in which it's appropriate to insert a new
/// attribute for the given declaration \D.
-static Optional<AttributeInsertion>
+static std::optional<AttributeInsertion>
createAttributeInsertion(const NamedDecl *D, const SourceManager &SM,
const LangOptions &LangOpts) {
if (isa<ObjCPropertyDecl>(D))
return AttributeInsertion::createInsertionAfter(D);
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (MD->hasBody())
- return None;
+ return std::nullopt;
return AttributeInsertion::createInsertionAfter(D);
}
if (const auto *TD = dyn_cast<TagDecl>(D)) {
SourceLocation Loc =
Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
if (Loc.isInvalid())
- return None;
+ return std::nullopt;
// Insert after the 'struct'/whatever keyword.
return AttributeInsertion::createInsertionAfter(Loc);
}
@@ -397,7 +401,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
return;
if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
return;
- Optional<AttributeInsertion> Insertion = createAttributeInsertion(
+ std::optional<AttributeInsertion> Insertion = createAttributeInsertion(
Enclosing, S.getSourceManager(), S.getLangOpts());
if (!Insertion)
return;
@@ -499,7 +503,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
Selector Sel = MethodDecl->getSelector();
SmallVector<StringRef, 12> SelectorSlotNames;
- Optional<unsigned> NumParams = tryParseObjCMethodName(
+ std::optional<unsigned> NumParams = tryParseObjCMethodName(
Replacement, SelectorSlotNames, S.getLangOpts());
if (NumParams && *NumParams == Sel.getNumArgs()) {
assert(SelectorSlotNames.size() == Locs.size());
@@ -895,6 +899,11 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
return;
Body = FD->getBody();
+
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
+ for (const CXXCtorInitializer *CI : CD->inits())
+ DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit());
+
} else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
Body = MD->getBody();
else if (auto *BD = dyn_cast<BlockDecl>(D))
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 0a49d72ba963..cfea6493ced7 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -22,8 +22,8 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
template <typename AttrT> static bool hasExplicitAttr(const VarDecl *D) {
@@ -338,7 +338,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
if (!InClass || HasExplicitAttr)
return false;
- llvm::Optional<CUDAFunctionTarget> InferredTarget;
+ std::optional<CUDAFunctionTarget> InferredTarget;
// We're going to invoke special member lookup; mark that these special
// members are called from this one, and not from its caller.
@@ -381,13 +381,12 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
InferredTarget = BaseMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
- InferredTarget.value(), BaseMethodTarget,
- InferredTarget.getPointer());
+ *InferredTarget, BaseMethodTarget, &*InferredTarget);
if (ResolutionError) {
if (Diagnose) {
Diag(ClassDecl->getLocation(),
diag::note_implicit_member_target_infer_collision)
- << (unsigned)CSM << InferredTarget.value() << BaseMethodTarget;
+ << (unsigned)CSM << *InferredTarget << BaseMethodTarget;
}
MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
return true;
@@ -425,13 +424,12 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
InferredTarget = FieldMethodTarget;
} else {
bool ResolutionError = resolveCalleeCUDATargetConflict(
- InferredTarget.value(), FieldMethodTarget,
- InferredTarget.getPointer());
+ *InferredTarget, FieldMethodTarget, &*InferredTarget);
if (ResolutionError) {
if (Diagnose) {
Diag(ClassDecl->getLocation(),
diag::note_implicit_member_target_infer_collision)
- << (unsigned)CSM << InferredTarget.value() << FieldMethodTarget;
+ << (unsigned)CSM << *InferredTarget << FieldMethodTarget;
}
MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
return true;
@@ -444,9 +442,9 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
// it's the least restrictive option that can be invoked from any target.
bool NeedsH = true, NeedsD = true;
if (InferredTarget) {
- if (InferredTarget.value() == CFT_Device)
+ if (*InferredTarget == CFT_Device)
NeedsH = false;
- else if (InferredTarget.value() == CFT_Host)
+ else if (*InferredTarget == CFT_Host)
NeedsD = false;
}
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 3f8fedda7174..daa61ba45e8e 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -931,10 +931,9 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
// Handle a dependent template specialization for which we cannot resolve
// the template name.
assert(DTN->getQualifier() == SS.getScopeRep());
- QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ QualType T = Context.getDependentTemplateSpecializationType(
+ ETK_None, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Create source-location information for this type.
TypeLocBuilder Builder;
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 7b5bc7ca80b1..9fd9369c9641 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -451,6 +451,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
case InitializationSequence::FK_ConstructorOverloadFailed:
case InitializationSequence::FK_UserConversionOverloadFailed:
+ case InitializationSequence::FK_ParenthesizedListInitFailed:
break;
}
@@ -1059,11 +1060,19 @@ static bool argTypeIsABIEquivalent(QualType SrcType, QualType DestType,
return Context.hasSameUnqualifiedType(SrcType, DestType);
}
-static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
- QualType DestType) {
- if (Self.Diags.isIgnored(diag::warn_cast_function_type,
- SrcExpr.get()->getExprLoc()))
- return true;
+static unsigned int checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
+ QualType DestType) {
+ unsigned int DiagID = 0;
+ const unsigned int DiagList[] = {diag::warn_cast_function_type_strict,
+ diag::warn_cast_function_type};
+ for (auto ID : DiagList) {
+ if (!Self.Diags.isIgnored(ID, SrcExpr.get()->getExprLoc())) {
+ DiagID = ID;
+ break;
+ }
+ }
+ if (!DiagID)
+ return 0;
QualType SrcType = SrcExpr.get()->getType();
const FunctionType *SrcFTy = nullptr;
@@ -1078,10 +1087,17 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
SrcFTy = SrcType->castAs<FunctionType>();
DstFTy = DestType.getNonReferenceType()->castAs<FunctionType>();
} else {
- return true;
+ return 0;
}
assert(SrcFTy && DstFTy);
+ if (Self.Context.hasSameType(SrcFTy, DstFTy))
+ return 0;
+
+ // For strict checks, ensure we have an exact match.
+ if (DiagID == diag::warn_cast_function_type_strict)
+ return DiagID;
+
auto IsVoidVoid = [](const FunctionType *T) {
if (!T->getReturnType()->isVoidType())
return false;
@@ -1092,16 +1108,16 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
// Skip if either function type is void(*)(void)
if (IsVoidVoid(SrcFTy) || IsVoidVoid(DstFTy))
- return true;
+ return 0;
// Check return type.
if (!argTypeIsABIEquivalent(SrcFTy->getReturnType(), DstFTy->getReturnType(),
Self.Context))
- return false;
+ return DiagID;
// Check if either has unspecified number of parameters
if (SrcFTy->isFunctionNoProtoType() || DstFTy->isFunctionNoProtoType())
- return true;
+ return 0;
// Check parameter types.
@@ -1114,19 +1130,19 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr,
unsigned DstNumParams = DstFPTy->getNumParams();
if (NumParams > DstNumParams) {
if (!DstFPTy->isVariadic())
- return false;
+ return DiagID;
NumParams = DstNumParams;
} else if (NumParams < DstNumParams) {
if (!SrcFPTy->isVariadic())
- return false;
+ return DiagID;
}
for (unsigned i = 0; i < NumParams; ++i)
if (!argTypeIsABIEquivalent(SrcFPTy->getParamType(i),
DstFPTy->getParamType(i), Self.Context))
- return false;
+ return DiagID;
- return true;
+ return 0;
}
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
@@ -1167,8 +1183,8 @@ void CastOperation::CheckReinterpretCast() {
checkObjCConversion(Sema::CCK_OtherCast);
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
- if (!checkCastFunctionType(Self, SrcExpr, DestType))
- Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
+ if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), DiagID)
<< SrcExpr.get()->getType() << DestType << OpRange;
} else {
SrcExpr = ExprError();
@@ -2797,8 +2813,8 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
if (Kind == CK_BitCast)
checkCastAlign();
- if (!checkCastFunctionType(Self, SrcExpr, DestType))
- Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
+ if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), DiagID)
<< SrcExpr.get()->getType() << DestType << OpRange;
} else {
@@ -2985,6 +3001,37 @@ void CastOperation::CheckCStyleCast() {
return;
}
+ // C2x 6.5.4p4:
+ // The type nullptr_t shall not be converted to any type other than void,
+ // bool, or a pointer type. No type other than nullptr_t shall be converted
+ // to nullptr_t.
+ if (SrcType->isNullPtrType()) {
+ // FIXME: 6.3.2.4p2 says that nullptr_t can be converted to itself, but
+ // 6.5.4p4 is a constraint check and nullptr_t is not void, bool, or a
+ // pointer type. We're not going to diagnose that as a constraint violation.
+ if (!DestType->isVoidType() && !DestType->isBooleanType() &&
+ !DestType->isPointerType() && !DestType->isNullPtrType()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_nullptr_cast)
+ << /*nullptr to type*/ 0 << DestType;
+ SrcExpr = ExprError();
+ return;
+ }
+ if (!DestType->isNullPtrType()) {
+ // Implicitly cast from the null pointer type to the type of the
+ // destination.
+ CastKind CK = DestType->isPointerType() ? CK_NullToPointer : CK_BitCast;
+ SrcExpr = ImplicitCastExpr::Create(Self.Context, DestType, CK,
+ SrcExpr.get(), nullptr, VK_PRValue,
+ Self.CurFPFeatureOverrides());
+ }
+ }
+ if (DestType->isNullPtrType() && !SrcType->isNullPtrType()) {
+ Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_nullptr_cast)
+ << /*type to nullptr*/ 1 << SrcType;
+ SrcExpr = ExprError();
+ return;
+ }
+
if (DestType->isExtVectorType()) {
SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.get(), Kind);
return;
@@ -3125,9 +3172,8 @@ void CastOperation::CheckCStyleCast() {
}
}
- if (!checkCastFunctionType(Self, SrcExpr, DestType))
- Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type)
- << SrcType << DestType << OpRange;
+ if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType))
+ Self.Diag(OpRange.getBegin(), DiagID) << SrcType << DestType << OpRange;
if (isa<PointerType>(SrcType) && isa<PointerType>(DestType)) {
QualType SrcTy = cast<PointerType>(SrcType)->getPointeeType();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dae51d0690e6..ea21171aaac6 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -67,8 +67,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -96,6 +94,7 @@
#include <cstdint>
#include <functional>
#include <limits>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -128,6 +127,28 @@ static bool checkArgCountAtLeast(Sema &S, CallExpr *Call,
<< Call->getSourceRange();
}
+/// Checks that a call expression's argument count is at most the desired
+/// number. This is useful when doing custom type-checking on a variadic
+/// function. Returns true on error.
+static bool checkArgCountAtMost(Sema &S, CallExpr *Call, unsigned MaxArgCount) {
+ unsigned ArgCount = Call->getNumArgs();
+ if (ArgCount <= MaxArgCount)
+ return false;
+ return S.Diag(Call->getEndLoc(),
+ diag::err_typecheck_call_too_many_args_at_most)
+ << 0 /*function call*/ << MaxArgCount << ArgCount
+ << Call->getSourceRange();
+}
+
+/// Checks that a call expression's argument count is in the desired range. This
+/// is useful when doing custom type-checking on a variadic function. Returns
+/// true on error.
+static bool checkArgCountRange(Sema &S, CallExpr *Call, unsigned MinArgCount,
+ unsigned MaxArgCount) {
+ return checkArgCountAtLeast(S, Call, MinArgCount) ||
+ checkArgCountAtMost(S, Call, MaxArgCount);
+}
+
/// Checks that a call expression's argument count is the desired number.
/// This is useful when doing custom type-checking. Returns true on error.
static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) {
@@ -148,6 +169,20 @@ static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) {
<< Call->getArg(1)->getSourceRange();
}
+static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) {
+ if (Value->isTypeDependent())
+ return false;
+
+ InitializedEntity Entity =
+ InitializedEntity::InitializeParameter(S.Context, Ty, false);
+ ExprResult Result =
+ S.PerformCopyInitialization(Entity, SourceLocation(), Value);
+ if (Result.isInvalid())
+ return true;
+ Value = Result.get();
+ return false;
+}
+
/// Check that the first argument to __builtin_annotation is an integer
/// and the second argument is a non-wide string literal.
static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
@@ -760,7 +795,7 @@ class ScanfDiagnosticFormatHandler
// Accepts the argument index (relative to the first destination index) of the
// argument whose size we want.
using ComputeSizeFunction =
- llvm::function_ref<Optional<llvm::APSInt>(unsigned)>;
+ llvm::function_ref<std::optional<llvm::APSInt>(unsigned)>;
// Accepts the argument index (relative to the first destination index), the
// destination size, and the source size).
@@ -800,7 +835,8 @@ public:
unsigned SourceSize = FW.getConstantAmount() + NulByte;
- Optional<llvm::APSInt> DestSizeAPS = ComputeSizeArgument(FS.getArgIndex());
+ std::optional<llvm::APSInt> DestSizeAPS =
+ ComputeSizeArgument(FS.getArgIndex());
if (!DestSizeAPS)
return true;
@@ -1018,7 +1054,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
const TargetInfo &TI = getASTContext().getTargetInfo();
unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType());
- auto TranslateIndex = [&](unsigned Index) -> Optional<unsigned> {
+ auto TranslateIndex = [&](unsigned Index) -> std::optional<unsigned> {
// If we refer to a diagnose_as_builtin attribute, we need to change the
// argument index to refer to the arguments of the called function. Unless
// the index is out of bounds, which presumably means it's a variadic
@@ -1030,26 +1066,27 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
? DABAttr->argIndices_begin()[Index]
: Index - DABIndices + FD->getNumParams();
if (NewIndex >= TheCall->getNumArgs())
- return llvm::None;
+ return std::nullopt;
return NewIndex;
};
auto ComputeExplicitObjectSizeArgument =
- [&](unsigned Index) -> Optional<llvm::APSInt> {
- Optional<unsigned> IndexOptional = TranslateIndex(Index);
+ [&](unsigned Index) -> std::optional<llvm::APSInt> {
+ std::optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
- return llvm::None;
+ return std::nullopt;
unsigned NewIndex = *IndexOptional;
Expr::EvalResult Result;
Expr *SizeArg = TheCall->getArg(NewIndex);
if (!SizeArg->EvaluateAsInt(Result, getASTContext()))
- return llvm::None;
+ return std::nullopt;
llvm::APSInt Integer = Result.Val.getInt();
Integer.setIsUnsigned(true);
return Integer;
};
- auto ComputeSizeArgument = [&](unsigned Index) -> Optional<llvm::APSInt> {
+ auto ComputeSizeArgument =
+ [&](unsigned Index) -> std::optional<llvm::APSInt> {
// If the parameter has a pass_object_size attribute, then we should use its
// (potentially) more strict checking mode. Otherwise, conservatively assume
// type 0.
@@ -1061,36 +1098,40 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
BOSType = POS->getType();
}
- Optional<unsigned> IndexOptional = TranslateIndex(Index);
+ std::optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
- return llvm::None;
+ return std::nullopt;
unsigned NewIndex = *IndexOptional;
+ if (NewIndex >= TheCall->getNumArgs())
+ return std::nullopt;
+
const Expr *ObjArg = TheCall->getArg(NewIndex);
uint64_t Result;
if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType))
- return llvm::None;
+ return std::nullopt;
// Get the object size in the target's size_t width.
return llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth);
};
- auto ComputeStrLenArgument = [&](unsigned Index) -> Optional<llvm::APSInt> {
- Optional<unsigned> IndexOptional = TranslateIndex(Index);
+ auto ComputeStrLenArgument =
+ [&](unsigned Index) -> std::optional<llvm::APSInt> {
+ std::optional<unsigned> IndexOptional = TranslateIndex(Index);
if (!IndexOptional)
- return llvm::None;
+ return std::nullopt;
unsigned NewIndex = *IndexOptional;
const Expr *ObjArg = TheCall->getArg(NewIndex);
uint64_t Result;
if (!ObjArg->tryEvaluateStrLen(Result, getASTContext()))
- return llvm::None;
+ return std::nullopt;
// Add 1 for null byte.
return llvm::APSInt::getUnsigned(Result + 1).extOrTrunc(SizeTypeWidth);
};
- Optional<llvm::APSInt> SourceSize;
- Optional<llvm::APSInt> DestinationSize;
+ std::optional<llvm::APSInt> SourceSize;
+ std::optional<llvm::APSInt> DestinationSize;
unsigned DiagID = 0;
bool IsChkVariant = false;
@@ -1869,18 +1910,18 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) {
TheCall->setType(ParamTy);
- auto DiagSelect = [&]() -> llvm::Optional<unsigned> {
+ auto DiagSelect = [&]() -> std::optional<unsigned> {
if (!ParamTy->isPointerType())
return 0;
if (ParamTy->isFunctionPointerType())
return 1;
if (ParamTy->isVoidPointerType())
return 2;
- return llvm::Optional<unsigned>{};
+ return std::optional<unsigned>{};
}();
if (DiagSelect) {
S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg)
- << DiagSelect.value() << TheCall->getSourceRange();
+ << *DiagSelect << TheCall->getSourceRange();
return ExprError();
}
@@ -1981,7 +2022,37 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
return CheckRISCVBuiltinFunctionCall(TI, BuiltinID, TheCall);
+ case llvm::Triple::loongarch32:
+ case llvm::Triple::loongarch64:
+ return CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, TheCall);
+ }
+}
+
+// Check if \p Ty is a valid type for the elementwise math builtins. If it is
+// not a valid type, emit an error message and return true. Otherwise return
+// false.
+static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
+ QualType Ty) {
+ if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) {
+ return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+ << 1 << /* vector, integer or float ty*/ 0 << Ty;
+ }
+
+ return false;
+}
+
+static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc,
+ QualType ArgTy, int ArgIndex) {
+ QualType EltTy = ArgTy;
+ if (auto *VecTy = EltTy->getAs<VectorType>())
+ EltTy = VecTy->getElementType();
+
+ if (!EltTy->isRealFloatingType()) {
+ return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+ << ArgIndex << /* vector or float ty*/ 5 << ArgTy;
}
+
+ return false;
}
ExprResult
@@ -2108,7 +2179,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_alloca_with_align_uninitialized:
if (SemaBuiltinAllocaWithAlign(TheCall))
return ExprError();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_alloca:
case Builtin::BI__builtin_alloca_uninitialized:
Diag(TheCall->getBeginLoc(), diag::warn_alloca)
@@ -2485,7 +2556,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
break;
case Builtin::BI__builtin_os_log_format:
Cleanup.setExprNeedsCleanups(true);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_os_log_format_buffer_size:
if (SemaBuiltinOSLogFormat(TheCall))
return ExprError();
@@ -2532,9 +2603,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
// These builtins restrict the element type to floating point
// types only.
case Builtin::BI__builtin_elementwise_ceil:
+ case Builtin::BI__builtin_elementwise_cos:
case Builtin::BI__builtin_elementwise_floor:
case Builtin::BI__builtin_elementwise_roundeven:
- case Builtin::BI__builtin_elementwise_trunc: {
+ case Builtin::BI__builtin_elementwise_sin:
+ case Builtin::BI__builtin_elementwise_trunc:
+ case Builtin::BI__builtin_elementwise_canonicalize: {
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
return ExprError();
@@ -2580,6 +2654,35 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (SemaBuiltinElementwiseMath(TheCall))
return ExprError();
break;
+ case Builtin::BI__builtin_elementwise_copysign: {
+ if (checkArgCount(*this, TheCall, 2))
+ return ExprError();
+
+ ExprResult Magnitude = UsualUnaryConversions(TheCall->getArg(0));
+ ExprResult Sign = UsualUnaryConversions(TheCall->getArg(1));
+ if (Magnitude.isInvalid() || Sign.isInvalid())
+ return ExprError();
+
+ QualType MagnitudeTy = Magnitude.get()->getType();
+ QualType SignTy = Sign.get()->getType();
+ if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(),
+ MagnitudeTy, 1) ||
+ checkFPMathBuiltinElementType(*this, TheCall->getArg(1)->getBeginLoc(),
+ SignTy, 2)) {
+ return ExprError();
+ }
+
+ if (MagnitudeTy.getCanonicalType() != SignTy.getCanonicalType()) {
+ return Diag(Sign.get()->getBeginLoc(),
+ diag::err_typecheck_call_different_arg_types)
+ << MagnitudeTy << SignTy;
+ }
+
+ TheCall->setArg(0, Magnitude.get());
+ TheCall->setArg(1, Sign.get());
+ TheCall->setType(Magnitude.get()->getType());
+ break;
+ }
case Builtin::BI__builtin_reduce_max:
case Builtin::BI__builtin_reduce_min: {
if (PrepareBuiltinReduceMathOneArgCall(TheCall))
@@ -3183,13 +3286,15 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
if (BuiltinID == AArch64::BI__builtin_arm_prefetch) {
return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) ||
- SemaBuiltinConstantArgRange(TheCall, 2, 0, 2) ||
- SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) ||
- SemaBuiltinConstantArgRange(TheCall, 4, 0, 1);
+ SemaBuiltinConstantArgRange(TheCall, 2, 0, 3) ||
+ SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) ||
+ SemaBuiltinConstantArgRange(TheCall, 4, 0, 1);
}
if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
- BuiltinID == AArch64::BI__builtin_arm_wsr64)
+ BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
+ BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128)
return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
// Memory Tagging Extensions (MTE) Intrinsics
@@ -3338,7 +3443,7 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
// The second argument needs to be a constant int
Expr *Arg = TheCall->getArg(1);
- Optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context);
diag::kind kind;
if (!Value) {
if (BuiltinID == BPF::BI__builtin_preserve_field_info)
@@ -3585,6 +3690,31 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) {
{ Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} },
{ Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B,
{{ 3, false, 1, 0 }} },
+
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10, {{ 2, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_128B,
+ {{ 2, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx,
+ {{ 3, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx_128B,
+ {{ 3, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10, {{ 2, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_128B,
+ {{ 2, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx,
+ {{ 3, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx_128B,
+ {{ 3, false, 2, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {{ 2, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {{ 2, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {{ 3, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B,
+ {{ 3, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {{ 2, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {{ 2, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {{ 3, false, 3, 0 }} },
+ { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B,
+ {{ 3, false, 3, 0 }} },
};
// Use a dynamically initialized static to sort the table exactly once on
@@ -3629,6 +3759,91 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID,
return CheckHexagonBuiltinArgument(BuiltinID, TheCall);
}
+bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
+ unsigned BuiltinID,
+ CallExpr *TheCall) {
+ switch (BuiltinID) {
+ default:
+ break;
+ case LoongArch::BI__builtin_loongarch_cacop_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ LLVM_FALLTHROUGH;
+ case LoongArch::BI__builtin_loongarch_cacop_w: {
+ if (BuiltinID == LoongArch::BI__builtin_loongarch_cacop_w &&
+ !TI.hasFeature("32bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la32)
+ << TheCall->getSourceRange();
+ SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5));
+ SemaBuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12),
+ llvm::maxIntN(12));
+ break;
+ }
+ case LoongArch::BI__builtin_loongarch_crc_w_b_w:
+ case LoongArch::BI__builtin_loongarch_crc_w_h_w:
+ case LoongArch::BI__builtin_loongarch_crc_w_w_w:
+ case LoongArch::BI__builtin_loongarch_crc_w_d_w:
+ case LoongArch::BI__builtin_loongarch_crcc_w_b_w:
+ case LoongArch::BI__builtin_loongarch_crcc_w_h_w:
+ case LoongArch::BI__builtin_loongarch_crcc_w_w_w:
+ case LoongArch::BI__builtin_loongarch_crcc_w_d_w:
+ case LoongArch::BI__builtin_loongarch_iocsrrd_d:
+ case LoongArch::BI__builtin_loongarch_iocsrwr_d:
+ case LoongArch::BI__builtin_loongarch_asrtle_d:
+ case LoongArch::BI__builtin_loongarch_asrtgt_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ break;
+ case LoongArch::BI__builtin_loongarch_break:
+ case LoongArch::BI__builtin_loongarch_dbar:
+ case LoongArch::BI__builtin_loongarch_ibar:
+ case LoongArch::BI__builtin_loongarch_syscall:
+ // Check if immediate is in [0, 32767].
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 32767);
+ case LoongArch::BI__builtin_loongarch_csrrd_w:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrwr_w:
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrxchg_w:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrrd_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrwr_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_csrxchg_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383);
+ case LoongArch::BI__builtin_loongarch_lddir_d:
+ case LoongArch::BI__builtin_loongarch_ldpte_d:
+ if (!TI.hasFeature("64bit"))
+ return Diag(TheCall->getBeginLoc(),
+ diag::err_loongarch_builtin_requires_la64)
+ << TheCall->getSourceRange();
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31);
+ case LoongArch::BI__builtin_loongarch_movfcsr2gr:
+ case LoongArch::BI__builtin_loongarch_movgr2fcsr:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2));
+ }
+
+ return false;
+}
+
bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID, CallExpr *TheCall) {
return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) ||
@@ -4039,7 +4254,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case PPC::BI__builtin_unpack_longdouble:
if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 1))
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case PPC::BI__builtin_pack_longdouble:
if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble())
return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi)
@@ -4172,10 +4387,11 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
diag::err_ppc_builtin_requires_vsx);
case PPC::BI__builtin_ppc_test_data_class: {
// Check if the first argument of the __builtin_ppc_test_data_class call is
- // valid. The argument must be either a 'float' or a 'double'.
+ // valid. The argument must be 'float' or 'double' or '__float128'.
QualType ArgType = TheCall->getArg(0)->getType();
if (ArgType != QualType(Context.FloatTy) &&
- ArgType != QualType(Context.DoubleTy))
+ ArgType != QualType(Context.DoubleTy) &&
+ ArgType != QualType(Context.Float128Ty))
return Diag(TheCall->getBeginLoc(),
diag::err_ppc_invalid_test_data_class_type);
return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions",
@@ -4321,27 +4537,6 @@ bool Sema::CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum) {
<< Arg->getSourceRange();
}
-static bool isRISCV32Builtin(unsigned BuiltinID) {
- // These builtins only work on riscv32 targets.
- switch (BuiltinID) {
- case RISCV::BI__builtin_riscv_zip_32:
- case RISCV::BI__builtin_riscv_unzip_32:
- case RISCV::BI__builtin_riscv_aes32dsi_32:
- case RISCV::BI__builtin_riscv_aes32dsmi_32:
- case RISCV::BI__builtin_riscv_aes32esi_32:
- case RISCV::BI__builtin_riscv_aes32esmi_32:
- case RISCV::BI__builtin_riscv_sha512sig0h_32:
- case RISCV::BI__builtin_riscv_sha512sig0l_32:
- case RISCV::BI__builtin_riscv_sha512sig1h_32:
- case RISCV::BI__builtin_riscv_sha512sig1l_32:
- case RISCV::BI__builtin_riscv_sha512sum0r_32:
- case RISCV::BI__builtin_riscv_sha512sum1r_32:
- return true;
- }
-
- return false;
-}
-
bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
unsigned BuiltinID,
CallExpr *TheCall) {
@@ -4352,31 +4547,28 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID);
Features.split(ReqFeatures, ',');
- // Check for 32-bit only builtins on a 64-bit target.
- const llvm::Triple &TT = TI.getTriple();
- if (TT.getArch() != llvm::Triple::riscv32 && isRISCV32Builtin(BuiltinID))
- return Diag(TheCall->getCallee()->getBeginLoc(),
- diag::err_32_bit_builtin_64_bit_tgt);
-
// Check if each required feature is included
for (StringRef F : ReqFeatures) {
SmallVector<StringRef> ReqOpFeatures;
F.split(ReqOpFeatures, '|');
- bool HasFeature = false;
- for (StringRef OF : ReqOpFeatures) {
- if (TI.hasFeature(OF)) {
- HasFeature = true;
- continue;
- }
- }
- if (!HasFeature) {
+ if (llvm::none_of(ReqOpFeatures,
+ [&TI](StringRef OF) { return TI.hasFeature(OF); })) {
std::string FeatureStrs;
+ bool IsExtension = true;
for (StringRef OF : ReqOpFeatures) {
// If the feature is 64bit, alter the string so it will print better in
// the diagnostic.
- if (OF == "64bit")
+ if (OF == "64bit") {
+ assert(ReqOpFeatures.size() == 1 && "Expected '64bit' to be alone");
OF = "RV64";
+ IsExtension = false;
+ }
+ if (OF == "32bit") {
+ assert(ReqOpFeatures.size() == 1 && "Expected '32bit' to be alone");
+ OF = "RV32";
+ IsExtension = false;
+ }
// Convert features like "zbr" and "experimental-zbr" to "Zbr".
OF.consume_front("experimental-");
@@ -4391,6 +4583,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
// Error message
FeatureMissing = true;
Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension)
+ << IsExtension
<< TheCall->getSourceRange() << StringRef(FeatureStrs);
}
}
@@ -4449,7 +4642,8 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
if (BuiltinID == SystemZ::BI__builtin_tabort) {
Expr *Arg = TheCall->getArg(0);
- if (Optional<llvm::APSInt> AbortCode = Arg->getIntegerConstantExpr(Context))
+ if (std::optional<llvm::APSInt> AbortCode =
+ Arg->getIntegerConstantExpr(Context))
if (AbortCode->getSExtValue() >= 0 && AbortCode->getSExtValue() < 256)
return Diag(Arg->getBeginLoc(), diag::err_systemz_invalid_tabort_code)
<< Arg->getSourceRange();
@@ -5010,6 +5204,7 @@ bool Sema::CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_tdpbusd:
case X86::BI__builtin_ia32_tdpbuud:
case X86::BI__builtin_ia32_tdpbf16ps:
+ case X86::BI__builtin_ia32_tdpfp16ps:
return CheckX86BuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2});
}
}
@@ -5394,6 +5589,10 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case X86::BI__builtin_ia32_reducesh_mask:
i = 4; l = 0; u = 255;
break;
+ case X86::BI__builtin_ia32_cmpccxadd32:
+ case X86::BI__builtin_ia32_cmpccxadd64:
+ i = 3; l = 0; u = 15;
+ break;
}
// Note that we don't force a hard error on the range check here, allowing
@@ -5437,8 +5636,7 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
/// Returns true if the value evaluates to null.
static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
// If the expression has non-null type, it doesn't evaluate to null.
- if (auto nullability
- = Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) {
+ if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) {
if (*nullability == NullabilityKind::NonNull)
return false;
}
@@ -5522,8 +5720,8 @@ DiagnoseCStringFormatDirectiveInCFAPI(Sema &S,
}
/// Determine whether the given type has a non-null nullability annotation.
-static bool isNonNullType(ASTContext &ctx, QualType type) {
- if (auto nullability = type->getNullability(ctx))
+static bool isNonNullType(QualType type) {
+ if (auto nullability = type->getNullability())
return *nullability == NullabilityKind::NonNull;
return false;
@@ -5536,7 +5734,7 @@ static void CheckNonNullArguments(Sema &S,
SourceLocation CallSiteLoc) {
assert((FDecl || Proto) && "Need a function declaration or prototype");
- // Already checked by by constant evaluator.
+ // Already checked by constant evaluator.
if (S.isConstantEvaluated())
return;
// Check the attributes attached to the method/function itself.
@@ -5576,8 +5774,7 @@ static void CheckNonNullArguments(Sema &S,
for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end();
I != E; ++I, ++ParamIndex) {
const ParmVarDecl *PVD = *I;
- if (PVD->hasAttr<NonNullAttr>() ||
- isNonNullType(S.Context, PVD->getType())) {
+ if (PVD->hasAttr<NonNullAttr>() || isNonNullType(PVD->getType())) {
if (NonNullArgs.empty())
NonNullArgs.resize(Args.size());
@@ -5606,7 +5803,7 @@ static void CheckNonNullArguments(Sema &S,
if (Proto) {
unsigned Index = 0;
for (auto paramType : Proto->getParamTypes()) {
- if (isNonNullType(S.Context, paramType)) {
+ if (isNonNullType(paramType)) {
if (NonNullArgs.empty())
NonNullArgs.resize(Args.size());
@@ -5622,7 +5819,7 @@ static void CheckNonNullArguments(Sema &S,
for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size();
ArgIndex != ArgIndexEnd; ++ArgIndex) {
if (NonNullArgs[ArgIndex])
- CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc);
+ CheckNonNullArgument(S, Args[ArgIndex], Args[ArgIndex]->getExprLoc());
}
}
@@ -5683,9 +5880,9 @@ void Sema::CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl,
// Find expected alignment, and the actual alignment of the passed object.
// getTypeAlignInChars requires complete types
- if (ArgTy.isNull() || ParamTy->isIncompleteType() ||
- ArgTy->isIncompleteType() || ParamTy->isUndeducedType() ||
- ArgTy->isUndeducedType())
+ if (ArgTy.isNull() || ParamTy->isDependentType() ||
+ ParamTy->isIncompleteType() || ArgTy->isIncompleteType() ||
+ ParamTy->isUndeducedType() || ArgTy->isUndeducedType())
return;
CharUnits ParamAlign = Context.getTypeAlignInChars(ParamTy);
@@ -5837,14 +6034,14 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
unsigned NumArgs = TheCall->getNumArgs();
Expr *ImplicitThis = nullptr;
- if (IsMemberOperatorCall) {
- // If this is a call to a member operator, hide the first argument
- // from checkCall.
+ if (IsMemberOperatorCall && !FDecl->isStatic()) {
+ // If this is a call to a non-static member operator, hide the first
+ // argument from checkCall.
// FIXME: Our choice of AST representation here is less than ideal.
ImplicitThis = Args[0];
++Args;
--NumArgs;
- } else if (IsMemberFunction)
+ } else if (IsMemberFunction && !FDecl->isStatic())
ImplicitThis =
cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();
@@ -5864,7 +6061,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
ThisTypeFromDecl);
}
- checkCall(FDecl, Proto, ImplicitThis, llvm::makeArrayRef(Args, NumArgs),
+ checkCall(FDecl, Proto, ImplicitThis, llvm::ArrayRef(Args, NumArgs),
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -5945,7 +6142,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
}
checkCall(NDecl, Proto, /*ThisArg=*/nullptr,
- llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
+ llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -5958,7 +6155,7 @@ bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
TheCall->getCallee());
checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr,
- llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
+ llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -6463,7 +6660,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
}
if (SubExprs.size() >= 2 && Form != Init) {
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
SubExprs[1]->getIntegerConstantExpr(Context))
if (!isValidOrderingForOp(Result->getSExtValue(), Op))
Diag(SubExprs[1]->getBeginLoc(),
@@ -6473,7 +6670,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
auto *Scope = Args[Args.size() - 1];
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
Scope->getIntegerConstantExpr(Context)) {
if (!ScopeModel->isValid(Result->getZExtValue()))
Diag(Scope->getBeginLoc(), diag::err_atomic_op_has_invalid_synch_scope)
@@ -6840,7 +7037,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
// Get the decl for the concrete builtin from this, we can tell what the
// concrete integer type we should convert to is.
unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
- const char *NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID);
+ StringRef NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID);
FunctionDecl *NewBuiltinDecl;
if (NewBuiltinID == BuiltinID)
NewBuiltinDecl = FDecl;
@@ -7122,6 +7319,9 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
if (checkVAStartABI(*this, BuiltinID, Fn))
return true;
+ // In C2x mode, va_start only needs one argument. However, the builtin still
+ // requires two arguments (which matches the behavior of the GCC builtin),
+ // <stdarg.h> passes `0` as the second argument in C2x mode.
if (checkArgCount(*this, TheCall, 2))
return true;
@@ -7135,9 +7335,15 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
return true;
// Verify that the second argument to the builtin is the last argument of the
- // current function or method.
+ // current function or method. In C2x mode, if the second argument is an
+ // integer constant expression with value 0, then we don't bother with this
+ // check.
bool SecondArgIsLastNamedArgument = false;
const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
+ if (std::optional<llvm::APSInt> Val =
+ TheCall->getArg(1)->getIntegerConstantExpr(Context);
+ Val && LangOpts.C2x && *Val == 0)
+ return false;
// These are valid if SecondArgIsLastNamedArgument is false after the next
// block.
@@ -7163,7 +7369,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
Type->isSpecificBuiltinType(BuiltinType::Float) || [=] {
// Promotable integers are UB, but enumerations need a bit of
// extra checking to see what their promotable type actually is.
- if (!Type->isPromotableIntegerType())
+ if (!Context.isPromotableIntegerType(Type))
return false;
if (!Type->isEnumeralType())
return true;
@@ -7178,7 +7384,6 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
Diag(ParamLoc, diag::note_parameter_type) << Type;
}
- TheCall->setType(Context.VoidTy);
return false;
}
@@ -7490,7 +7695,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
TheCall->getArg(i)->isValueDependent())
continue;
- Optional<llvm::APSInt> Result;
+ std::optional<llvm::APSInt> Result;
if (!(Result = TheCall->getArg(i)->getIntegerConstantExpr(Context)))
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_shufflevector_nonconstant_argument)
@@ -7644,38 +7849,43 @@ bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) {
/// Handle __builtin_assume_aligned. This is declared
/// as (const void*, size_t, ...) and can take one optional constant int arg.
bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) {
+ if (checkArgCountRange(*this, TheCall, 2, 3))
+ return true;
+
unsigned NumArgs = TheCall->getNumArgs();
+ Expr *FirstArg = TheCall->getArg(0);
- if (NumArgs > 3)
- return Diag(TheCall->getEndLoc(),
- diag::err_typecheck_call_too_many_args_at_most)
- << 0 /*function call*/ << 3 << NumArgs << TheCall->getSourceRange();
+ {
+ ExprResult FirstArgResult =
+ DefaultFunctionArrayLvalueConversion(FirstArg);
+ if (FirstArgResult.isInvalid())
+ return true;
+ TheCall->setArg(0, FirstArgResult.get());
+ }
// The alignment must be a constant integer.
- Expr *Arg = TheCall->getArg(1);
+ Expr *SecondArg = TheCall->getArg(1);
// We can't check the value of a dependent argument.
- if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
+ if (!SecondArg->isValueDependent()) {
llvm::APSInt Result;
if (SemaBuiltinConstantArg(TheCall, 1, Result))
return true;
if (!Result.isPowerOf2())
return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
- << Arg->getSourceRange();
+ << SecondArg->getSourceRange();
if (Result > Sema::MaximumAlignment)
Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great)
- << Arg->getSourceRange() << Sema::MaximumAlignment;
+ << SecondArg->getSourceRange() << Sema::MaximumAlignment;
}
if (NumArgs > 2) {
- ExprResult Arg(TheCall->getArg(2));
- InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
- Context.getSizeType(), false);
- Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
- if (Arg.isInvalid()) return true;
- TheCall->setArg(2, Arg.get());
+ Expr *ThirdArg = TheCall->getArg(2);
+ if (convertArgumentToType(*this, ThirdArg, Context.getSizeType()))
+ return true;
+ TheCall->setArg(2, ThirdArg);
}
return false;
@@ -7771,7 +7981,7 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
if (Arg->isTypeDependent() || Arg->isValueDependent()) return false;
- Optional<llvm::APSInt> R;
+ std::optional<llvm::APSInt> R;
if (!(R = Arg->getIntegerConstantExpr(Context)))
return Diag(TheCall->getBeginLoc(), diag::err_constant_integer_arg_type)
<< FDecl->getDeclName() << Arg->getSourceRange();
@@ -8106,6 +8316,8 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
BuiltinID == ARM::BI__builtin_arm_wsrp;
bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
+ BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128 ||
BuiltinID == AArch64::BI__builtin_arm_rsr ||
BuiltinID == AArch64::BI__builtin_arm_rsrp ||
BuiltinID == AArch64::BI__builtin_arm_wsr ||
@@ -8173,21 +8385,51 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall,
return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
<< Arg->getSourceRange();
} else if (IsAArch64Builtin && Fields.size() == 1) {
- // If the register name is one of those that appear in the condition below
- // and the special register builtin being used is one of the write builtins,
- // then we require that the argument provided for writing to the register
- // is an integer constant expression. This is because it will be lowered to
- // an MSR (immediate) instruction, so we need to know the immediate at
- // compile time.
+ // This code validates writes to PSTATE registers.
+
+ // Not a write.
if (TheCall->getNumArgs() != 2)
return false;
- std::string RegLower = Reg.lower();
- if (RegLower != "spsel" && RegLower != "daifset" && RegLower != "daifclr" &&
- RegLower != "pan" && RegLower != "uao")
+ // The 128-bit system register accesses do not touch PSTATE.
+ if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128)
return false;
- return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15);
+ // These are the named PSTATE accesses using "MSR (immediate)" instructions,
+ // along with the upper limit on the immediates allowed.
+ auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)
+ .CaseLower("spsel", 15)
+ .CaseLower("daifclr", 15)
+ .CaseLower("daifset", 15)
+ .CaseLower("pan", 15)
+ .CaseLower("uao", 15)
+ .CaseLower("dit", 15)
+ .CaseLower("ssbs", 15)
+ .CaseLower("tco", 15)
+ .CaseLower("allint", 1)
+ .CaseLower("pm", 1)
+ .Default(std::nullopt);
+
+ // If this is not a named PSTATE, just continue without validating, as this
+ // will be lowered to an "MSR (register)" instruction directly
+ if (!MaxLimit)
+ return false;
+
+ // Here we only allow constants in the range for that pstate, as required by
+ // the ACLE.
+ //
+ // While clang also accepts the names of system registers in its ACLE
+ // intrinsics, we prevent this with the PSTATE names used in MSR (immediate)
+ // as the value written via a register is different to the value used as an
+ // immediate to have the same effect. e.g., for the instruction `msr tco,
+ // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but
+ // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.
+ //
+ // If a programmer wants to codegen the MSR (register) form of `msr tco,
+ // xN`, they can still do so by specifying the register using five
+ // colon-separated numbers in a string.
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit);
}
return false;
@@ -8473,6 +8715,9 @@ static void CheckFormatString(
llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
bool IgnoreStringsWithoutSpecifiers);
+static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
+ const Expr *E);
+
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
// format string, we will usually need to emit a warning.
@@ -8503,6 +8748,15 @@ tryAgain:
return SLCT_UncheckedLiteral;
switch (E->getStmtClass()) {
+ case Stmt::InitListExprClass:
+ // Handle expressions like {"foobar"}.
+ if (const clang::Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) {
+ return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg,
+ Type, CallType, /*InFunctionCall*/ false,
+ CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
+ }
+ return SLCT_NotALiteral;
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
// The expression is a literal if both sub-expressions were, and it was
@@ -8713,7 +8967,11 @@ tryAgain:
}
}
}
-
+ if (const Expr *SLE = maybeConstEvalStringLiteral(S.Context, E))
+ return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg,
+ Type, CallType, /*InFunctionCall*/ false,
+ CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
return SLCT_NotALiteral;
}
case Stmt::ObjCMessageExprClass: {
@@ -8823,6 +9081,20 @@ tryAgain:
}
}
+// If this expression can be evaluated at compile-time,
+// check if the result is a StringLiteral and return it
+// otherwise return nullptr
+static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
+ const Expr *E) {
+ Expr::EvalResult Result;
+ if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) {
+ const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
+ if (isa_and_nonnull<StringLiteral>(LVE))
+ return LVE;
+ }
+ return nullptr;
+}
+
Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
return llvm::StringSwitch<FormatStringType>(Format->getType()->getName())
.Case("scanf", FST_Scanf)
@@ -9013,7 +9285,7 @@ public:
EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr,
const PartialDiagnostic &PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
- ArrayRef<FixItHint> Fixit = None);
+ ArrayRef<FixItHint> Fixit = std::nullopt);
protected:
bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
@@ -9040,7 +9312,7 @@ protected:
template <typename Range>
void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
bool IsStringLocation, Range StringRange,
- ArrayRef<FixItHint> Fixit = None);
+ ArrayRef<FixItHint> Fixit = std::nullopt);
};
} // namespace
@@ -9083,7 +9355,7 @@ void CheckFormatHandler::HandleInvalidLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
getLocationOfByte(LM.getStart()),
@@ -9116,7 +9388,7 @@ void CheckFormatHandler::HandleNonStandardLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< LM.toString() << 0,
@@ -9143,7 +9415,7 @@ void CheckFormatHandler::HandleNonStandardConversionSpecifier(
using namespace analyze_format_string;
// See if we know how to fix this conversion specifier.
- Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+ std::optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
if (FixedCS) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< CS.toString() << /*conversion specifier*/1,
@@ -10005,7 +10277,7 @@ isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) {
// It's an integer promotion if the destination type is the promoted
// source type.
if (ICE->getCastKind() == CK_IntegralCast &&
- From->isPromotableIntegerType() &&
+ S.Context.isPromotableIntegerType(From) &&
S.Context.getPromotedIntegerType(From) == To)
return true;
// Look through vector types, since we do default argument promotion for
@@ -10060,10 +10332,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
return true;
}
- analyze_printf::ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
- if (Match == analyze_printf::ArgType::Match)
+ ArgType::MatchKind ImplicitMatch = ArgType::NoMatch;
+ ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
+ if (Match == ArgType::Match)
return true;
+ // NoMatchPromotionTypeConfusion should be only returned in ImplictCastExpr
+ assert(Match != ArgType::NoMatchPromotionTypeConfusion);
+
// Look through argument promotions for our error message's reported type.
// This includes the integral and floating promotions, but excludes array
// and function pointer decay (seeing that an argument intended to be a
@@ -10080,13 +10356,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getType() == S.Context.IntTy ||
ICE->getType() == S.Context.UnsignedIntTy) {
// 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)
+ ImplicitMatch = AT.matchesType(S.Context, ExprTy);
+ if (ImplicitMatch == ArgType::Match)
return true;
- if (ImplicitMatch == ArgType::NoMatchPedantic ||
- ImplicitMatch == ArgType::NoMatchTypeConfusion)
- Match = ImplicitMatch;
}
}
} else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
@@ -10097,10 +10369,29 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// modifier is provided.
if (ExprTy == S.Context.IntTy &&
FS.getLengthModifier().getKind() != LengthModifier::AsChar)
- if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue()))
+ if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) {
ExprTy = S.Context.CharTy;
+ // To improve check results, we consider a character literal in C
+ // to be a 'char' rather than an 'int'. 'printf("%hd", 'a');' is
+ // more likely a type confusion situation, so we will suggest to
+ // use '%hhd' instead by discarding the MatchPromotion.
+ if (Match == ArgType::MatchPromotion)
+ Match = ArgType::NoMatch;
+ }
}
-
+ if (Match == ArgType::MatchPromotion) {
+ // WG14 N2562 only clarified promotions in *printf
+ // For NSLog in ObjC, just preserve -Wformat behavior
+ if (!S.getLangOpts().ObjC &&
+ ImplicitMatch != ArgType::NoMatchPromotionTypeConfusion &&
+ ImplicitMatch != ArgType::NoMatchTypeConfusion)
+ return true;
+ Match = ArgType::NoMatch;
+ }
+ if (ImplicitMatch == ArgType::NoMatchPedantic ||
+ ImplicitMatch == ArgType::NoMatchTypeConfusion)
+ Match = ImplicitMatch;
+ assert(Match != ArgType::MatchPromotion);
// Look through enums to their underlying type.
bool IsEnum = false;
if (auto EnumTy = ExprTy->getAs<EnumType>()) {
@@ -10173,7 +10464,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) {
unsigned Diag;
switch (Match) {
- case ArgType::Match: llvm_unreachable("expected non-matching");
+ case ArgType::Match:
+ case ArgType::MatchPromotion:
+ case ArgType::NoMatchPromotionTypeConfusion:
+ llvm_unreachable("expected non-matching");
case ArgType::NoMatchPedantic:
Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
break;
@@ -10236,7 +10530,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// We extract the name from the typedef because we don't want to show
// the underlying type in the diagnostic.
StringRef Name;
- if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(ExprTy))
+ if (const auto *TypedefTy = ExprTy->getAs<TypedefType>())
Name = TypedefTy->getDecl()->getName();
else
Name = CastTyName;
@@ -10270,7 +10564,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
case Sema::VAK_ValidInCXX11: {
unsigned Diag;
switch (Match) {
- case ArgType::Match: llvm_unreachable("expected non-matching");
+ case ArgType::Match:
+ case ArgType::MatchPromotion:
+ case ArgType::NoMatchPromotionTypeConfusion:
+ llvm_unreachable("expected non-matching");
case ArgType::NoMatchPedantic:
Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
break;
@@ -10824,7 +11121,7 @@ static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range,
unsigned AbsKind, QualType ArgType) {
bool EmitHeaderHint = true;
const char *HeaderName = nullptr;
- const char *FunctionName = nullptr;
+ StringRef FunctionName;
if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) {
FunctionName = "std::abs";
if (ArgType->isIntegralOrEnumerationType()) {
@@ -10932,7 +11229,7 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
// Unsigned types cannot be negative. Suggest removing the absolute value
// function call.
if (ArgType->isUnsignedIntegerType()) {
- const char *FunctionName =
+ StringRef FunctionName =
IsStdAbs ? "std::abs" : Context.BuiltinInfo.getName(AbsKind);
Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType;
Diag(Call->getExprLoc(), diag::note_remove_abs)
@@ -11851,7 +12148,7 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
const FunctionDecl *FD) {
// Check if the return value is null but should not be.
if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) ||
- (!isObjCMethod && isNonNullType(Context, lhsType))) &&
+ (!isObjCMethod && isNonNullType(lhsType))) &&
CheckNonNullExpr(*this, RetValExp))
Diag(ReturnLoc, diag::warn_null_ret)
<< (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange();
@@ -12301,7 +12598,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
return IntRange(R.Width, /*NonNegative*/ true);
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case BO_ShlAssign:
return IntRange::forValueOfType(C, GetExprType(E));
@@ -12314,7 +12611,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
// If the shift amount is a positive constant, drop the width by
// that much.
- if (Optional<llvm::APSInt> shift =
+ if (std::optional<llvm::APSInt> shift =
BO->getRHS()->getIntegerConstantExpr(C)) {
if (shift->isNonNegative()) {
unsigned zext = shift->getZExtValue();
@@ -12359,7 +12656,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth,
Approximate);
// If the divisor is constant, use that.
- if (Optional<llvm::APSInt> divisor =
+ if (std::optional<llvm::APSInt> divisor =
BO->getRHS()->getIntegerConstantExpr(C)) {
unsigned log2 = divisor->logBase2(); // floor(log_2(divisor))
if (log2 >= L.Width)
@@ -12589,7 +12886,7 @@ struct PromotedRange {
llvm_unreachable("impossible compare result");
}
- static llvm::Optional<StringRef>
+ static std::optional<StringRef>
constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) {
if (Op == BO_Cmp) {
ComparisonResult LTFlag = LT, GTFlag = GT;
@@ -12598,7 +12895,7 @@ struct PromotedRange {
if (R & EQ) return StringRef("'std::strong_ordering::equal'");
if (R & LTFlag) return StringRef("'std::strong_ordering::less'");
if (R & GTFlag) return StringRef("'std::strong_ordering::greater'");
- return llvm::None;
+ return std::nullopt;
}
ComparisonResult TrueFlag, FalseFlag;
@@ -12623,7 +12920,7 @@ struct PromotedRange {
return StringRef("true");
if (R & FalseFlag)
return StringRef("false");
- return llvm::None;
+ return std::nullopt;
}
};
}
@@ -12833,8 +13130,10 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
Expr *RHS = E->getRHS();
if (T->isIntegralType(S.Context)) {
- Optional<llvm::APSInt> RHSValue = RHS->getIntegerConstantExpr(S.Context);
- Optional<llvm::APSInt> LHSValue = LHS->getIntegerConstantExpr(S.Context);
+ std::optional<llvm::APSInt> RHSValue =
+ RHS->getIntegerConstantExpr(S.Context);
+ std::optional<llvm::APSInt> LHSValue =
+ LHS->getIntegerConstantExpr(S.Context);
// We don't care about expressions whose result is a constant.
if (RHSValue && LHSValue)
@@ -12955,9 +13254,6 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
}
}
- if (Bitfield->getType()->isBooleanType())
- return false;
-
// Ignore value- or type-dependent expressions.
if (Bitfield->getBitWidth()->isValueDependent() ||
Bitfield->getBitWidth()->isTypeDependent() ||
@@ -13029,6 +13325,18 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
unsigned OriginalWidth = Value.getBitWidth();
+ // In C, the macro 'true' from stdbool.h will evaluate to '1'; To reduce
+ // false positives where the user is demonstrating they intend to use the
+ // bit-field as a Boolean, check to see if the value is 1 and we're assigning
+ // to a one-bit bit-field to see if the value came from a macro named 'true'.
+ bool OneAssignedToOneBitBitfield = FieldWidth == 1 && Value == 1;
+ if (OneAssignedToOneBitBitfield && !S.LangOpts.CPlusPlus) {
+ SourceLocation MaybeMacroLoc = OriginalInit->getBeginLoc();
+ if (S.SourceMgr.isInSystemMacro(MaybeMacroLoc) &&
+ S.findMacroSpelling(MaybeMacroLoc, "true"))
+ return false;
+ }
+
if (!Value.isSigned() || Value.isNegative())
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit))
if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not)
@@ -13046,17 +13354,14 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
if (llvm::APSInt::isSameValue(Value, TruncatedValue))
return false;
- // Special-case bitfields of width 1: booleans are naturally 0/1, and
- // therefore don't strictly fit into a signed bitfield of width 1.
- if (FieldWidth == 1 && Value == 1)
- return false;
-
std::string PrettyValue = toString(Value, 10);
std::string PrettyTrunc = toString(TruncatedValue, 10);
- S.Diag(InitLoc, diag::warn_impcast_bitfield_precision_constant)
- << PrettyValue << PrettyTrunc << OriginalInit->getType()
- << Init->getSourceRange();
+ S.Diag(InitLoc, OneAssignedToOneBitBitfield
+ ? diag::warn_impcast_single_bit_bitield_precision_constant
+ : diag::warn_impcast_bitfield_precision_constant)
+ << PrettyValue << PrettyTrunc << OriginalInit->getType()
+ << Init->getSourceRange();
return true;
}
@@ -13342,9 +13647,10 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
return;
// Check for NULL (GNUNull) or nullptr (CXX11_nullptr).
- const Expr::NullPointerConstantKind NullKind =
- E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull);
- if (NullKind != Expr::NPCK_GNUNull && NullKind != Expr::NPCK_CXX11_nullptr)
+ const Expr *NewE = E->IgnoreParenImpCasts();
+ bool IsGNUNullExpr = isa<GNUNullExpr>(NewE);
+ bool HasNullPtrType = NewE->getType()->isNullPtrType();
+ if (!IsGNUNullExpr && !HasNullPtrType)
return;
// Return if target type is a safe conversion.
@@ -13361,7 +13667,7 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
CC = S.SourceMgr.getTopMacroCallerLoc(CC);
// __null is usually wrapped in a macro. Go up a macro if that is the case.
- if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) {
+ if (IsGNUNullExpr && Loc.isMacroID()) {
StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
Loc, S.SourceMgr, S.getLangOpts());
if (MacroName == "NULL")
@@ -13373,7 +13679,7 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
return;
S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
- << (NullKind == Expr::NPCK_CXX11_nullptr) << T << SourceRange(CC)
+ << HasNullPtrType << T << SourceRange(CC)
<< FixItHint::CreateReplacement(Loc,
S.getFixItZeroLiteralForType(T, Loc));
}
@@ -13836,7 +14142,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (SourcePrecision > 0 && TargetPrecision > 0 &&
SourcePrecision > TargetPrecision) {
- if (Optional<llvm::APSInt> SourceInt =
+ if (std::optional<llvm::APSInt> SourceInt =
E->getIntegerConstantExpr(S.Context)) {
// If the source integer is a constant, convert it to the target
// floating point type. Issue a warning if the value changes
@@ -14559,6 +14865,17 @@ void Sema::CheckForIntOverflow (Expr *E) {
Exprs.append(Call->arg_begin(), Call->arg_end());
else if (auto Message = dyn_cast<ObjCMessageExpr>(E))
Exprs.append(Message->arg_begin(), Message->arg_end());
+ else if (auto Construct = dyn_cast<CXXConstructExpr>(E))
+ Exprs.append(Construct->arg_begin(), Construct->arg_end());
+ else if (auto Array = dyn_cast<ArraySubscriptExpr>(E))
+ Exprs.push_back(Array->getIdx());
+ else if (auto Compound = dyn_cast<CompoundLiteralExpr>(E))
+ Exprs.push_back(Compound->getInitializer());
+ else if (auto New = dyn_cast<CXXNewExpr>(E)) {
+ if (New->isArray())
+ if (auto ArraySize = New->getArraySize())
+ Exprs.push_back(*ArraySize);
+ }
} while (!Exprs.empty());
}
@@ -15425,8 +15742,8 @@ void Sema::CheckUnsequencedOperations(const Expr *E) {
void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
bool IsConstexpr) {
- llvm::SaveAndRestore<bool> ConstantContext(
- isConstantEvaluatedOverride, IsConstexpr || isa<ConstantExpr>(E));
+ llvm::SaveAndRestore ConstantContext(isConstantEvaluatedOverride,
+ IsConstexpr || isa<ConstantExpr>(E));
CheckImplicitConversions(E, CheckLoc);
if (!E->isInstantiationDependent())
CheckUnsequencedOperations(E);
@@ -15551,8 +15868,11 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
return HasInvalidParm;
}
-Optional<std::pair<CharUnits, CharUnits>>
-static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx);
+std::optional<std::pair<
+ CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr
+ *E,
+ ASTContext
+ &Ctx);
/// Compute the alignment and offset of the base class object given the
/// derived-to-base cast expression and the alignment and offset of the derived
@@ -15586,21 +15906,21 @@ getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType,
}
/// Compute the alignment and offset of a binary additive operator.
-static Optional<std::pair<CharUnits, CharUnits>>
+static std::optional<std::pair<CharUnits, CharUnits>>
getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE,
bool IsSub, ASTContext &Ctx) {
QualType PointeeType = PtrE->getType()->getPointeeType();
if (!PointeeType->isConstantSizeType())
- return llvm::None;
+ return std::nullopt;
auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx);
if (!P)
- return llvm::None;
+ return std::nullopt;
CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType);
- if (Optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) {
+ if (std::optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) {
CharUnits Offset = EltSize * IdxRes->getExtValue();
if (IsSub)
Offset = -Offset;
@@ -15617,8 +15937,10 @@ getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE,
/// This helper function takes an lvalue expression and returns the alignment of
/// a VarDecl and a constant offset from the VarDecl.
-Optional<std::pair<CharUnits, CharUnits>>
-static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) {
+std::optional<std::pair<
+ CharUnits,
+ CharUnits>> static getBaseAlignmentAndOffsetFromLValue(const Expr *E,
+ ASTContext &Ctx) {
E = E->IgnoreParens();
switch (E->getStmtClass()) {
default:
@@ -15666,7 +15988,7 @@ static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) {
if (!FD || FD->getType()->isReferenceType() ||
FD->getParent()->isInvalidDecl())
break;
- Optional<std::pair<CharUnits, CharUnits>> P;
+ std::optional<std::pair<CharUnits, CharUnits>> P;
if (ME->isArrow())
P = getBaseAlignmentAndOffsetFromPtr(ME->getBase(), Ctx);
else
@@ -15700,13 +16022,16 @@ static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) {
break;
}
}
- return llvm::None;
+ return std::nullopt;
}
/// This helper function takes a pointer expression and returns the alignment of
/// a VarDecl and a constant offset from the VarDecl.
-Optional<std::pair<CharUnits, CharUnits>>
-static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx) {
+std::optional<std::pair<
+ CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr
+ *E,
+ ASTContext
+ &Ctx) {
E = E->IgnoreParens();
switch (E->getStmtClass()) {
default:
@@ -15765,12 +16090,12 @@ static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx) {
break;
}
}
- return llvm::None;
+ return std::nullopt;
}
static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) {
// See if we can compute the alignment of a VarDecl and an offset from it.
- Optional<std::pair<CharUnits, CharUnits>> P =
+ std::optional<std::pair<CharUnits, CharUnits>> P =
getBaseAlignmentAndOffsetFromPtr(E, S.Context);
if (P)
@@ -15824,71 +16149,6 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
<< TRange << Op->getSourceRange();
}
-/// Check whether this array fits the idiom of a size-one tail padded
-/// array member of a struct.
-///
-/// We avoid emitting out-of-bounds access warnings for such arrays as they are
-/// commonly used to emulate flexible arrays in C89 code.
-static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size,
- const NamedDecl *ND,
- unsigned StrictFlexArraysLevel) {
- if (!ND)
- return false;
-
- if (StrictFlexArraysLevel >= 2 && Size != 0)
- return false;
-
- if (StrictFlexArraysLevel == 1 && Size.ule(1))
- return false;
-
- // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing
- // arrays to be treated as flexible-array-members, we still emit diagnostics
- // as if they are not. Pending further discussion...
- if (StrictFlexArraysLevel == 0 && Size != 1)
- return false;
-
- const FieldDecl *FD = dyn_cast<FieldDecl>(ND);
- if (!FD)
- return false;
-
- // Don't consider sizes resulting from macro expansions or template argument
- // substitution to form C89 tail-padded arrays.
-
- TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
- while (TInfo) {
- TypeLoc TL = TInfo->getTypeLoc();
- // Look through typedefs.
- if (TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>()) {
- const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
- TInfo = TDL->getTypeSourceInfo();
- continue;
- }
- if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
- const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
- if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
- return false;
- }
- break;
- }
-
- const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext());
- if (!RD)
- return false;
- if (RD->isUnion())
- return false;
- if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- if (!CRD->isStandardLayout())
- return false;
- }
-
- // See if this is the last field decl in the record.
- const Decl *D = FD;
- while ((D = D->getNextDeclInContext()))
- if (isa<FieldDecl>(D))
- return false;
- return true;
-}
-
void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ArraySubscriptExpr *ASE,
bool AllowOnePastEnd, bool IndexNegated) {
@@ -15906,9 +16166,15 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
const ConstantArrayType *ArrayTy =
Context.getAsConstantArrayType(BaseExpr->getType());
+ LangOptions::StrictFlexArraysLevelKind
+ StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel();
+
const Type *BaseType =
ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr();
- bool IsUnboundedArray = (BaseType == nullptr);
+ bool IsUnboundedArray =
+ BaseType == nullptr || BaseExpr->isFlexibleArrayMemberLike(
+ Context, StrictFlexArraysLevel,
+ /*IgnoreTemplateOrMacroSubstitution=*/true);
if (EffectiveType->isDependentType() ||
(!IsUnboundedArray && BaseType->isDependentType()))
return;
@@ -15923,23 +16189,16 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
index = -index;
}
- const NamedDecl *ND = nullptr;
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
- ND = DRE->getDecl();
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr))
- ND = ME->getMemberDecl();
-
if (IsUnboundedArray) {
if (EffectiveType->isFunctionType())
return;
if (index.isUnsigned() || !index.isNegative()) {
const auto &ASTC = getASTContext();
- unsigned AddrBits =
- ASTC.getTargetInfo().getPointerWidth(ASTC.getTargetAddressSpace(
- EffectiveType->getCanonicalTypeInternal()));
+ unsigned AddrBits = ASTC.getTargetInfo().getPointerWidth(
+ EffectiveType->getCanonicalTypeInternal().getAddressSpace());
if (index.getBitWidth() < AddrBits)
index = index.zext(AddrBits);
- Optional<CharUnits> ElemCharUnits =
+ std::optional<CharUnits> ElemCharUnits =
ASTC.getTypeSizeInCharsIfKnown(EffectiveType);
// PR50741 - If EffectiveType has unknown size (e.g., if it's a void
// pointer) bounds-checking isn't meaningful.
@@ -15982,15 +16241,14 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
<< (unsigned)MaxElems.getLimitedValue(~0U)
<< IndexExpr->getSourceRange());
- if (!ND) {
- // Try harder to find a NamedDecl to point at in the note.
- while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
- BaseExpr = ASE->getBase()->IgnoreParenCasts();
- if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
- ND = DRE->getDecl();
- if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
- ND = ME->getMemberDecl();
- }
+ const NamedDecl *ND = nullptr;
+ // Try harder to find a NamedDecl to point at in the note.
+ while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
+ BaseExpr = ASE->getBase()->IgnoreParenCasts();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+ ND = DRE->getDecl();
+ if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
+ ND = ME->getMemberDecl();
if (ND)
DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
@@ -16006,29 +16264,28 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
// example). In this case we have no information about whether the array
// access exceeds the array bounds. However we can still diagnose an array
// access which precedes the array bounds.
- //
- // FIXME: this check should be redundant with the IsUnboundedArray check
- // above.
if (BaseType->isIncompleteType())
return;
- // FIXME: this check should belong to the IsTailPaddedMemberArray call
- // below.
llvm::APInt size = ArrayTy->getSize();
- if (!size.isStrictlyPositive())
- return;
if (BaseType != EffectiveType) {
- // Make sure we're comparing apples to apples when comparing index to size
+ // Make sure we're comparing apples to apples when comparing index to
+ // size.
uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType);
uint64_t array_typesize = Context.getTypeSize(BaseType);
- // Handle ptrarith_typesize being zero, such as when casting to void*
- if (!ptrarith_typesize) ptrarith_typesize = 1;
+
+ // Handle ptrarith_typesize being zero, such as when casting to void*.
+ // Use the size in bits (what "getTypeSize()" returns) rather than bytes.
+ if (!ptrarith_typesize)
+ ptrarith_typesize = Context.getCharWidth();
+
if (ptrarith_typesize != array_typesize) {
- // There's a cast to a different size type involved
+ // There's a cast to a different size type involved.
uint64_t ratio = array_typesize / ptrarith_typesize;
+
// TODO: Be smarter about handling cases where array_typesize is not a
- // multiple of ptrarith_typesize
+ // multiple of ptrarith_typesize.
if (ptrarith_typesize * ratio == array_typesize)
size *= llvm::APInt(size.getBitWidth(), ratio);
}
@@ -16046,11 +16303,6 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (AllowOnePastEnd ? index.ule(size) : index.ult(size))
return;
- // Also don't warn for Flexible Array Member emulation.
- const unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays;
- if (IsTailPaddedMemberArray(*this, size, ND, StrictFlexArraysLevel))
- return;
-
// Suppress the warning if the subscript expression (as identified by the
// ']' location) and the index expression are both from macro expansions
// within a system header.
@@ -16067,12 +16319,13 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
unsigned DiagID = ASE ? diag::warn_array_index_exceeds_bounds
: diag::warn_ptr_arith_exceeds_bounds;
+ unsigned CastMsg = (!ASE || BaseType == EffectiveType) ? 0 : 1;
+ QualType CastMsgTy = ASE ? ASE->getLHS()->getType() : QualType();
- DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
- PDiag(DiagID) << toString(index, 10, true)
- << toString(size, 10, true)
- << (unsigned)size.getLimitedValue(~0U)
- << IndexExpr->getSourceRange());
+ DiagRuntimeBehavior(
+ BaseExpr->getBeginLoc(), BaseExpr,
+ PDiag(DiagID) << toString(index, 10, true) << ArrayTy->desugar()
+ << CastMsg << CastMsgTy << IndexExpr->getSourceRange());
} else {
unsigned DiagID = diag::warn_array_index_precedes_bounds;
if (!ASE) {
@@ -16085,15 +16338,14 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
<< IndexExpr->getSourceRange());
}
- if (!ND) {
- // Try harder to find a NamedDecl to point at in the note.
- while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
- BaseExpr = ASE->getBase()->IgnoreParenCasts();
- if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
- ND = DRE->getDecl();
- if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
- ND = ME->getMemberDecl();
- }
+ const NamedDecl *ND = nullptr;
+ // Try harder to find a NamedDecl to point at in the note.
+ while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
+ BaseExpr = ASE->getBase()->IgnoreParenCasts();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+ ND = DRE->getDecl();
+ if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
+ ND = ME->getMemberDecl();
if (ND)
DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
@@ -16318,7 +16570,7 @@ namespace {
return;
if (Expr *RHS = BinOp->getRHS()) {
RHS = RHS->IgnoreParenCasts();
- Optional<llvm::APSInt> Value;
+ std::optional<llvm::APSInt> Value;
VarWillBeReased =
(RHS && (Value = RHS->getIntegerConstantExpr(Context)) &&
*Value == 0);
@@ -16399,21 +16651,21 @@ static bool isSetterLikeSelector(Selector sel) {
return !isLowercase(str.front());
}
-static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S,
- ObjCMessageExpr *Message) {
+static std::optional<int>
+GetNSMutableArrayArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
bool IsMutableArray = S.NSAPIObj->isSubclassOfNSClass(
Message->getReceiverInterface(),
NSAPI::ClassId_NSMutableArray);
if (!IsMutableArray) {
- return None;
+ return std::nullopt;
}
Selector Sel = Message->getSelector();
- Optional<NSAPI::NSArrayMethodKind> MKOpt =
- S.NSAPIObj->getNSArrayMethodKind(Sel);
+ std::optional<NSAPI::NSArrayMethodKind> MKOpt =
+ S.NSAPIObj->getNSArrayMethodKind(Sel);
if (!MKOpt) {
- return None;
+ return std::nullopt;
}
NSAPI::NSArrayMethodKind MK = *MKOpt;
@@ -16427,28 +16679,27 @@ static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S,
return 1;
default:
- return None;
+ return std::nullopt;
}
- return None;
+ return std::nullopt;
}
-static
-Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S,
- ObjCMessageExpr *Message) {
+static std::optional<int>
+GetNSMutableDictionaryArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
bool IsMutableDictionary = S.NSAPIObj->isSubclassOfNSClass(
Message->getReceiverInterface(),
NSAPI::ClassId_NSMutableDictionary);
if (!IsMutableDictionary) {
- return None;
+ return std::nullopt;
}
Selector Sel = Message->getSelector();
- Optional<NSAPI::NSDictionaryMethodKind> MKOpt =
- S.NSAPIObj->getNSDictionaryMethodKind(Sel);
+ std::optional<NSAPI::NSDictionaryMethodKind> MKOpt =
+ S.NSAPIObj->getNSDictionaryMethodKind(Sel);
if (!MKOpt) {
- return None;
+ return std::nullopt;
}
NSAPI::NSDictionaryMethodKind MK = *MKOpt;
@@ -16460,13 +16711,14 @@ Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S,
return 0;
default:
- return None;
+ return std::nullopt;
}
- return None;
+ return std::nullopt;
}
-static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
+static std::optional<int> GetNSSetArgumentIndex(Sema &S,
+ ObjCMessageExpr *Message) {
bool IsMutableSet = S.NSAPIObj->isSubclassOfNSClass(
Message->getReceiverInterface(),
NSAPI::ClassId_NSMutableSet);
@@ -16475,14 +16727,15 @@ static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
Message->getReceiverInterface(),
NSAPI::ClassId_NSMutableOrderedSet);
if (!IsMutableSet && !IsMutableOrderedSet) {
- return None;
+ return std::nullopt;
}
Selector Sel = Message->getSelector();
- Optional<NSAPI::NSSetMethodKind> MKOpt = S.NSAPIObj->getNSSetMethodKind(Sel);
+ std::optional<NSAPI::NSSetMethodKind> MKOpt =
+ S.NSAPIObj->getNSSetMethodKind(Sel);
if (!MKOpt) {
- return None;
+ return std::nullopt;
}
NSAPI::NSSetMethodKind MK = *MKOpt;
@@ -16497,7 +16750,7 @@ static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) {
return 1;
}
- return None;
+ return std::nullopt;
}
void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {
@@ -16505,7 +16758,7 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {
return;
}
- Optional<int> ArgOpt;
+ std::optional<int> ArgOpt;
if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) &&
!(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) &&
@@ -17386,15 +17639,15 @@ void Sema::DiagnoseMisalignedMembers() {
void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
E = E->IgnoreParens();
- if (!T->isPointerType() && !T->isIntegerType())
+ if (!T->isPointerType() && !T->isIntegerType() && !T->isDependentType())
return;
if (isa<UnaryOperator>(E) &&
cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {
auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
if (isa<MemberExpr>(Op)) {
- auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op));
+ auto *MA = llvm::find(MisalignedMembers, MisalignedMember(Op));
if (MA != MisalignedMembers.end() &&
- (T->isIntegerType() ||
+ (T->isDependentType() || T->isIntegerType() ||
(T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||
Context.getTypeAlignInChars(
T->getPointeeType()) <= MA->Alignment))))
@@ -17520,19 +17773,6 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) {
_2, _3, _4));
}
-// Check if \p Ty is a valid type for the elementwise math builtins. If it is
-// not a valid type, emit an error message and return true. Otherwise return
-// false.
-static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
- QualType Ty) {
- if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) {
- S.Diag(Loc, diag::err_builtin_invalid_arg_type)
- << 1 << /* vector, integer or float ty*/ 0 << Ty;
- return true;
- }
- return false;
-}
-
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
if (checkArgCount(*this, TheCall, 1))
return true;
@@ -17624,10 +17864,10 @@ ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall,
}
// Get and verify the matrix dimensions.
-static llvm::Optional<unsigned>
+static std::optional<unsigned>
getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) {
SourceLocation ErrorPos;
- Optional<llvm::APSInt> Value =
+ std::optional<llvm::APSInt> Value =
Expr->getIntegerConstantExpr(S.Context, &ErrorPos);
if (!Value) {
S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg)
@@ -17715,7 +17955,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
} else
ColumnsExpr = nullptr;
- // If any any part of the result matrix type is still pending, just use
+ // If any part of the result matrix type is still pending, just use
// Context.DependentTy, until all parts are resolved.
if ((RowsExpr && RowsExpr->isTypeDependent()) ||
(ColumnsExpr && ColumnsExpr->isTypeDependent())) {
@@ -17724,11 +17964,11 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
}
// Check row and column dimensions.
- llvm::Optional<unsigned> MaybeRows;
+ std::optional<unsigned> MaybeRows;
if (RowsExpr)
MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this);
- llvm::Optional<unsigned> MaybeColumns;
+ std::optional<unsigned> MaybeColumns;
if (ColumnsExpr)
MaybeColumns = getAndVerifyMatrixDimension(ColumnsExpr, "column", *this);
@@ -17740,7 +17980,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
TheCall->setArg(3, StrideExpr);
if (MaybeRows) {
- if (Optional<llvm::APSInt> Value =
+ if (std::optional<llvm::APSInt> Value =
StrideExpr->getIntegerConstantExpr(Context)) {
uint64_t Stride = Value->getZExtValue();
if (Stride < *MaybeRows) {
@@ -17840,7 +18080,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall,
// Check stride argument.
if (MatrixTy) {
- if (Optional<llvm::APSInt> Value =
+ if (std::optional<llvm::APSInt> Value =
StrideExpr->getIntegerConstantExpr(Context)) {
uint64_t Stride = Value->getZExtValue();
if (Stride < MatrixTy->getNumRows()) {
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 8ede7c015315..144bbe150abb 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -56,6 +56,7 @@
#include <list>
#include <map>
+#include <optional>
#include <string>
#include <vector>
@@ -1098,7 +1099,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
getBasePriority(Using->getTargetDecl()),
R.Qualifier, false,
(R.Availability == CXAvailability_Available ||
- R.Availability == CXAvailability_Deprecated));
+ R.Availability == CXAvailability_Deprecated),
+ std::move(R.FixIts));
Result.ShadowDecl = Using;
MaybeAddResult(Result, CurContext);
return;
@@ -1212,7 +1214,7 @@ static void setInBaseClass(ResultBuilder::Result &R) {
enum class OverloadCompare { BothViable, Dominates, Dominated };
// Will Candidate ever be called on the object, when overloaded with Incumbent?
// Returns Dominates if Candidate is always called, Dominated if Incumbent is
-// always called, BothViable if either may be called dependending on arguments.
+// always called, BothViable if either may be called depending on arguments.
// Precondition: must actually be overloads!
static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
const CXXMethodDecl &Incumbent,
@@ -1230,8 +1232,8 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
if (Candidate.parameters()[I]->getType().getCanonicalType() !=
Incumbent.parameters()[I]->getType().getCanonicalType())
return OverloadCompare::BothViable;
- if (!llvm::empty(Candidate.specific_attrs<EnableIfAttr>()) ||
- !llvm::empty(Incumbent.specific_attrs<EnableIfAttr>()))
+ if (!Candidate.specific_attrs<EnableIfAttr>().empty() ||
+ !Incumbent.specific_attrs<EnableIfAttr>().empty())
return OverloadCompare::BothViable;
// At this point, we know calls can't pick one or the other based on
// arguments, so one of the two must win. (Or both fail, handled elsewhere).
@@ -1273,7 +1275,8 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
getBasePriority(Using->getTargetDecl()),
R.Qualifier, false,
(R.Availability == CXAvailability_Available ||
- R.Availability == CXAvailability_Deprecated));
+ R.Availability == CXAvailability_Deprecated),
+ std::move(R.FixIts));
Result.ShadowDecl = Using;
AddResult(Result, CurContext, Hiding);
return;
@@ -1377,6 +1380,33 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
OverloadSet.Add(Method, Results.size());
}
+ // When completing a non-static member function (and not via
+ // dot/arrow member access) and we're not inside that class' scope,
+ // it can't be a call.
+ if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) {
+ const auto *Method = dyn_cast<CXXMethodDecl>(R.getDeclaration());
+ if (Method && !Method->isStatic()) {
+ // Find the class scope that we're currently in.
+ // We could e.g. be inside a lambda, so walk up the DeclContext until we
+ // find a CXXMethodDecl.
+ const auto *CurrentClassScope = [&]() -> const CXXRecordDecl * {
+ for (DeclContext *Ctx = SemaRef.CurContext; Ctx;
+ Ctx = Ctx->getParent()) {
+ const auto *CtxMethod = llvm::dyn_cast<CXXMethodDecl>(Ctx);
+ if (CtxMethod && !CtxMethod->getParent()->isLambda()) {
+ return CtxMethod->getParent();
+ }
+ }
+ return nullptr;
+ }();
+
+ R.FunctionCanBeCall =
+ CurrentClassScope &&
+ (CurrentClassScope == Method->getParent() ||
+ CurrentClassScope->isDerivedFrom(Method->getParent()));
+ }
+ }
+
// Insert this result into the set of results.
Results.push_back(R);
@@ -1807,7 +1837,7 @@ static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC,
Results.AddResult(Result("mutable"));
Results.AddResult(Result("virtual"));
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_ObjCInterface:
case Sema::PCC_ObjCImplementation:
@@ -2095,7 +2125,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
AddObjCTopLevelResults(Results, true);
AddTypedefResult(Results);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Class:
if (SemaRef.getLangOpts().CPlusPlus) {
@@ -2153,7 +2183,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Builder);
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Template:
case Sema::PCC_MemberTemplate:
@@ -2423,14 +2453,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts());
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// Fall through (for statement expressions).
case Sema::PCC_ForInit:
case Sema::PCC_Condition:
AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results);
// Fall through: conditions and statements can have expressions.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_ParenthesizedExpression:
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
@@ -2460,7 +2490,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Results.AddResult(Result(Builder.TakeString()));
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::PCC_Expression: {
if (SemaRef.getLangOpts().CPlusPlus) {
@@ -2643,6 +2673,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S,
Results.AddResult(Result(Builder.TakeString()));
}
+ if (SemaRef.getLangOpts().C2x) {
+ // nullptr
+ Builder.AddResultTypeChunk("nullptr_t");
+ Builder.AddTypedTextChunk("nullptr");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
+
// sizeof expression
Builder.AddResultTypeChunk("size_t");
Builder.AddTypedTextChunk("sizeof");
@@ -2783,7 +2820,7 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo,
while (true) {
// Look through typedefs.
if (!SuppressBlock) {
- if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) {
+ if (TypedefTypeLoc TypedefTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
if (TypeSourceInfo *InnerTSInfo =
TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) {
TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
@@ -2814,18 +2851,16 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo,
}
}
-static std::string
-formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
- FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
- bool SuppressBlockName = false,
- bool SuppressBlock = false,
- Optional<ArrayRef<QualType>> ObjCSubsts = None);
+static std::string formatBlockPlaceholder(
+ const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
+ FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
+ bool SuppressBlockName = false, bool SuppressBlock = false,
+ std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt);
-static std::string
-FormatFunctionParameter(const PrintingPolicy &Policy,
- const DeclaratorDecl *Param, bool SuppressName = false,
- bool SuppressBlock = false,
- Optional<ArrayRef<QualType>> ObjCSubsts = None) {
+static std::string FormatFunctionParameter(
+ const PrintingPolicy &Policy, const DeclaratorDecl *Param,
+ bool SuppressName = false, bool SuppressBlock = false,
+ std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt) {
// Params are unavailable in FunctionTypeLoc if the FunctionType is invalid.
// It would be better to pass in the param Type, which is usually available.
// But this case is rare, so just pretend we fell back to int as elsewhere.
@@ -2920,7 +2955,7 @@ static std::string
formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl,
FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto,
bool SuppressBlockName, bool SuppressBlock,
- Optional<ArrayRef<QualType>> ObjCSubsts) {
+ std::optional<ArrayRef<QualType>> ObjCSubsts) {
std::string Result;
QualType ResultType = Block.getTypePtr()->getReturnType();
if (ObjCSubsts)
@@ -3589,7 +3624,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl(
std::string Arg;
QualType ParamType = (*P)->getType();
- Optional<ArrayRef<QualType>> ObjCSubsts;
+ std::optional<ArrayRef<QualType>> ObjCSubsts;
if (!CCContext.getBaseType().isNull())
ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method);
@@ -4199,7 +4234,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
// We need to have names for all of the parameters, if we're going to
// generate a forwarding call.
- for (auto P : Method->parameters())
+ for (auto *P : Method->parameters())
if (!P->getDeclName())
return;
@@ -4227,7 +4262,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
Results.getAllocator().CopyString(Overridden->getNameAsString()));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
bool FirstParam = true;
- for (auto P : Method->parameters()) {
+ for (auto *P : Method->parameters()) {
if (FirstParam)
FirstParam = false;
else
@@ -4444,7 +4479,8 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
0) {
ParsedType T = DS.getRepAsType();
if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType())
- AddClassMessageCompletions(*this, S, T, None, false, false, Results);
+ AddClassMessageCompletions(*this, S, T, std::nullopt, false, false,
+ Results);
}
// Note that we intentionally suppress macro results here, since we do not
@@ -4657,9 +4693,9 @@ static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) {
// Note we only handle the sugared types, they closely match what users wrote.
// We explicitly choose to not handle ClassTemplateSpecializationDecl.
if (auto *Specialization = T->getAs<TemplateSpecializationType>()) {
- if (Specialization->getNumArgs() != 1)
+ if (Specialization->template_arguments().size() != 1)
return nullptr;
- const TemplateArgument &Argument = Specialization->getArg(0);
+ const TemplateArgument &Argument = Specialization->template_arguments()[0];
if (Argument.getKind() != TemplateArgument::Type)
return nullptr;
return Argument.getAsType()->getAs<FunctionProtoType>();
@@ -4801,7 +4837,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E,
if (E.isInvalid())
CodeCompleteExpression(S, PreferredType);
else if (getLangOpts().ObjC)
- CodeCompleteObjCInstanceMessage(S, E.get(), None, false);
+ CodeCompleteObjCInstanceMessage(S, E.get(), std::nullopt, false);
}
/// The set of properties that have already been added, referenced by
@@ -5045,9 +5081,11 @@ AddObjCProperties(const CodeCompletionContext &CCContext,
}
}
-static void AddRecordMembersCompletionResults(
- Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType,
- ExprValueKind BaseKind, RecordDecl *RD, Optional<FixItHint> AccessOpFixIt) {
+static void
+AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results,
+ Scope *S, QualType BaseType,
+ ExprValueKind BaseKind, RecordDecl *RD,
+ std::optional<FixItHint> AccessOpFixIt) {
// Indicate that we are performing a member access, and the cv-qualifiers
// for the base object type.
Results.setObjectTypeQualifiers(BaseType.getQualifiers(), BaseKind);
@@ -5086,7 +5124,8 @@ static void AddRecordMembersCompletionResults(
// Returns the RecordDecl inside the BaseType, falling back to primary template
// in case of specializations. Since we might not have a decl for the
// instantiation/specialization yet, e.g. dependent code.
-static RecordDecl *getAsRecordDecl(const QualType BaseType) {
+static RecordDecl *getAsRecordDecl(QualType BaseType) {
+ BaseType = BaseType.getNonReferenceType();
if (auto *RD = BaseType->getAsRecordDecl()) {
if (const auto *CTSD =
llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
@@ -5145,7 +5184,7 @@ public:
// We don't have the declared parameter types, only the actual types of
// arguments we've seen. These are still valuable, as it's hard to render
// a useful function completion with neither parameter types nor names!
- llvm::Optional<SmallVector<QualType, 1>> ArgTypes;
+ std::optional<SmallVector<QualType, 1>> ArgTypes;
// Whether this is accessed as T.member, T->member, or T::member.
enum AccessOperator {
Colons,
@@ -5475,11 +5514,16 @@ private:
// We accept some lossiness (like dropping parameters).
// We only try to handle common expressions on the LHS of MemberExpr.
QualType getApproximateType(const Expr *E) {
+ if (E->getType().isNull())
+ return QualType();
+ E = E->IgnoreParenImpCasts();
QualType Unresolved = E->getType();
- if (Unresolved.isNull() ||
- !Unresolved->isSpecificBuiltinType(BuiltinType::Dependent))
- return Unresolved;
- E = E->IgnoreParens();
+ // We only resolve DependentTy, or undeduced autos (including auto* etc).
+ if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) {
+ AutoType *Auto = Unresolved->getContainedAutoType();
+ if (!Auto || !Auto->isUndeducedAutoType())
+ return Unresolved;
+ }
// A call: approximate-resolve callee to a function type, get its return type
if (const CallExpr *CE = llvm::dyn_cast<CallExpr>(E)) {
QualType Callee = getApproximateType(CE->getCallee());
@@ -5542,6 +5586,13 @@ QualType getApproximateType(const Expr *E) {
}
}
}
+ // A reference to an `auto` variable: approximate-resolve its initializer.
+ if (const auto *DRE = llvm::dyn_cast<DeclRefExpr>(E)) {
+ if (const auto *VD = llvm::dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (VD->hasInit())
+ return getApproximateType(VD->getInit());
+ }
+ }
return Unresolved;
}
@@ -5600,7 +5651,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
&ResultBuilder::IsMember);
auto DoCompletion = [&](Expr *Base, bool IsArrow,
- Optional<FixItHint> AccessOpFixIt) -> bool {
+ std::optional<FixItHint> AccessOpFixIt) -> bool {
if (!Base)
return false;
@@ -5698,7 +5749,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
Results.EnterNewScope();
- bool CompletionSucceded = DoCompletion(Base, IsArrow, None);
+ bool CompletionSucceded = DoCompletion(Base, IsArrow, std::nullopt);
if (CodeCompleter->includeFixIts()) {
const CharSourceRange OpRange =
CharSourceRange::getTokenRange(OpLoc, OpLoc);
@@ -6157,8 +6208,8 @@ QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args,
// Only aggregate initialization is possible, but we can't assist with it.
// Returns an out-of-range index.
// - we saw no designators, just positional arguments.
-// Returns None.
-static llvm::Optional<unsigned>
+// Returns std::nullopt.
+static std::optional<unsigned>
getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate,
ArrayRef<Expr *> Args) {
static constexpr unsigned Invalid = std::numeric_limits<unsigned>::max();
@@ -6183,7 +6234,7 @@ getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate,
}
}
if (!DesignatedFieldName)
- return llvm::None;
+ return std::nullopt;
// Find the index within the class's fields.
// (Probing getParamDecl() directly would be quadratic in number of fields).
@@ -7537,7 +7588,8 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) {
Results.EnterNewScope();
VisitedSelectorSet Selectors;
- AddObjCMethods(Class, true, MK_ZeroArgSelector, None, CurContext, Selectors,
+ AddObjCMethods(Class, true, MK_ZeroArgSelector, std::nullopt, CurContext,
+ Selectors,
/*AllowSameLength=*/true, Results);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(),
@@ -7563,7 +7615,8 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) {
Results.EnterNewScope();
VisitedSelectorSet Selectors;
- AddObjCMethods(Class, true, MK_OneArgSelector, None, CurContext, Selectors,
+ AddObjCMethods(Class, true, MK_OneArgSelector, std::nullopt, CurContext,
+ Selectors,
/*AllowSameLength=*/true, Results);
Results.ExitScope();
@@ -7859,7 +7912,8 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
if (Iface->getSuperClass()) {
Results.AddResult(Result("super"));
- AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, None, Results);
+ AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, std::nullopt,
+ Results);
}
if (getLangOpts().CPlusPlus11)
@@ -8505,7 +8559,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCCategoryName);
- // Add all of the categories that have have corresponding interface
+ // Add all of the categories that have corresponding interface
// declarations in this class and any of its superclasses, except for
// already-implemented categories in the class itself.
llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
@@ -8669,7 +8723,7 @@ typedef llvm::DenseMap<Selector,
/// indexed by selector so they can be easily found.
static void FindImplementableMethods(ASTContext &Context,
ObjCContainerDecl *Container,
- Optional<bool> WantInstanceMethods,
+ std::optional<bool> WantInstanceMethods,
QualType ReturnType,
KnownMethodsMap &KnownMethods,
bool InOriginalClass = true) {
@@ -9393,7 +9447,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
}
}
-void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod,
+void Sema::CodeCompleteObjCMethodDecl(Scope *S,
+ std::optional<bool> IsInstanceMethod,
ParsedType ReturnTy) {
// Determine the return type of the method we're declaring, if
// provided.
@@ -9978,10 +10033,10 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) {
break;
case llvm::sys::fs::file_type::regular_file: {
// Only files that really look like headers. (Except in special dirs).
- // Header extensions from Types.def, which we can't depend on here.
const bool IsHeader = Filename.endswith_insensitive(".h") ||
Filename.endswith_insensitive(".hh") ||
Filename.endswith_insensitive(".hpp") ||
+ Filename.endswith_insensitive(".hxx") ||
Filename.endswith_insensitive(".inc") ||
(ExtensionlessHeaders && !Filename.contains('.'));
if (!IsHeader)
@@ -10048,7 +10103,7 @@ void Sema::CodeCompleteAvailabilityPlatformName() {
CodeCompletionContext::CCC_Other);
Results.EnterNewScope();
static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"};
- for (const char *Platform : llvm::makeArrayRef(Platforms)) {
+ for (const char *Platform : llvm::ArrayRef(Platforms)) {
Results.AddResult(CodeCompletionResult(Platform));
Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString(
Twine(Platform) + "ApplicationExtension")));
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 239e5dc4394c..4d4b2482d046 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TreeTransform.h"
#include "clang/Sema/SemaConcept.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
@@ -18,18 +19,21 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Initialization.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
using namespace clang;
using namespace sema;
namespace {
class LogicalBinOp {
+ SourceLocation Loc;
OverloadedOperatorKind Op = OO_None;
const Expr *LHS = nullptr;
const Expr *RHS = nullptr;
@@ -40,12 +44,14 @@ public:
Op = BinaryOperator::getOverloadedOperator(BO->getOpcode());
LHS = BO->getLHS();
RHS = BO->getRHS();
+ Loc = BO->getExprLoc();
} else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) {
// If OO is not || or && it might not have exactly 2 arguments.
if (OO->getNumArgs() == 2) {
Op = OO->getOperator();
LHS = OO->getArg(0);
RHS = OO->getArg(1);
+ Loc = OO->getOperatorLoc();
}
}
}
@@ -56,6 +62,26 @@ public:
const Expr *getLHS() const { return LHS; }
const Expr *getRHS() const { return RHS; }
+
+ ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) const {
+ return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS()));
+ }
+
+ ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS,
+ ExprResult RHS) const {
+ assert((isAnd() || isOr()) && "Not the right kind of op?");
+ assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?");
+
+ if (!LHS.isUsable() || !RHS.isUsable())
+ return ExprEmpty();
+
+ // We should just be able to 'normalize' these to the builtin Binary
+ // Operator, since that is how they are evaluated in constriant checks.
+ return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(),
+ BinaryOperator::getOverloadedOpcode(Op),
+ SemaRef.Context.BoolTy, VK_PRValue,
+ OK_Ordinary, Loc, FPOptionsOverride{});
+ }
};
}
@@ -121,17 +147,30 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
return true;
}
+namespace {
+struct SatisfactionStackRAII {
+ Sema &SemaRef;
+ SatisfactionStackRAII(Sema &SemaRef, llvm::FoldingSetNodeID FSNID)
+ : SemaRef(SemaRef) {
+ SemaRef.PushSatisfactionStackEntry(FSNID);
+ }
+ ~SatisfactionStackRAII() { SemaRef.PopSatisfactionStackEntry(); }
+};
+} // namespace
+
template <typename AtomicEvaluator>
-static bool
+static ExprResult
calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction,
AtomicEvaluator &&Evaluator) {
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
if (LogicalBinOp BO = ConstraintExpr) {
- if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction,
- Evaluator))
- return true;
+ ExprResult LHSRes = calculateConstraintSatisfaction(
+ S, BO.getLHS(), Satisfaction, Evaluator);
+
+ if (LHSRes.isInvalid())
+ return ExprError();
bool IsLHSSatisfied = Satisfaction.IsSatisfied;
@@ -142,7 +181,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
// is checked. If that is satisfied, the disjunction is satisfied.
// Otherwise, the disjunction is satisfied if and only if the second
// operand is satisfied.
- return false;
+ // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+ return LHSRes;
if (BO.isAnd() && !IsLHSSatisfied)
// [temp.constr.op] p2
@@ -151,12 +191,22 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
// is checked. If that is not satisfied, the conjunction is not
// satisfied. Otherwise, the conjunction is satisfied if and only if
// the second operand is satisfied.
- return false;
+ // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+ return LHSRes;
- return calculateConstraintSatisfaction(
+ ExprResult RHSRes = calculateConstraintSatisfaction(
S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
- } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
- return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
+ if (RHSRes.isInvalid())
+ return ExprError();
+
+ return BO.recreateBinOp(S, LHSRes, RHSRes);
+ }
+
+ if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
+ // These aren't evaluated, so we don't care about cleanups, so we can just
+ // evaluate these as if the cleanups didn't exist.
+ return calculateConstraintSatisfaction(
+ S, C->getSubExpr(), Satisfaction,
std::forward<AtomicEvaluator>(Evaluator));
}
@@ -164,11 +214,35 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr);
if (SubstitutedAtomicExpr.isInvalid())
- return true;
+ return ExprError();
if (!SubstitutedAtomicExpr.isUsable())
// Evaluator has decided satisfaction without yielding an expression.
- return false;
+ return ExprEmpty();
+
+ // We don't have the ability to evaluate this, since it contains a
+ // RecoveryExpr, so we want to fail overload resolution. Otherwise,
+ // we'd potentially pick up a different overload, and cause confusing
+ // diagnostics. SO, add a failure detail that will cause us to make this
+ // overload set not viable.
+ if (SubstitutedAtomicExpr.get()->containsErrors()) {
+ Satisfaction.IsSatisfied = false;
+ Satisfaction.ContainsErrors = true;
+
+ PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error);
+ SmallString<128> DiagString;
+ DiagString = ": ";
+ Msg.EmitToString(S.getDiagnostics(), DiagString);
+ unsigned MessageSize = DiagString.size();
+ char *Mem = new (S.Context) char[MessageSize];
+ memcpy(Mem, DiagString.c_str(), MessageSize);
+ Satisfaction.Details.emplace_back(
+ ConstraintExpr,
+ new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+ SubstitutedAtomicExpr.get()->getBeginLoc(),
+ StringRef(Mem, MessageSize)});
+ return SubstitutedAtomicExpr;
+ }
EnterExpressionEvaluationContext ConstantEvaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
@@ -185,7 +259,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
<< SubstitutedAtomicExpr.get()->getSourceRange();
for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
S.Diag(PDiag.first, PDiag.second);
- return true;
+ return ExprError();
}
assert(EvalResult.Val.isInt() &&
@@ -195,17 +269,41 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
Satisfaction.Details.emplace_back(ConstraintExpr,
SubstitutedAtomicExpr.get());
+ return SubstitutedAtomicExpr;
+}
+
+static bool
+DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID, const Expr *E,
+ const MultiLevelTemplateArgumentList &MLTAL) {
+ E->Profile(ID, S.Context, /*Canonical=*/true);
+ for (const auto &List : MLTAL)
+ for (const auto &TemplateArg : List.Args)
+ TemplateArg.Profile(ID, S.Context);
+
+ // Note that we have to do this with our own collection, because there are
+ // times where a constraint-expression check can cause us to need to evaluate
+ // other constriants that are unrelated, such as when evaluating a recovery
+ // expression, or when trying to determine the constexpr-ness of special
+ // members. Otherwise we could just use the
+ // Sema::InstantiatingTemplate::isAlreadyBeingInstantiated function.
+ if (S.SatisfactionStackContains(ID)) {
+ S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self)
+ << const_cast<Expr *>(E) << E->getSourceRange();
+ return true;
+ }
+
return false;
}
-static bool calculateConstraintSatisfaction(
- Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
- SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL,
- const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) {
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
+ const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
EnterExpressionEvaluationContext ConstantEvaluated(
- S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ Sema::ReuseLambdaContextDecl);
// Atomic constraint - substitute arguments and check satisfaction.
ExprResult SubstitutedExpression;
@@ -217,17 +315,21 @@ static bool calculateConstraintSatisfaction(
AtomicExpr->getSourceRange());
if (Inst.isInvalid())
return ExprError();
+
+ llvm::FoldingSetNodeID ID;
+ if (DiagRecursiveConstraintEval(S, ID, AtomicExpr, MLTAL)) {
+ Satisfaction.IsSatisfied = false;
+ Satisfaction.ContainsErrors = true;
+ return ExprEmpty();
+ }
+
+ SatisfactionStackRAII StackRAII(S, ID);
+
// We do not want error diagnostics escaping here.
Sema::SFINAETrap Trap(S);
- SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr),
- MLTAL);
- // Substitution might have stripped off a contextual conversion to
- // bool if this is the operand of an '&&' or '||'. For example, we
- // might lose an lvalue-to-rvalue conversion here. If so, put it back
- // before we try to evaluate.
- if (!SubstitutedExpression.isInvalid())
- SubstitutedExpression =
- S.PerformContextuallyConvertToBool(SubstitutedExpression.get());
+ SubstitutedExpression =
+ S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
+
if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) {
// C++2a [temp.constr.atomic]p1
// ...If substitution results in an invalid type or expression, the
@@ -264,78 +366,129 @@ static bool calculateConstraintSatisfaction(
if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
return ExprError();
+ // [temp.constr.atomic]p3: To determine if an atomic constraint is
+ // satisfied, the parameter mapping and template arguments are first
+ // substituted into its expression. If substitution results in an
+ // invalid type or expression, the constraint is not satisfied.
+ // Otherwise, the lvalue-to-rvalue conversion is performed if necessary,
+ // and E shall be a constant expression of type bool.
+ //
+ // Perform the L to R Value conversion if necessary. We do so for all
+ // non-PRValue categories, else we fail to extend the lifetime of
+ // temporaries, and that fails the constant expression check.
+ if (!SubstitutedExpression.get()->isPRValue())
+ SubstitutedExpression = ImplicitCastExpr::Create(
+ S.Context, SubstitutedExpression.get()->getType(),
+ CK_LValueToRValue, SubstitutedExpression.get(),
+ /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride());
+
return SubstitutedExpression;
});
}
-static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template,
- ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs,
- SourceRange TemplateIDRange,
- ConstraintSatisfaction &Satisfaction) {
+static bool CheckConstraintSatisfaction(
+ Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
+ llvm::SmallVectorImpl<Expr *> &Converted,
+ const MultiLevelTemplateArgumentList &TemplateArgsLists,
+ SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) {
if (ConstraintExprs.empty()) {
Satisfaction.IsSatisfied = true;
return false;
}
- for (auto& Arg : TemplateArgs)
- if (Arg.isInstantiationDependent()) {
- // No need to check satisfaction for dependent constraint expressions.
- Satisfaction.IsSatisfied = true;
- return false;
- }
+ if (TemplateArgsLists.isAnyArgInstantiationDependent()) {
+ // No need to check satisfaction for dependent constraint expressions.
+ Satisfaction.IsSatisfied = true;
+ return false;
+ }
+ ArrayRef<TemplateArgument> TemplateArgs =
+ TemplateArgsLists.getNumSubstitutedLevels() > 0
+ ? TemplateArgsLists.getOutermost()
+ : ArrayRef<TemplateArgument> {};
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
if (Inst.isInvalid())
return true;
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(TemplateArgs);
-
for (const Expr *ConstraintExpr : ConstraintExprs) {
- if (calculateConstraintSatisfaction(S, Template, TemplateArgs,
- TemplateIDRange.getBegin(), MLTAL,
- ConstraintExpr, Satisfaction))
+ ExprResult Res = calculateConstraintSatisfaction(
+ S, Template, TemplateIDRange.getBegin(), TemplateArgsLists,
+ ConstraintExpr, Satisfaction);
+ if (Res.isInvalid())
return true;
- if (!Satisfaction.IsSatisfied)
+
+ Converted.push_back(Res.get());
+ if (!Satisfaction.IsSatisfied) {
+ // Backfill the 'converted' list with nulls so we can keep the Converted
+ // and unconverted lists in sync.
+ Converted.append(ConstraintExprs.size() - Converted.size(), nullptr);
// [temp.constr.op] p2
- // [...] To determine if a conjunction is satisfied, the satisfaction
- // of the first operand is checked. If that is not satisfied, the
- // conjunction is not satisfied. [...]
+ // [...] To determine if a conjunction is satisfied, the satisfaction
+ // of the first operand is checked. If that is not satisfied, the
+ // conjunction is not satisfied. [...]
return false;
+ }
}
return false;
}
bool Sema::CheckConstraintSatisfaction(
const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs,
- ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange,
- ConstraintSatisfaction &OutSatisfaction) {
+ llvm::SmallVectorImpl<Expr *> &ConvertedConstraints,
+ const MultiLevelTemplateArgumentList &TemplateArgsLists,
+ SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) {
if (ConstraintExprs.empty()) {
OutSatisfaction.IsSatisfied = true;
return false;
}
if (!Template) {
- return ::CheckConstraintSatisfaction(*this, nullptr, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- OutSatisfaction);
+ return ::CheckConstraintSatisfaction(
+ *this, nullptr, ConstraintExprs, ConvertedConstraints,
+ TemplateArgsLists, TemplateIDRange, OutSatisfaction);
}
+
+ // A list of the template argument list flattened in a predictible manner for
+ // the purposes of caching. The ConstraintSatisfaction type is in AST so it
+ // has no access to the MultiLevelTemplateArgumentList, so this has to happen
+ // here.
+ llvm::SmallVector<TemplateArgument, 4> FlattenedArgs;
+ for (auto List : TemplateArgsLists)
+ FlattenedArgs.insert(FlattenedArgs.end(), List.Args.begin(),
+ List.Args.end());
+
llvm::FoldingSetNodeID ID;
- ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs);
+ ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
void *InsertPos;
if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
OutSatisfaction = *Cached;
return false;
}
+
auto Satisfaction =
- std::make_unique<ConstraintSatisfaction>(Template, TemplateArgs);
+ std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs);
if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs,
- TemplateArgs, TemplateIDRange,
- *Satisfaction)) {
+ ConvertedConstraints, TemplateArgsLists,
+ TemplateIDRange, *Satisfaction)) {
+ OutSatisfaction = *Satisfaction;
return true;
}
+
+ if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) {
+ // The evaluation of this constraint resulted in us trying to re-evaluate it
+ // recursively. This isn't really possible, except we try to form a
+ // RecoveryExpr as a part of the evaluation. If this is the case, just
+ // return the 'cached' version (which will have the same result), and save
+ // ourselves the extra-insert. If it ever becomes possible to legitimately
+ // recursively check a constraint, we should skip checking the 'inner' one
+ // above, and replace the cached version with this one, as it would be more
+ // specific.
+ OutSatisfaction = *Cached;
+ return false;
+ }
+
+ // Else we can simply add this satisfaction to the list.
OutSatisfaction = *Satisfaction;
// We cannot use InsertPos here because CheckConstraintSatisfaction might have
// invalidated it.
@@ -347,21 +500,133 @@ bool Sema::CheckConstraintSatisfaction(
bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction) {
return calculateConstraintSatisfaction(
- *this, ConstraintExpr, Satisfaction,
- [this](const Expr *AtomicExpr) -> ExprResult {
- // We only do this to immitate lvalue-to-rvalue conversion.
- return PerformContextuallyConvertToBool(const_cast<Expr *>(AtomicExpr));
- });
+ *this, ConstraintExpr, Satisfaction,
+ [this](const Expr *AtomicExpr) -> ExprResult {
+ // We only do this to immitate lvalue-to-rvalue conversion.
+ return PerformContextuallyConvertToBool(
+ const_cast<Expr *>(AtomicExpr));
+ })
+ .isInvalid();
+}
+
+bool Sema::SetupConstraintScope(
+ FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+ MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) {
+ if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) {
+ FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
+ InstantiatingTemplate Inst(
+ *this, FD->getPointOfInstantiation(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate,
+ TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+ SourceRange());
+ if (Inst.isInvalid())
+ return true;
+
+ // addInstantiatedParametersToScope creates a map of 'uninstantiated' to
+ // 'instantiated' parameters and adds it to the context. For the case where
+ // this function is a template being instantiated NOW, we also need to add
+ // the list of current template arguments to the list so that they also can
+ // be picked out of the map.
+ if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) {
+ MultiLevelTemplateArgumentList JustTemplArgs(FD, SpecArgs->asArray(),
+ /*Final=*/false);
+ if (addInstantiatedParametersToScope(
+ FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs))
+ return true;
+ }
+
+ // If this is a member function, make sure we get the parameters that
+ // reference the original primary template.
+ if (const auto *FromMemTempl =
+ PrimaryTemplate->getInstantiatedFromMemberTemplate()) {
+ if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(),
+ Scope, MLTAL))
+ return true;
+ }
+
+ return false;
+ }
+
+ if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
+ FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) {
+ FunctionDecl *InstantiatedFrom =
+ FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization
+ ? FD->getInstantiatedFromMemberFunction()
+ : FD->getInstantiatedFromDecl();
+
+ InstantiatingTemplate Inst(
+ *this, FD->getPointOfInstantiation(),
+ Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom,
+ TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{},
+ SourceRange());
+ if (Inst.isInvalid())
+ return true;
+
+ // Case where this was not a template, but instantiated as a
+ // child-function.
+ if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL))
+ return true;
+ }
+
+ return false;
+}
+
+// This function collects all of the template arguments for the purposes of
+// constraint-instantiation and checking.
+std::optional<MultiLevelTemplateArgumentList>
+Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
+ FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs,
+ LocalInstantiationScope &Scope) {
+ MultiLevelTemplateArgumentList MLTAL;
+
+ // Collect the list of template arguments relative to the 'primary' template.
+ // We need the entire list, since the constraint is completely uninstantiated
+ // at this point.
+ MLTAL =
+ getTemplateInstantiationArgs(FD, /*Final=*/false, /*Innermost=*/nullptr,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
+ if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
+ return std::nullopt;
+
+ return MLTAL;
}
bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
ConstraintSatisfaction &Satisfaction,
- SourceLocation UsageLoc) {
- const Expr *RC = FD->getTrailingRequiresClause();
- if (RC->isInstantiationDependent()) {
+ SourceLocation UsageLoc,
+ bool ForOverloadResolution) {
+ // Don't check constraints if the function is dependent. Also don't check if
+ // this is a function template specialization, as the call to
+ // CheckinstantiatedFunctionTemplateConstraints after this will check it
+ // better.
+ if (FD->isDependentContext() ||
+ FD->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization) {
Satisfaction.IsSatisfied = true;
return false;
}
+
+ DeclContext *CtxToSave = const_cast<FunctionDecl *>(FD);
+
+ while (isLambdaCallOperator(CtxToSave) || FD->isTransparentContext()) {
+ if (isLambdaCallOperator(CtxToSave))
+ CtxToSave = CtxToSave->getParent()->getParent();
+ else
+ CtxToSave = CtxToSave->getNonTransparentContext();
+ }
+
+ ContextRAII SavedContext{*this, CtxToSave};
+ LocalInstantiationScope Scope(*this, !ForOverloadResolution ||
+ isLambdaCallOperator(FD));
+ std::optional<MultiLevelTemplateArgumentList> MLTAL =
+ SetupConstraintCheckingTemplateArgumentsAndScope(
+ const_cast<FunctionDecl *>(FD), {}, Scope);
+
+ if (!MLTAL)
+ return true;
+
Qualifiers ThisQuals;
CXXRecordDecl *Record = nullptr;
if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
@@ -372,19 +637,124 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
// We substitute with empty arguments in order to rebuild the atomic
// constraint in a constant-evaluated context.
// FIXME: Should this be a dedicated TreeTransform?
- return CheckConstraintSatisfaction(
- FD, {RC}, /*TemplateArgs=*/{},
- SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
- Satisfaction);
+ const Expr *RC = FD->getTrailingRequiresClause();
+ llvm::SmallVector<Expr *, 1> Converted;
+
+ if (CheckConstraintSatisfaction(
+ FD, {RC}, Converted, *MLTAL,
+ SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()),
+ Satisfaction))
+ return true;
+
+ // FIXME: we need to do this for the function constraints for
+ // comparison of constraints to work, but do we also need to do it for
+ // CheckInstantiatedFunctionConstraints? That one is more difficult, but we
+ // seem to always just pick up the constraints from the primary template.
+ assert(Converted.size() <= 1 && "Got more expressions converted?");
+ if (!Converted.empty() && Converted[0] != nullptr)
+ const_cast<FunctionDecl *>(FD)->setTrailingRequiresClause(Converted[0]);
+ return false;
+}
+
+
+// Figure out the to-translation-unit depth for this function declaration for
+// the purpose of seeing if they differ by constraints. This isn't the same as
+// getTemplateDepth, because it includes already instantiated parents.
+static unsigned
+CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
+ bool SkipForSpecialization = false) {
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ ND, /*Final=*/false, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true, SkipForSpecialization);
+ return MLTAL.getNumSubstitutedLevels();
+}
+
+namespace {
+ class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> {
+ unsigned TemplateDepth = 0;
+ public:
+ using inherited = TreeTransform<AdjustConstraintDepth>;
+ AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth)
+ : inherited(SemaRef), TemplateDepth(TemplateDepth) {}
+
+ using inherited::TransformTemplateTypeParmType;
+ QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+ TemplateTypeParmTypeLoc TL, bool) {
+ const TemplateTypeParmType *T = TL.getTypePtr();
+
+ TemplateTypeParmDecl *NewTTPDecl = nullptr;
+ if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
+ NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
+ TransformDecl(TL.getNameLoc(), OldTTPDecl));
+
+ QualType Result = getSema().Context.getTemplateTypeParmType(
+ T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(),
+ NewTTPDecl);
+ TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ return Result;
+ }
+ };
+} // namespace
+
+bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
+ const Expr *OldConstr,
+ const NamedDecl *New,
+ const Expr *NewConstr) {
+ if (Old && New && Old != New) {
+ unsigned Depth1 = CalculateTemplateDepthForConstraints(
+ *this, Old);
+ unsigned Depth2 = CalculateTemplateDepthForConstraints(
+ *this, New);
+
+ // Adjust the 'shallowest' verison of this to increase the depth to match
+ // the 'other'.
+ if (Depth2 > Depth1) {
+ OldConstr = AdjustConstraintDepth(*this, Depth2 - Depth1)
+ .TransformExpr(const_cast<Expr *>(OldConstr))
+ .get();
+ } else if (Depth1 > Depth2) {
+ NewConstr = AdjustConstraintDepth(*this, Depth1 - Depth2)
+ .TransformExpr(const_cast<Expr *>(NewConstr))
+ .get();
+ }
+ }
+
+ llvm::FoldingSetNodeID ID1, ID2;
+ OldConstr->Profile(ID1, Context, /*Canonical=*/true);
+ NewConstr->Profile(ID2, Context, /*Canonical=*/true);
+ return ID1 == ID2;
+}
+
+bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
+ assert(FD->getFriendObjectKind() && "Must be a friend!");
+
+ // The logic for non-templates is handled in ASTContext::isSameEntity, so we
+ // don't have to bother checking 'DependsOnEnclosingTemplate' for a
+ // non-function-template.
+ assert(FD->getDescribedFunctionTemplate() &&
+ "Non-function templates don't need to be checked");
+
+ SmallVector<const Expr *, 3> ACs;
+ FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
+
+ unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
+ for (const Expr *Constraint : ACs)
+ if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
+ Constraint))
+ return true;
+
+ return false;
}
bool Sema::EnsureTemplateArgumentListConstraints(
- TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs,
+ TemplateDecl *TD, const MultiLevelTemplateArgumentList &TemplateArgsLists,
SourceRange TemplateIDRange) {
ConstraintSatisfaction Satisfaction;
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
TD->getAssociatedConstraints(AssociatedConstraints);
- if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs,
+ if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgsLists,
TemplateIDRange, Satisfaction))
return true;
@@ -392,7 +762,8 @@ bool Sema::EnsureTemplateArgumentListConstraints(
SmallString<128> TemplateArgString;
TemplateArgString = " ";
TemplateArgString += getTemplateArgumentBindingsText(
- TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
+ TD->getTemplateParameters(), TemplateArgsLists.getInnermost().data(),
+ TemplateArgsLists.getInnermost().size());
Diag(TemplateIDRange.getBegin(),
diag::err_template_arg_list_constraints_not_satisfied)
@@ -424,21 +795,13 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
- // If this is not an explicit specialization - we need to get the instantiated
- // version of the template arguments and add them to scope for the
- // substitution.
- if (Decl->isTemplateInstantiation()) {
- InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(),
- InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(),
- TemplateArgs, SourceRange());
- if (Inst.isInvalid())
- return true;
- MultiLevelTemplateArgumentList MLTAL(
- *Decl->getTemplateSpecializationArgs());
- if (addInstantiatedParametersToScope(
- Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL))
- return true;
- }
+ std::optional<MultiLevelTemplateArgumentList> MLTAL =
+ SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs,
+ Scope);
+
+ if (!MLTAL)
+ return true;
+
Qualifiers ThisQuals;
CXXRecordDecl *Record = nullptr;
if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
@@ -446,7 +809,14 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
Record = Method->getParent();
}
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
- return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs,
+ FunctionScopeRAII FuncScope(*this);
+ if (isLambdaCallOperator(Decl))
+ PushLambdaScope();
+ else
+ FuncScope.disable();
+
+ llvm::SmallVector<Expr *, 1> Converted;
+ return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
PointOfInstantiation, Satisfaction);
}
@@ -541,31 +911,28 @@ static void diagnoseUnsatisfiedRequirement(Sema &S,
return;
}
}
+static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
+ Expr *SubstExpr,
+ bool First = true);
static void diagnoseUnsatisfiedRequirement(Sema &S,
concepts::NestedRequirement *Req,
bool First) {
- if (Req->isSubstitutionFailure()) {
- concepts::Requirement::SubstitutionDiagnostic *SubstDiag =
- Req->getSubstitutionDiagnostic();
- if (!SubstDiag->DiagMessage.empty())
- S.Diag(SubstDiag->DiagLoc,
- diag::note_nested_requirement_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity
- << SubstDiag->DiagMessage;
+ using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
+ for (auto &Pair : Req->getConstraintSatisfaction()) {
+ if (auto *SubstDiag = Pair.second.dyn_cast<SubstitutionDiagnostic *>())
+ S.Diag(SubstDiag->first, diag::note_nested_requirement_substitution_error)
+ << (int)First << Req->getInvalidConstraintEntity() << SubstDiag->second;
else
- S.Diag(SubstDiag->DiagLoc,
- diag::note_nested_requirement_unknown_substitution_error)
- << (int)First << SubstDiag->SubstitutedEntity;
- return;
+ diagnoseWellFormedUnsatisfiedConstraintExpr(
+ S, Pair.second.dyn_cast<Expr *>(), First);
+ First = false;
}
- S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First);
}
-
static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
Expr *SubstExpr,
- bool First = true) {
+ bool First) {
SubstExpr = SubstExpr->IgnoreParenImpCasts();
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) {
switch (BO->getOpcode()) {
@@ -645,6 +1012,7 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S,
S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction());
return;
} else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) {
+ // FIXME: RequiresExpr should store dependent diagnostics.
for (concepts::Requirement *Req : RE->getRequirements())
if (!Req->isDependent() && !Req->isSatisfied()) {
if (auto *E = dyn_cast<concepts::ExprRequirement>(Req))
@@ -721,34 +1089,33 @@ Sema::getNormalizedAssociatedConstraints(
return CacheEntry->second;
}
-static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
- ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs,
- const ASTTemplateArgumentListInfo *ArgsAsWritten) {
+static bool
+substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ ConceptDecl *Concept,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten) {
if (!N.isAtomic()) {
- if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs,
+ if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL,
ArgsAsWritten))
return true;
- return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs,
+ return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL,
ArgsAsWritten);
}
TemplateParameterList *TemplateParams = Concept->getTemplateParameters();
AtomicConstraint &Atomic = *N.getAtomicConstraint();
TemplateArgumentListInfo SubstArgs;
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(TemplateArgs);
if (!Atomic.ParameterMapping) {
llvm::SmallBitVector OccurringIndices(TemplateParams->size());
S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false,
/*Depth=*/0, OccurringIndices);
- Atomic.ParameterMapping.emplace(
- MutableArrayRef<TemplateArgumentLoc>(
- new (S.Context) TemplateArgumentLoc[OccurringIndices.count()],
- OccurringIndices.count()));
+ TemplateArgumentLoc *TempArgs =
+ new (S.Context) TemplateArgumentLoc[OccurringIndices.count()];
for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I)
if (OccurringIndices[I])
- new (&(*Atomic.ParameterMapping)[J++]) TemplateArgumentLoc(
- S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I],
+ new (&(TempArgs)[J++])
+ TemplateArgumentLoc(S.getIdentityTemplateArgumentLoc(
+ TemplateParams->begin()[I],
// Here we assume we do not support things like
// template<typename A, typename B>
// concept C = ...;
@@ -757,9 +1124,10 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
// struct S { };
// The above currently yields a diagnostic.
// We still might have default arguments for concept parameters.
- ArgsAsWritten->NumTemplateArgs > I ?
- ArgsAsWritten->arguments()[I].getLocation() :
- SourceLocation()));
+ ArgsAsWritten->NumTemplateArgs > I
+ ? ArgsAsWritten->arguments()[I].getLocation()
+ : SourceLocation()));
+ Atomic.ParameterMapping.emplace(TempArgs, OccurringIndices.count());
}
Sema::InstantiatingTemplate Inst(
S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(),
@@ -768,33 +1136,47 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
ArgsAsWritten->arguments().back().getSourceRange().getEnd()));
if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs))
return true;
- Atomic.ParameterMapping.emplace(
- MutableArrayRef<TemplateArgumentLoc>(
- new (S.Context) TemplateArgumentLoc[SubstArgs.size()],
- SubstArgs.size()));
+
+ TemplateArgumentLoc *TempArgs =
+ new (S.Context) TemplateArgumentLoc[SubstArgs.size()];
std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(),
- N.getAtomicConstraint()->ParameterMapping->begin());
+ TempArgs);
+ Atomic.ParameterMapping.emplace(TempArgs, SubstArgs.size());
return false;
}
-Optional<NormalizedConstraint>
+static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
+ const ConceptSpecializationExpr *CSE) {
+ TemplateArgumentList TAL{TemplateArgumentList::OnStack,
+ CSE->getTemplateArguments()};
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ CSE->getNamedConcept(), /*Final=*/false, &TAL,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true);
+
+ return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
+ CSE->getTemplateArgsAsWritten());
+}
+
+std::optional<NormalizedConstraint>
NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
ArrayRef<const Expr *> E) {
assert(E.size() != 0);
auto Conjunction = fromConstraintExpr(S, D, E[0]);
if (!Conjunction)
- return None;
+ return std::nullopt;
for (unsigned I = 1; I < E.size(); ++I) {
auto Next = fromConstraintExpr(S, D, E[I]);
if (!Next)
- return None;
+ return std::nullopt;
*Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction),
std::move(*Next), CCK_Conjunction);
}
return Conjunction;
}
-llvm::Optional<NormalizedConstraint>
+std::optional<NormalizedConstraint>
NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
assert(E != nullptr);
@@ -803,13 +1185,19 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
// - The normal form of an expression (E) is the normal form of E.
// [...]
E = E->IgnoreParenImpCasts();
+
+ // C++2a [temp.param]p4:
+ // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
+ // Fold expression is considered atomic constraints per current wording.
+ // See http://cplusplus.github.io/concepts-ts/ts-active.html#28
+
if (LogicalBinOp BO = E) {
auto LHS = fromConstraintExpr(S, D, BO.getLHS());
if (!LHS)
- return None;
+ return std::nullopt;
auto RHS = fromConstraintExpr(S, D, BO.getRHS());
if (!RHS)
- return None;
+ return std::nullopt;
return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS),
BO.isAnd() ? CCK_Conjunction : CCK_Disjunction);
@@ -833,16 +1221,14 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) {
SubNF = S.getNormalizedAssociatedConstraints(CD,
{CD->getConstraintExpr()});
if (!SubNF)
- return None;
+ return std::nullopt;
}
- Optional<NormalizedConstraint> New;
+ std::optional<NormalizedConstraint> New;
New.emplace(S.Context, *SubNF);
- if (substituteParameterMappings(
- S, *New, CSE->getNamedConcept(),
- CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten()))
- return None;
+ if (substituteParameterMappings(S, *New, CSE))
+ return std::nullopt;
return New;
}
@@ -965,9 +1351,26 @@ static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P,
return false;
}
-bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
- NamedDecl *D2, ArrayRef<const Expr *> AC2,
+bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
+ MutableArrayRef<const Expr *> AC1,
+ NamedDecl *D2,
+ MutableArrayRef<const Expr *> AC2,
bool &Result) {
+ if (const auto *FD1 = dyn_cast<FunctionDecl>(D1)) {
+ auto IsExpectedEntity = [](const FunctionDecl *FD) {
+ FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind();
+ return Kind == FunctionDecl::TK_NonTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplate;
+ };
+ const auto *FD2 = dyn_cast<FunctionDecl>(D2);
+ (void)IsExpectedEntity;
+ (void)FD1;
+ (void)FD2;
+ assert(IsExpectedEntity(FD1) && FD2 && IsExpectedEntity(FD2) &&
+ "use non-instantiated function declaration for constraints partial "
+ "ordering");
+ }
+
if (AC1.empty()) {
Result = AC2.empty();
return false;
@@ -985,6 +1388,21 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
return false;
}
+ unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
+ unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
+
+ for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
+ if (Depth2 > Depth1) {
+ AC1[I] = AdjustConstraintDepth(*this, Depth2 - Depth1)
+ .TransformExpr(const_cast<Expr *>(AC1[I]))
+ .get();
+ } else if (Depth1 > Depth2) {
+ AC2[I] = AdjustConstraintDepth(*this, Depth1 - Depth2)
+ .TransformExpr(const_cast<Expr *>(AC2[I]))
+ .get();
+ }
+ }
+
if (subsumes(*this, D1, AC1, D2, AC2, Result,
[this] (const AtomicConstraint &A, const AtomicConstraint &B) {
return A.subsumes(Context, B);
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index a738befdd6ce..79c08adb8fab 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -339,7 +339,7 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
// EvaluateBinaryTypeTrait(BTT_IsConvertible, ...) which is at the moment
// a private function in SemaExprCXX.cpp
- ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", None);
+ ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", std::nullopt);
if (AddressExpr.isInvalid())
return nullptr;
@@ -395,8 +395,8 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
return Result.get();
};
- CallExpr *AwaitReady =
- cast_or_null<CallExpr>(BuildSubExpr(ACT::ACT_Ready, "await_ready", None));
+ CallExpr *AwaitReady = cast_or_null<CallExpr>(
+ BuildSubExpr(ACT::ACT_Ready, "await_ready", std::nullopt));
if (!AwaitReady)
return Calls;
if (!AwaitReady->getType()->isDependentType()) {
@@ -457,7 +457,7 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise,
}
}
- BuildSubExpr(ACT::ACT_Resume, "await_resume", None);
+ BuildSubExpr(ACT::ACT_Resume, "await_resume", std::nullopt);
// Make sure the awaiter object gets a chance to be cleaned up.
S.Cleanup.setExprNeedsCleanups(true);
@@ -705,8 +705,8 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc,
SourceLocation Loc = Fn->getLocation();
// Build the initial suspend point
auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
- ExprResult Operand =
- buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None);
+ ExprResult Operand = buildPromiseCall(*this, ScopeInfo->CoroutinePromise,
+ Loc, Name, std::nullopt);
if (Operand.isInvalid())
return StmtError();
ExprResult Suspend =
@@ -768,27 +768,34 @@ static bool isWithinCatchScope(Scope *S) {
// function-body *outside of a handler* [...] A context within a function
// where an await-expression can appear is called a suspension context of the
// function."
-static void checkSuspensionContext(Sema &S, SourceLocation Loc,
+static bool checkSuspensionContext(Sema &S, SourceLocation Loc,
StringRef Keyword) {
// First emphasis of [expr.await]p2: must be a potentially evaluated context.
// That is, 'co_await' and 'co_yield' cannot appear in subexpressions of
// \c sizeof.
- if (S.isUnevaluatedContext())
+ if (S.isUnevaluatedContext()) {
S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
+ return false;
+ }
// Second emphasis of [expr.await]p2: must be outside of an exception handler.
- if (isWithinCatchScope(S.getCurScope()))
+ if (isWithinCatchScope(S.getCurScope())) {
S.Diag(Loc, diag::err_coroutine_within_handler) << Keyword;
+ return false;
+ }
+
+ return true;
}
ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) {
+ if (!checkSuspensionContext(*this, Loc, "co_await"))
+ return ExprError();
+
if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
- checkSuspensionContext(*this, Loc, "co_await");
-
if (E->hasPlaceholderType()) {
ExprResult R = CheckPlaceholderExpr(E);
if (R.isInvalid()) return ExprError();
@@ -905,13 +912,14 @@ ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *Operand,
}
ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) {
+ if (!checkSuspensionContext(*this, Loc, "co_yield"))
+ return ExprError();
+
if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) {
CorrectDelayedTyposInExpr(E);
return ExprError();
}
- checkSuspensionContext(*this, Loc, "co_yield");
-
// Build yield_value call.
ExprResult Awaitable = buildPromiseCall(
*this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E);
@@ -989,7 +997,7 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E,
PC = buildPromiseCall(*this, Promise, Loc, "return_value", E);
} else {
E = MakeFullDiscardedValueExpr(E).get();
- PC = buildPromiseCall(*this, Promise, Loc, "return_void", None);
+ PC = buildPromiseCall(*this, Promise, Loc, "return_void", std::nullopt);
}
if (PC.isInvalid())
return StmtError();
@@ -1030,41 +1038,55 @@ static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) {
return DR.get();
}
-// Find an appropriate delete for the promise.
-static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc,
- QualType PromiseType) {
- FunctionDecl *OperatorDelete = nullptr;
+static TypeSourceInfo *getTypeSourceInfoForStdAlignValT(Sema &S,
+ SourceLocation Loc) {
+ EnumDecl *StdAlignValT = S.getStdAlignValT();
+ QualType StdAlignValDecl = S.Context.getTypeDeclType(StdAlignValT);
+ return S.Context.getTrivialTypeSourceInfo(StdAlignValDecl);
+}
+// Find an appropriate delete for the promise.
+static bool findDeleteForPromise(Sema &S, SourceLocation Loc, QualType PromiseType,
+ FunctionDecl *&OperatorDelete) {
DeclarationName DeleteName =
S.Context.DeclarationNames.getCXXOperatorName(OO_Delete);
auto *PointeeRD = PromiseType->getAsCXXRecordDecl();
assert(PointeeRD && "PromiseType must be a CxxRecordDecl type");
+ const bool Overaligned = S.getLangOpts().CoroAlignedAllocation;
+
// [dcl.fct.def.coroutine]p12
// The deallocation function's name is looked up by searching for it in the
// scope of the promise type. If nothing is found, a search is performed in
// the global scope.
- if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete))
- return nullptr;
+ if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete,
+ /*Diagnose*/ true, /*WantSize*/ true,
+ /*WantAligned*/ Overaligned))
+ return false;
- // FIXME: We didn't implement following selection:
// [dcl.fct.def.coroutine]p12
// If both a usual deallocation function with only a pointer parameter and a
// usual deallocation function with both a pointer parameter and a size
// parameter are found, then the selected deallocation function shall be the
// one with two parameters. Otherwise, the selected deallocation function
// shall be the function with one parameter.
-
if (!OperatorDelete) {
// Look for a global declaration.
- const bool CanProvideSize = S.isCompleteType(Loc, PromiseType);
- const bool Overaligned = false;
+ // Coroutines can always provide their required size.
+ const bool CanProvideSize = true;
+ // Sema::FindUsualDeallocationFunction will try to find the one with two
+ // parameters first. It will return the deallocation function with one
+ // parameter if failed.
OperatorDelete = S.FindUsualDeallocationFunction(Loc, CanProvideSize,
Overaligned, DeleteName);
+
+ if (!OperatorDelete)
+ return false;
}
+
S.MarkFunctionReferenced(Loc, OperatorDelete);
- return OperatorDelete;
+ return true;
}
@@ -1103,6 +1125,12 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
<< Fn->getFirstCoroutineStmtKeyword();
}
+
+ // Coroutines will get splitted into pieces. The GNU address of label
+ // extension wouldn't be meaningful in coroutines.
+ for (AddrLabelExpr *ALE : Fn->AddrLabels)
+ Diag(ALE->getBeginLoc(), diag::err_coro_invalid_addr_of_label);
+
CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body);
if (Builder.isInvalid() || !Builder.buildStatements())
return FD->setInvalidDecl();
@@ -1319,12 +1347,9 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// lvalue that denotes the parameter copy corresponding to p_i.
FunctionDecl *OperatorNew = nullptr;
- FunctionDecl *OperatorDelete = nullptr;
- FunctionDecl *UnusedResult = nullptr;
- bool PassAlignment = false;
SmallVector<Expr *, 1> PlacementArgs;
- bool PromiseContainsNew = [this, &PromiseType]() -> bool {
+ const bool PromiseContainsNew = [this, &PromiseType]() -> bool {
DeclarationName NewName =
S.getASTContext().DeclarationNames.getCXXOperatorName(OO_New);
LookupResult R(S, NewName, Loc, Sema::LookupOrdinaryName);
@@ -1335,19 +1360,29 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return !R.empty() && !R.isAmbiguous();
}();
- auto LookupAllocationFunction = [&]() {
+ // Helper function to indicate whether the last lookup found the aligned
+ // allocation function.
+ bool PassAlignment = S.getLangOpts().CoroAlignedAllocation;
+ auto LookupAllocationFunction = [&](Sema::AllocationFunctionScope NewScope =
+ Sema::AFS_Both,
+ bool WithoutPlacementArgs = false,
+ bool ForceNonAligned = false) {
// [dcl.fct.def.coroutine]p9
// The allocation function's name is looked up by searching for it in the
// scope of the promise type.
// - If any declarations are found, ...
// - If no declarations are found in the scope of the promise type, a search
// is performed in the global scope.
- Sema::AllocationFunctionScope NewScope =
- PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global;
- S.FindAllocationFunctions(Loc, SourceRange(),
- NewScope,
+ if (NewScope == Sema::AFS_Both)
+ NewScope = PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global;
+
+ PassAlignment = !ForceNonAligned && S.getLangOpts().CoroAlignedAllocation;
+ FunctionDecl *UnusedResult = nullptr;
+ S.FindAllocationFunctions(Loc, SourceRange(), NewScope,
/*DeleteScope*/ Sema::AFS_Both, PromiseType,
- /*isArray*/ false, PassAlignment, PlacementArgs,
+ /*isArray*/ false, PassAlignment,
+ WithoutPlacementArgs ? MultiExprArg{}
+ : PlacementArgs,
OperatorNew, UnusedResult, /*Diagnose*/ false);
};
@@ -1359,15 +1394,58 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
LookupAllocationFunction();
- // [dcl.fct.def.coroutine]p9
- // If no viable function is found ([over.match.viable]), overload resolution
- // is performed again on a function call created by passing just the amount of
- // space required as an argument of type std::size_t.
- if (!OperatorNew && !PlacementArgs.empty() && PromiseContainsNew) {
- PlacementArgs.clear();
- LookupAllocationFunction();
+ if (PromiseContainsNew && !PlacementArgs.empty()) {
+ // [dcl.fct.def.coroutine]p9
+ // If no viable function is found ([over.match.viable]), overload
+ // resolution
+ // is performed again on a function call created by passing just the amount
+ // of space required as an argument of type std::size_t.
+ //
+ // Proposed Change of [dcl.fct.def.coroutine]p9 in P2014R0:
+ // Otherwise, overload resolution is performed again on a function call
+ // created
+ // by passing the amount of space requested as an argument of type
+ // std::size_t as the first argument, and the requested alignment as
+ // an argument of type std:align_val_t as the second argument.
+ if (!OperatorNew ||
+ (S.getLangOpts().CoroAlignedAllocation && !PassAlignment))
+ LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
+ /*WithoutPlacementArgs*/ true);
}
+ // Proposed Change of [dcl.fct.def.coroutine]p12 in P2014R0:
+ // Otherwise, overload resolution is performed again on a function call
+ // created
+ // by passing the amount of space requested as an argument of type
+ // std::size_t as the first argument, and the lvalues p1 ... pn as the
+ // succeeding arguments. Otherwise, overload resolution is performed again
+ // on a function call created by passing just the amount of space required as
+ // an argument of type std::size_t.
+ //
+ // So within the proposed change in P2014RO, the priority order of aligned
+ // allocation functions wiht promise_type is:
+ //
+ // void* operator new( std::size_t, std::align_val_t, placement_args... );
+ // void* operator new( std::size_t, std::align_val_t);
+ // void* operator new( std::size_t, placement_args... );
+ // void* operator new( std::size_t);
+
+ // Helper variable to emit warnings.
+ bool FoundNonAlignedInPromise = false;
+ if (PromiseContainsNew && S.getLangOpts().CoroAlignedAllocation)
+ if (!OperatorNew || !PassAlignment) {
+ FoundNonAlignedInPromise = OperatorNew;
+
+ LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
+ /*WithoutPlacementArgs*/ false,
+ /*ForceNonAligned*/ true);
+
+ if (!OperatorNew && !PlacementArgs.empty())
+ LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class,
+ /*WithoutPlacementArgs*/ true,
+ /*ForceNonAligned*/ true);
+ }
+
bool IsGlobalOverload =
OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext());
// If we didn't find a class-local new declaration and non-throwing new
@@ -1379,15 +1457,24 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
return false;
PlacementArgs = {StdNoThrow};
OperatorNew = nullptr;
- S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Both,
- /*DeleteScope*/ Sema::AFS_Both, PromiseType,
- /*isArray*/ false, PassAlignment, PlacementArgs,
- OperatorNew, UnusedResult);
+ LookupAllocationFunction(Sema::AFS_Global);
+ }
+
+ // If we found a non-aligned allocation function in the promise_type,
+ // it indicates the user forgot to update the allocation function. Let's emit
+ // a warning here.
+ if (FoundNonAlignedInPromise) {
+ S.Diag(OperatorNew->getLocation(),
+ diag::warn_non_aligned_allocation_function)
+ << &FD;
}
if (!OperatorNew) {
if (PromiseContainsNew)
S.Diag(Loc, diag::err_coroutine_unusable_new) << PromiseType << &FD;
+ else if (RequiresNoThrowAlloc)
+ S.Diag(Loc, diag::err_coroutine_unfound_nothrow_new)
+ << &FD << S.getLangOpts().CoroAlignedAllocation;
return false;
}
@@ -1404,7 +1491,8 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
}
}
- if ((OperatorDelete = findDeleteForPromise(S, Loc, PromiseType)) == nullptr) {
+ FunctionDecl *OperatorDelete = nullptr;
+ if (!findDeleteForPromise(S, Loc, PromiseType, OperatorDelete)) {
// FIXME: We should add an error here. According to:
// [dcl.fct.def.coroutine]p12
// If no usual deallocation function is found, the program is ill-formed.
@@ -1417,15 +1505,34 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
Expr *FrameSize =
S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_size, {});
- // Make new call.
+ Expr *FrameAlignment = nullptr;
+
+ if (S.getLangOpts().CoroAlignedAllocation) {
+ FrameAlignment =
+ S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_align, {});
+
+ TypeSourceInfo *AlignValTy = getTypeSourceInfoForStdAlignValT(S, Loc);
+ if (!AlignValTy)
+ return false;
+
+ FrameAlignment = S.BuildCXXNamedCast(Loc, tok::kw_static_cast, AlignValTy,
+ FrameAlignment, SourceRange(Loc, Loc),
+ SourceRange(Loc, Loc))
+ .get();
+ }
+ // Make new call.
ExprResult NewRef =
S.BuildDeclRefExpr(OperatorNew, OperatorNew->getType(), VK_LValue, Loc);
if (NewRef.isInvalid())
return false;
SmallVector<Expr *, 2> NewArgs(1, FrameSize);
- llvm::append_range(NewArgs, PlacementArgs);
+ if (S.getLangOpts().CoroAlignedAllocation && PassAlignment)
+ NewArgs.push_back(FrameAlignment);
+
+ if (OperatorNew->getNumParams() > NewArgs.size())
+ llvm::append_range(NewArgs, PlacementArgs);
ExprResult NewExpr =
S.BuildCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc);
@@ -1454,9 +1561,29 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
// used, the size of the block is passed as the corresponding argument.
const auto *OpDeleteType =
OpDeleteQualType.getTypePtr()->castAs<FunctionProtoType>();
- if (OpDeleteType->getNumParams() > 1)
+ if (OpDeleteType->getNumParams() > DeleteArgs.size() &&
+ S.getASTContext().hasSameType(
+ OpDeleteType->getParamType(DeleteArgs.size()), FrameSize->getType()))
DeleteArgs.push_back(FrameSize);
+ // Proposed Change of [dcl.fct.def.coroutine]p12 in P2014R0:
+ // If deallocation function lookup finds a usual deallocation function with
+ // a pointer parameter, size parameter and alignment parameter then this
+ // will be the selected deallocation function, otherwise if lookup finds a
+ // usual deallocation function with both a pointer parameter and a size
+ // parameter, then this will be the selected deallocation function.
+ // Otherwise, if lookup finds a usual deallocation function with only a
+ // pointer parameter, then this will be the selected deallocation
+ // function.
+ //
+ // So we are not forced to pass alignment to the deallocation function.
+ if (S.getLangOpts().CoroAlignedAllocation &&
+ OpDeleteType->getNumParams() > DeleteArgs.size() &&
+ S.getASTContext().hasSameType(
+ OpDeleteType->getParamType(DeleteArgs.size()),
+ FrameAlignment->getType()))
+ DeleteArgs.push_back(FrameAlignment);
+
ExprResult DeleteExpr =
S.BuildCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc);
DeleteExpr =
@@ -1549,8 +1676,8 @@ bool CoroutineStmtBuilder::makeOnException() {
if (!S.getLangOpts().CXXExceptions)
return true;
- ExprResult UnhandledException = buildPromiseCall(S, Fn.CoroutinePromise, Loc,
- "unhandled_exception", None);
+ ExprResult UnhandledException = buildPromiseCall(
+ S, Fn.CoroutinePromise, Loc, "unhandled_exception", std::nullopt);
UnhandledException = S.ActOnFinishFullExpr(UnhandledException.get(), Loc,
/*DiscardedValue*/ false);
if (UnhandledException.isInvalid())
@@ -1573,8 +1700,8 @@ bool CoroutineStmtBuilder::makeReturnObject() {
// [dcl.fct.def.coroutine]p7
// The expression promise.get_return_object() is used to initialize the
// returned reference or prvalue result object of a call to a coroutine.
- ExprResult ReturnObject =
- buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None);
+ ExprResult ReturnObject = buildPromiseCall(S, Fn.CoroutinePromise, Loc,
+ "get_return_object", std::nullopt);
if (ReturnObject.isInvalid())
return false;
@@ -1694,7 +1821,7 @@ bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) {
// [dcl.fct.def.coroutine]p13
// The initialization and destruction of each parameter copy occurs in the
// context of the called coroutine.
- auto D = buildVarDecl(*this, Loc, PD->getType(), PD->getIdentifier());
+ auto *D = buildVarDecl(*this, Loc, PD->getType(), PD->getIdentifier());
AddInitializerToDecl(D, CExpr, /*DirectInit=*/true);
// Convert decl to a statement.
@@ -1724,7 +1851,8 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
// discovered.
// TODO: Become stricter when <experimental/coroutine> is removed.
- auto const &TraitIdent = PP.getIdentifierTable().get("coroutine_traits");
+ IdentifierInfo const &TraitIdent =
+ PP.getIdentifierTable().get("coroutine_traits");
NamespaceDecl *StdSpace = getStdNamespace();
LookupResult ResStd(*this, &TraitIdent, FuncLoc, LookupOrdinaryName);
@@ -1742,7 +1870,7 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
}
// Prefer ::std to std::experimental.
- auto &Result = InStd ? ResStd : ResExp;
+ LookupResult &Result = InStd ? ResStd : ResExp;
CoroTraitsNamespaceCache = InStd ? StdSpace : ExpSpace;
// coroutine_traits is required to be a class template.
@@ -1759,7 +1887,7 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc,
Diag(KwLoc, diag::warn_deprecated_coroutine_namespace)
<< "coroutine_traits";
ResExp.suppressDiagnostics();
- auto *Found = *ResExp.begin();
+ NamedDecl *Found = *ResExp.begin();
Diag(Found->getLocation(), diag::note_entity_declared_at) << Found;
if (InStd &&
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 985005d0b79b..e2b921bfe78f 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -27,6 +27,7 @@
#include "clang/AST/Randstruct.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/HLSLRuntime.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -49,6 +50,7 @@
#include <algorithm>
#include <cstring>
#include <functional>
+#include <optional>
#include <unordered_map>
using namespace clang;
@@ -145,7 +147,8 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw___ibm128:
case tok::kw_wchar_t:
case tok::kw_bool:
- case tok::kw___underlying_type:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case tok::kw___auto_type:
return true;
@@ -275,6 +278,45 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
}
+/// Build a ParsedType for a simple-type-specifier with a nested-name-specifier.
+static ParsedType buildNamedType(Sema &S, const CXXScopeSpec *SS, QualType T,
+ SourceLocation NameLoc,
+ bool WantNontrivialTypeSourceInfo = true) {
+ switch (T->getTypeClass()) {
+ case Type::DeducedTemplateSpecialization:
+ case Type::Enum:
+ case Type::InjectedClassName:
+ case Type::Record:
+ case Type::Typedef:
+ case Type::UnresolvedUsing:
+ case Type::Using:
+ break;
+ // These can never be qualified so an ElaboratedType node
+ // would carry no additional meaning.
+ case Type::ObjCInterface:
+ case Type::ObjCTypeParam:
+ case Type::TemplateTypeParm:
+ return ParsedType::make(T);
+ default:
+ llvm_unreachable("Unexpected Type Class");
+ }
+
+ if (!SS || SS->isEmpty())
+ return ParsedType::make(
+ S.Context.getElaboratedType(ETK_None, nullptr, T, nullptr));
+
+ QualType ElTy = S.getElaboratedType(ETK_None, *SS, T);
+ if (!WantNontrivialTypeSourceInfo)
+ return ParsedType::make(ElTy);
+
+ TypeLocBuilder Builder;
+ Builder.pushTypeSpec(T).setNameLoc(NameLoc);
+ ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(ElTy);
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ ElabTL.setQualifierLoc(SS->getWithLocInContext(S.Context));
+ return S.CreateParsedType(ElTy, Builder.getTypeSourceInfo(S.Context, ElTy));
+}
+
/// If the identifier refers to a type name within this scope,
/// return the declaration of that type.
///
@@ -284,12 +326,12 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
/// opaque pointer (actually a QualType) corresponding to that
/// type. Otherwise, returns NULL.
ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
- Scope *S, CXXScopeSpec *SS,
- bool isClassName, bool HasTrailingDot,
- ParsedType ObjectTypePtr,
+ Scope *S, CXXScopeSpec *SS, bool isClassName,
+ bool HasTrailingDot, ParsedType ObjectTypePtr,
bool IsCtorOrDtorName,
bool WantNontrivialTypeSourceInfo,
bool IsClassTemplateDeductionContext,
+ ImplicitTypenameContext AllowImplicitTypename,
IdentifierInfo **CorrectedII) {
// FIXME: Consider allowing this outside C++1z mode as an extension.
bool AllowDeducedTemplate = IsClassTemplateDeductionContext &&
@@ -316,17 +358,33 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
//
// We therefore do not perform any name lookup if the result would
// refer to a member of an unknown specialization.
- if (!isClassName && !IsCtorOrDtorName)
+ // In C++2a, in several contexts a 'typename' is not required. Also
+ // allow this as an extension.
+ if (AllowImplicitTypename == ImplicitTypenameContext::No &&
+ !isClassName && !IsCtorOrDtorName)
return nullptr;
+ bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName;
+ if (IsImplicitTypename) {
+ SourceLocation QualifiedLoc = SS->getRange().getBegin();
+ if (getLangOpts().CPlusPlus20)
+ Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename);
+ else
+ Diag(QualifiedLoc, diag::ext_implicit_typename)
+ << SS->getScopeRep() << II.getName()
+ << FixItHint::CreateInsertion(QualifiedLoc, "typename ");
+ }
// We know from the grammar that this name refers to a type,
// so build a dependent node to describe the type.
if (WantNontrivialTypeSourceInfo)
- return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get();
+ return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc,
+ (ImplicitTypenameContext)IsImplicitTypename)
+ .get();
NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context);
- QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc,
- II, NameLoc);
+ QualType T =
+ CheckTypenameType(IsImplicitTypename ? ETK_Typename : ETK_None,
+ SourceLocation(), QualifierLoc, II, NameLoc);
return ParsedType::make(T);
}
@@ -417,7 +475,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
}
}
// If typo correction failed or was not performed, fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
Result.suppressDiagnostics();
@@ -500,8 +558,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
} else if (auto *UD = dyn_cast<UnresolvedUsingIfExistsDecl>(IIDecl)) {
(void)DiagnoseUseOfDecl(UD, NameLoc);
// Recover with 'int'
- T = Context.IntTy;
- FoundUsingShadow = nullptr;
+ return ParsedType::make(Context.IntTy);
} else if (AllowDeducedTemplate) {
if (auto *TD = getAsTypeTemplateDecl(IIDecl)) {
assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD);
@@ -523,27 +580,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
if (FoundUsingShadow)
T = Context.getUsingType(FoundUsingShadow, T);
- // NOTE: avoid constructing an ElaboratedType(Loc) if this is a
- // constructor or destructor name (in such a case, the scope specifier
- // will be attached to the enclosing Expr or Decl node).
- if (SS && SS->isNotEmpty() && !IsCtorOrDtorName &&
- !isa<ObjCInterfaceDecl, UnresolvedUsingIfExistsDecl>(IIDecl)) {
- if (WantNontrivialTypeSourceInfo) {
- // Construct a type with type-source information.
- TypeLocBuilder Builder;
- Builder.pushTypeSpec(T).setNameLoc(NameLoc);
-
- T = getElaboratedType(ETK_None, *SS, T);
- ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
- ElabTL.setElaboratedKeywordLoc(SourceLocation());
- ElabTL.setQualifierLoc(SS->getWithLocInContext(Context));
- return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
- } else {
- T = getElaboratedType(ETK_None, *SS, T);
- }
- }
-
- return ParsedType::make(T);
+ return buildNamedType(*this, SS, T, NameLoc, WantNontrivialTypeSourceInfo);
}
// Builds a fake NNS for the given decl context.
@@ -1147,17 +1184,7 @@ Corrected:
QualType T = Context.getTypeDeclType(Type);
if (const auto *USD = dyn_cast<UsingShadowDecl>(Found))
T = Context.getUsingType(USD, T);
-
- if (SS.isEmpty()) // No elaborated type, trivial location info
- return ParsedType::make(T);
-
- TypeLocBuilder Builder;
- Builder.pushTypeSpec(T).setNameLoc(NameLoc);
- T = getElaboratedType(ETK_None, SS, T);
- ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
- ElabTL.setElaboratedKeywordLoc(SourceLocation());
- ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
- return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
+ return buildNamedType(*this, &SS, T, NameLoc);
};
NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl();
@@ -1221,7 +1248,8 @@ Corrected:
// member accesses, as we need to defer certain access checks until we know
// the context.
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
- if (Result.isSingleResult() && !ADL && !FirstDecl->isCXXClassMember())
+ if (Result.isSingleResult() && !ADL &&
+ (!FirstDecl->isCXXClassMember() || isa<EnumConstantDecl>(FirstDecl)))
return NameClassification::NonType(Result.getRepresentativeDecl());
// Otherwise, this is an overload set that we will need to resolve later.
@@ -1266,7 +1294,7 @@ ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS,
Result.resolveKind();
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
- return BuildDeclarationNameExpr(SS, Result, ADL);
+ return BuildDeclarationNameExpr(SS, Result, ADL, /*AcceptInvalidDecl=*/true);
}
ExprResult Sema::ActOnNameClassifiedAsOverloadSet(Scope *S, Expr *E) {
@@ -1635,9 +1663,11 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) {
// Partitions are part of the module, but a partition could import another
// module, so verify that the PMIs agree.
- if (NewM && OldM && (NewM->isModulePartition() || OldM->isModulePartition()))
- return NewM->getPrimaryModuleInterfaceName() ==
- OldM->getPrimaryModuleInterfaceName();
+ if (NewM && OldM &&
+ (NewM->isModulePartition() || OldM->isModulePartition()) &&
+ NewM->getPrimaryModuleInterfaceName() ==
+ OldM->getPrimaryModuleInterfaceName())
+ return false;
bool NewIsModuleInterface = NewM && NewM->isModulePurview();
bool OldIsModuleInterface = OldM && OldM->isModulePurview();
@@ -1711,6 +1741,80 @@ bool Sema::CheckRedeclarationInModule(NamedDecl *New, NamedDecl *Old) {
return false;
}
+// Check the redefinition in C++20 Modules.
+//
+// [basic.def.odr]p14:
+// For any definable item D with definitions in multiple translation units,
+// - if D is a non-inline non-templated function or variable, or
+// - if the definitions in different translation units do not satisfy the
+// following requirements,
+// the program is ill-formed; a diagnostic is required only if the definable
+// item is attached to a named module and a prior definition is reachable at
+// the point where a later definition occurs.
+// - Each such definition shall not be attached to a named module
+// ([module.unit]).
+// - Each such definition shall consist of the same sequence of tokens, ...
+// ...
+//
+// Return true if the redefinition is not allowed. Return false otherwise.
+bool Sema::IsRedefinitionInModule(const NamedDecl *New,
+ const NamedDecl *Old) const {
+ assert(getASTContext().isSameEntity(New, Old) &&
+ "New and Old are not the same definition, we should diagnostic it "
+ "immediately instead of checking it.");
+ assert(const_cast<Sema *>(this)->isReachable(New) &&
+ const_cast<Sema *>(this)->isReachable(Old) &&
+ "We shouldn't see unreachable definitions here.");
+
+ Module *NewM = New->getOwningModule();
+ Module *OldM = Old->getOwningModule();
+
+ // We only checks for named modules here. The header like modules is skipped.
+ // FIXME: This is not right if we import the header like modules in the module
+ // purview.
+ //
+ // For example, assuming "header.h" provides definition for `D`.
+ // ```C++
+ // //--- M.cppm
+ // export module M;
+ // import "header.h"; // or #include "header.h" but import it by clang modules
+ // actually.
+ //
+ // //--- Use.cpp
+ // import M;
+ // import "header.h"; // or uses clang modules.
+ // ```
+ //
+ // In this case, `D` has multiple definitions in multiple TU (M.cppm and
+ // Use.cpp) and `D` is attached to a named module `M`. The compiler should
+ // reject it. But the current implementation couldn't detect the case since we
+ // don't record the information about the importee modules.
+ //
+ // But this might not be painful in practice. Since the design of C++20 Named
+ // Modules suggests us to use headers in global module fragment instead of
+ // module purview.
+ if (NewM && NewM->isHeaderLikeModule())
+ NewM = nullptr;
+ if (OldM && OldM->isHeaderLikeModule())
+ OldM = nullptr;
+
+ if (!NewM && !OldM)
+ return true;
+
+ // [basic.def.odr]p14.3
+ // Each such definition shall not be attached to a named module
+ // ([module.unit]).
+ if ((NewM && NewM->isModulePurview()) || (OldM && OldM->isModulePurview()))
+ return true;
+
+ // Then New and Old lives in the same TU if their share one same module unit.
+ if (NewM)
+ NewM = NewM->getTopLevelModule();
+ if (OldM)
+ OldM = OldM->getTopLevelModule();
+ return OldM == NewM;
+}
+
static bool isUsingDecl(NamedDecl *D) {
return isa<UsingShadowDecl>(D) ||
isa<UnresolvedUsingTypenameDecl>(D) ||
@@ -1773,7 +1877,7 @@ bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) {
// FIXME: This needs to be refactored; some other isInMainFile users want
// these semantics.
static bool isMainFileLoc(const Sema &S, SourceLocation Loc) {
- if (S.TUKind != TU_Complete)
+ if (S.TUKind != TU_Complete || S.getLangOpts().IsHeaderFile)
return false;
return S.SourceMgr.isInMainFile(Loc);
}
@@ -1990,20 +2094,31 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
}
void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) {
+ DiagnoseUnusedNestedTypedefs(
+ D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
+}
+
+void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D,
+ DiagReceiverTy DiagReceiver) {
if (D->getTypeForDecl()->isDependentType())
return;
for (auto *TmpD : D->decls()) {
if (const auto *T = dyn_cast<TypedefNameDecl>(TmpD))
- DiagnoseUnusedDecl(T);
+ DiagnoseUnusedDecl(T, DiagReceiver);
else if(const auto *R = dyn_cast<RecordDecl>(TmpD))
- DiagnoseUnusedNestedTypedefs(R);
+ DiagnoseUnusedNestedTypedefs(R, DiagReceiver);
}
}
+void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+ DiagnoseUnusedDecl(
+ D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
+}
+
/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used
/// unless they are marked attr(unused).
-void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+void Sema::DiagnoseUnusedDecl(const NamedDecl *D, DiagReceiverTy DiagReceiver) {
if (!ShouldDiagnoseUnusedDecl(D))
return;
@@ -2025,10 +2140,11 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
else
DiagID = diag::warn_unused_variable;
- Diag(D->getLocation(), DiagID) << D << Hint;
+ DiagReceiver(D->getLocation(), PDiag(DiagID) << D << Hint);
}
-void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
+void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD,
+ DiagReceiverTy DiagReceiver) {
// If it's not referenced, it can't be set. If it has the Cleanup attribute,
// it's not really unused.
if (!VD->isReferenced() || !VD->getDeclName() || VD->hasAttr<UnusedAttr>() ||
@@ -2074,10 +2190,11 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
return;
unsigned DiagID = isa<ParmVarDecl>(VD) ? diag::warn_unused_but_set_parameter
: diag::warn_unused_but_set_variable;
- Diag(VD->getLocation(), DiagID) << VD;
+ DiagReceiver(VD->getLocation(), PDiag(DiagID) << VD);
}
-static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
+static void CheckPoppedLabel(LabelDecl *L, Sema &S,
+ Sema::DiagReceiverTy DiagReceiver) {
// Verify that we have no forward references left. If so, there was a goto
// or address of a label taken, but no definition of it. Label fwd
// definitions are indicated with a null substmt which is also not a resolved
@@ -2088,7 +2205,8 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
else
Diagnose = L->getStmt() == nullptr;
if (Diagnose)
- S.Diag(L->getLocation(), diag::err_undeclared_label_use) << L;
+ DiagReceiver(L->getLocation(), S.PDiag(diag::err_undeclared_label_use)
+ << L);
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
@@ -2098,6 +2216,24 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
"Scope shouldn't contain decls!");
+ /// We visit the decls in non-deterministic order, but we want diagnostics
+ /// emitted in deterministic order. Collect any diagnostic that may be emitted
+ /// and sort the diagnostics before emitting them, after we visited all decls.
+ struct LocAndDiag {
+ SourceLocation Loc;
+ std::optional<SourceLocation> PreviousDeclLoc;
+ PartialDiagnostic PD;
+ };
+ SmallVector<LocAndDiag, 16> DeclDiags;
+ auto addDiag = [&DeclDiags](SourceLocation Loc, PartialDiagnostic PD) {
+ DeclDiags.push_back(LocAndDiag{Loc, std::nullopt, std::move(PD)});
+ };
+ auto addDiagWithPrev = [&DeclDiags](SourceLocation Loc,
+ SourceLocation PreviousDeclLoc,
+ PartialDiagnostic PD) {
+ DeclDiags.push_back(LocAndDiag{Loc, PreviousDeclLoc, std::move(PD)});
+ };
+
for (auto *TmpD : S->decls()) {
assert(TmpD && "This decl didn't get pushed??");
@@ -2106,11 +2242,11 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
// Diagnose unused variables in this scope.
if (!S->hasUnrecoverableErrorOccurred()) {
- DiagnoseUnusedDecl(D);
+ DiagnoseUnusedDecl(D, addDiag);
if (const auto *RD = dyn_cast<RecordDecl>(D))
- DiagnoseUnusedNestedTypedefs(RD);
+ DiagnoseUnusedNestedTypedefs(RD, addDiag);
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- DiagnoseUnusedButSetDecl(VD);
+ DiagnoseUnusedButSetDecl(VD, addDiag);
RefsMinusAssignments.erase(VD);
}
}
@@ -2119,7 +2255,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
// If this was a forward reference to a label, verify it was defined.
if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
- CheckPoppedLabel(LD, *this);
+ CheckPoppedLabel(LD, *this, addDiag);
// Remove this name from our lexical scope, and warn on it if we haven't
// already.
@@ -2127,13 +2263,27 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
auto ShadowI = ShadowingDecls.find(D);
if (ShadowI != ShadowingDecls.end()) {
if (const auto *FD = dyn_cast<FieldDecl>(ShadowI->second)) {
- Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field)
- << D << FD << FD->getParent();
- Diag(FD->getLocation(), diag::note_previous_declaration);
+ addDiagWithPrev(D->getLocation(), FD->getLocation(),
+ PDiag(diag::warn_ctor_parm_shadows_field)
+ << D << FD << FD->getParent());
}
ShadowingDecls.erase(ShadowI);
}
}
+
+ llvm::sort(DeclDiags,
+ [](const LocAndDiag &LHS, const LocAndDiag &RHS) -> bool {
+ // The particular order for diagnostics is not important, as long
+ // as the order is deterministic. Using the raw location is going
+ // to generally be in source order unless there are macro
+ // expansions involved.
+ return LHS.Loc.getRawEncoding() < RHS.Loc.getRawEncoding();
+ });
+ for (const LocAndDiag &D : DeclDiags) {
+ Diag(D.Loc, D.PD);
+ if (D.PreviousDeclLoc)
+ Diag(*D.PreviousDeclLoc, diag::note_previous_declaration);
+ }
}
/// Look for an Objective-C class in the translation unit.
@@ -2949,7 +3099,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
continue;
} else if (isa<OMPDeclareVariantAttr>(NewAttribute)) {
// We allow to add OMP[Begin]DeclareVariantAttr to be added to
- // declarations after defintions.
+ // declarations after definitions.
++I;
continue;
}
@@ -3249,8 +3399,8 @@ static bool EquivalentArrayTypes(QualType Old, QualType New,
static void mergeParamDeclTypes(ParmVarDecl *NewParam,
const ParmVarDecl *OldParam,
Sema &S) {
- if (auto Oldnullability = OldParam->getType()->getNullability(S.Context)) {
- if (auto Newnullability = NewParam->getType()->getNullability(S.Context)) {
+ if (auto Oldnullability = OldParam->getType()->getNullability()) {
+ if (auto Newnullability = NewParam->getType()->getNullability()) {
if (*Oldnullability != *Newnullability) {
S.Diag(NewParam->getLocation(), diag::warn_mismatched_nullability_attr)
<< DiagNullabilityKind(
@@ -3960,7 +4110,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
// default argument promotion rules were already checked by
// ASTContext::typesAreCompatible().
if (Old->hasPrototype() && !New->hasWrittenPrototype() && NewDeclIsDefn &&
- Old->getNumParams() != New->getNumParams()) {
+ Old->getNumParams() != New->getNumParams() && !Old->isImplicit()) {
if (Old->hasInheritedPrototype())
Old = Old->getCanonicalDecl();
Diag(New->getLocation(), diag::err_conflicting_types) << New;
@@ -4026,10 +4176,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
// The old declaration provided a function prototype, but the
// new declaration does not. Merge in the prototype.
assert(!OldProto->hasExceptionSpec() && "Exception spec in C");
- SmallVector<QualType, 16> ParamTypes(OldProto->param_types());
- NewQType =
- Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes,
- OldProto->getExtProtoInfo());
+ NewQType = Context.getFunctionType(NewFuncType->getReturnType(),
+ OldProto->getParamTypes(),
+ OldProto->getExtProtoInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -4657,6 +4806,7 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
if (!hasVisibleDefinition(Old) &&
(New->getFormalLinkage() == InternalLinkage ||
New->isInline() ||
+ isa<VarTemplateSpecializationDecl>(New) ||
New->getDescribedVarTemplate() ||
New->getNumTemplateParameterLists() ||
New->getDeclContext()->isDependentContext())) {
@@ -5840,7 +5990,9 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_typename:
case DeclSpec::TST_typeofType:
- case DeclSpec::TST_underlyingType:
+ case DeclSpec::TST_typeof_unqualType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case DeclSpec::TST_atomic: {
// Grab the type from the parser.
TypeSourceInfo *TSI = nullptr;
@@ -5864,6 +6016,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D,
}
case DeclSpec::TST_decltype:
+ case DeclSpec::TST_typeof_unqualExpr:
case DeclSpec::TST_typeofExpr: {
Expr *E = DS.getRepAsExpr();
ExprResult Result = S.RebuildExprInCurrentInstantiation(E);
@@ -6502,8 +6655,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 1 << static_cast<int>(D.getDeclSpec().getConstexprSpecifier());
- if (D.getName().Kind != UnqualifiedIdKind::IK_Identifier) {
- if (D.getName().Kind == UnqualifiedIdKind::IK_DeductionGuideName)
+ if (D.getName().getKind() != UnqualifiedIdKind::IK_Identifier) {
+ if (D.getName().getKind() == UnqualifiedIdKind::IK_DeductionGuideName)
Diag(D.getName().StartLocation,
diag::err_deduction_guide_invalid_specifier)
<< "typedef";
@@ -6939,13 +7092,24 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
(!IsInline || (IsMicrosoftABI && IsTemplate)) && !IsStaticDataMember &&
!NewDecl->isLocalExternDecl() && !IsQualifiedFriend) {
if (IsMicrosoftABI && IsDefinition) {
- S.Diag(NewDecl->getLocation(),
- diag::warn_redeclaration_without_import_attribute)
- << NewDecl;
- S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
- NewDecl->dropAttr<DLLImportAttr>();
- NewDecl->addAttr(
- DLLExportAttr::CreateImplicit(S.Context, NewImportAttr->getRange()));
+ if (IsSpecialization) {
+ S.Diag(
+ NewDecl->getLocation(),
+ diag::err_attribute_dllimport_function_specialization_definition);
+ S.Diag(OldImportAttr->getLocation(), diag::note_attribute);
+ NewDecl->dropAttr<DLLImportAttr>();
+ } else {
+ S.Diag(NewDecl->getLocation(),
+ diag::warn_redeclaration_without_import_attribute)
+ << NewDecl;
+ S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
+ NewDecl->dropAttr<DLLImportAttr>();
+ NewDecl->addAttr(DLLExportAttr::CreateImplicit(
+ S.Context, NewImportAttr->getRange()));
+ }
+ } else if (IsMicrosoftABI && IsSpecialization) {
+ assert(!IsDefinition);
+ // MSVC allows this. Keep the inherited attribute.
} else {
S.Diag(NewDecl->getLocation(),
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
@@ -7039,6 +7203,9 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
return true;
if (DC->isRecord())
return false;
+ if (DC->getDeclKind() == Decl::HLSLBuffer)
+ return false;
+
if (isa<RequiresExprBodyDecl>(DC))
return false;
llvm_unreachable("Unexpected context");
@@ -7212,6 +7379,36 @@ static void copyAttrFromTypedefToDecl(Sema &S, Decl *D, const TypedefType *TT) {
}
}
+// This function emits warning and a corresponding note based on the
+// ReadOnlyPlacementAttr attribute. The warning checks that all global variable
+// declarations of an annotated type must be const qualified.
+void emitReadOnlyPlacementAttrWarning(Sema &S, const VarDecl *VD) {
+ QualType VarType = VD->getType().getCanonicalType();
+
+ // Ignore local declarations (for now) and those with const qualification.
+ // TODO: Local variables should not be allowed if their type declaration has
+ // ReadOnlyPlacementAttr attribute. To be handled in follow-up patch.
+ if (!VD || VD->hasLocalStorage() || VD->getType().isConstQualified())
+ return;
+
+ if (VarType->isArrayType()) {
+ // Retrieve element type for array declarations.
+ VarType = S.getASTContext().getBaseElementType(VarType);
+ }
+
+ const RecordDecl *RD = VarType->getAsRecordDecl();
+
+ // Check if the record declaration is present and if it has any attributes.
+ if (RD == nullptr)
+ return;
+
+ if (const auto *ConstDecl = RD->getAttr<ReadOnlyPlacementAttr>()) {
+ S.Diag(VD->getLocation(), diag::warn_var_decl_not_read_only) << RD;
+ S.Diag(ConstDecl->getLocation(), diag::note_enforce_read_only_placement);
+ return;
+ }
+}
+
NamedDecl *Sema::ActOnVariableDeclarator(
Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo,
LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists,
@@ -7555,7 +7752,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
Diag(D.getDeclSpec().getConstexprSpecLoc(),
diag::err_constexpr_wrong_decl_kind)
<< static_cast<int>(D.getDeclSpec().getConstexprSpecifier());
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ConstexprSpecKind::Constexpr:
NewVD->setConstexpr(true);
@@ -7876,6 +8073,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (IsMemberSpecialization && !NewVD->isInvalidDecl())
CompleteMemberSpecialization(NewVD, Previous);
+ emitReadOnlyPlacementAttrWarning(*this, NewVD);
+
return NewVD;
}
@@ -8003,7 +8202,7 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl,
if (shadowedVar->isExternC()) {
// For shadowing external vars, make sure that we point to the global
// declaration, not a locally scoped extern declaration.
- for (auto I : shadowedVar->redecls())
+ for (auto *I : shadowedVar->redecls())
if (I->isFileVarDecl()) {
ShadowedDecl = I;
break;
@@ -8492,6 +8691,19 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
NewVD->setInvalidDecl();
return;
}
+
+ // Check that SVE types are only used in functions with SVE available.
+ if (T->isSVESizelessBuiltinType() && CurContext->isFunctionOrMethod()) {
+ const FunctionDecl *FD = cast<FunctionDecl>(CurContext);
+ llvm::StringMap<bool> CallerFeatureMap;
+ Context.getFunctionFeatureMap(CallerFeatureMap, FD);
+ if (!Builtin::evaluateRequiredTargetFeatures(
+ "sve", CallerFeatureMap)) {
+ Diag(NewVD->getLocation(), diag::err_sve_vector_in_non_sve_target) << T;
+ NewVD->setInvalidDecl();
+ return;
+ }
+ }
}
/// Perform semantic checking on a newly-created variable
@@ -9069,10 +9281,23 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
// reference if an implementation supports them in kernel parameters.
if (S.getLangOpts().OpenCLCPlusPlus &&
!S.getOpenCLOptions().isAvailableOption(
- "__cl_clang_non_portable_kernel_param_types", S.getLangOpts()) &&
- !PointeeType->isAtomicType() && !PointeeType->isVoidType() &&
- !PointeeType->isStandardLayoutType())
+ "__cl_clang_non_portable_kernel_param_types", S.getLangOpts())) {
+ auto CXXRec = PointeeType.getCanonicalType()->getAsCXXRecordDecl();
+ bool IsStandardLayoutType = true;
+ if (CXXRec) {
+ // If template type is not ODR-used its definition is only available
+ // in the template definition not its instantiation.
+ // FIXME: This logic doesn't work for types that depend on template
+ // parameter (PR58590).
+ if (!CXXRec->hasDefinition())
+ CXXRec = CXXRec->getTemplateInstantiationPattern();
+ if (!CXXRec || !CXXRec->hasDefinition() || !CXXRec->isStandardLayout())
+ IsStandardLayoutType = false;
+ }
+ if (!PointeeType->isAtomicType() && !PointeeType->isVoidType() &&
+ !IsStandardLayoutType)
return InvalidKernelParam;
+ }
return PtrKernelParam;
}
@@ -9419,7 +9644,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules ||
!NewFD->getOwningModule() ||
NewFD->getOwningModule()->isGlobalModule() ||
- NewFD->getOwningModule()->isModuleMapModule();
+ NewFD->getOwningModule()->isHeaderLikeModule();
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
@@ -9755,6 +9980,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setType(Context.getFunctionType(
FPT->getReturnType(), FPT->getParamTypes(),
FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept)));
+
+ // C++20 [dcl.inline]/7
+ // If an inline function or variable that is attached to a named module
+ // is declared in a definition domain, it shall be defined in that
+ // domain.
+ // So, if the current declaration does not have a definition, we must
+ // check at the end of the TU (or when the PMF starts) to see that we
+ // have a definition at that point.
+ if (isInline && !D.isFunctionDefinition() && getLangOpts().CPlusPlus20 &&
+ NewFD->hasOwningModule() &&
+ NewFD->getOwningModule()->isModulePurview()) {
+ PendingInlineFuncDecls.insert(NewFD);
+ }
}
// Filter out previous declarations that don't match the scope.
@@ -9900,6 +10138,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->dropAttr<SectionAttr>();
}
+ // Apply an implicit StrictGuardStackCheckAttr if #pragma strict_gs_check is
+ // active.
+ if (StrictGuardStackCheckStack.CurrentValue && D.isFunctionDefinition() &&
+ !NewFD->hasAttr<StrictGuardStackCheckAttr>())
+ NewFD->addAttr(StrictGuardStackCheckAttr::CreateImplicit(
+ Context, PragmaClangTextSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
+
// Apply an implicit CodeSegAttr from class declspec or
// apply an implicit SectionAttr from #pragma code_seg if active.
if (!NewFD->hasAttr<CodeSegAttr>()) {
@@ -9911,14 +10157,49 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
+ const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
+ if (NewTVA && !NewTVA->isDefaultVersion() &&
+ !Context.getTargetInfo().hasFeature("fmv")) {
+ // Don't add to scope fmv functions declarations if fmv disabled
+ AddToScope = false;
+ return NewFD;
+ }
if (getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5: Using an address space qualifier in a function return
// type declaration will generate a compilation error.
LangAS AddressSpace = NewFD->getReturnType().getAddressSpace();
if (AddressSpace != LangAS::Default) {
- Diag(NewFD->getLocation(),
- diag::err_opencl_return_value_with_address_space);
+ Diag(NewFD->getLocation(), diag::err_return_value_with_address_space);
+ NewFD->setInvalidDecl();
+ }
+ }
+
+ if (getLangOpts().HLSL) {
+ auto &TargetInfo = getASTContext().getTargetInfo();
+ // Skip operator overload which not identifier.
+ // Also make sure NewFD is in translation-unit scope.
+ if (!NewFD->isInvalidDecl() && Name.isIdentifier() &&
+ NewFD->getName() == TargetInfo.getTargetOpts().HLSLEntry &&
+ S->getDepth() == 0) {
+ CheckHLSLEntryPoint(NewFD);
+ if (!NewFD->isInvalidDecl()) {
+ auto Env = TargetInfo.getTriple().getEnvironment();
+ AttributeCommonInfo AL(NewFD->getBeginLoc());
+ HLSLShaderAttr::ShaderType ShaderType =
+ static_cast<HLSLShaderAttr::ShaderType>(
+ hlsl::getStageFromEnvironment(Env));
+ // To share code with HLSLShaderAttr, add HLSLShaderAttr to entry
+ // function.
+ if (HLSLShaderAttr *Attr = mergeHLSLShaderAttr(NewFD, AL, ShaderType))
+ NewFD->addAttr(Attr);
+ }
+ }
+ // HLSL does not support specifying an address space on a function return
+ // type.
+ LangAS AddressSpace = NewFD->getReturnType().getAddressSpace();
+ if (AddressSpace != LangAS::Default) {
+ Diag(NewFD->getLocation(), diag::err_return_value_with_address_space);
NewFD->setInvalidDecl();
}
}
@@ -10091,7 +10372,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.setRedeclaration(true);
}
- assert((NewFD->isInvalidDecl() || !D.isRedeclaration() ||
+ assert((NewFD->isInvalidDecl() || NewFD->isMultiVersion() ||
+ !D.isRedeclaration() ||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
"previous declaration set still overloaded");
@@ -10253,16 +10535,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(NewFD->getLocation(),
diag::err_attribute_overloadable_no_prototype)
<< NewFD;
-
- // Turn this into a variadic function with no parameters.
- const auto *FT = NewFD->getType()->castAs<FunctionType>();
- FunctionProtoType::ExtProtoInfo EPI(
- Context.getDefaultCallingConvention(true, false));
- EPI.Variadic = true;
- EPI.ExtInfo = FT->getExtInfo();
-
- QualType R = Context.getFunctionType(FT->getReturnType(), None, EPI);
- NewFD->setType(R);
+ NewFD->dropAttr<OverloadableAttr>();
}
// If there's a #pragma GCC visibility in scope, and this isn't a class
@@ -10344,7 +10617,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
llvm::SmallPtrSet<const Type *, 16> ValidTypes;
- for (auto Param : NewFD->parameters())
+ for (auto *Param : NewFD->parameters())
checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
if (getLangOpts().OpenCLCPlusPlus) {
@@ -10360,6 +10633,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (getLangOpts().CPlusPlus) {
+ // Precalculate whether this is a friend function template with a constraint
+ // that depends on an enclosing template, per [temp.friend]p9.
+ if (isFriend && FunctionTemplate &&
+ FriendConstraintsDependOnEnclosingTemplate(NewFD))
+ NewFD->setFriendConstraintRefersToEnclosingTemplate(true);
+
if (FunctionTemplate) {
if (NewFD->isInvalidDecl())
FunctionTemplate->setInvalidDecl();
@@ -10482,7 +10761,7 @@ static Attr *getImplicitCodeSegAttrFromClass(Sema &S, const FunctionDecl *FD) {
/// (from the current #pragma code-seg value).
///
/// \param FD Function being declared.
-/// \param IsDefinition Whether it is a definition or just a declarartion.
+/// \param IsDefinition Whether it is a definition or just a declaration.
/// \returns A CodeSegAttr or SectionAttr to apply to the function or
/// nullptr if no attribute should be added.
Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
@@ -10566,37 +10845,53 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
PrevVD->getType());
}
-/// Check the target attribute of the function for MultiVersion
-/// validity.
+/// Check the target or target_version attribute of the function for
+/// MultiVersion validity.
///
/// Returns true if there was an error, false otherwise.
static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
const auto *TA = FD->getAttr<TargetAttr>();
- assert(TA && "MultiVersion Candidate requires a target attribute");
- ParsedTargetAttr ParseInfo = TA->parse();
+ const auto *TVA = FD->getAttr<TargetVersionAttr>();
+ assert(
+ (TA || TVA) &&
+ "MultiVersion candidate requires a target or target_version attribute");
const TargetInfo &TargetInfo = S.Context.getTargetInfo();
enum ErrType { Feature = 0, Architecture = 1 };
- if (!ParseInfo.Architecture.empty() &&
- !TargetInfo.validateCpuIs(ParseInfo.Architecture)) {
- S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
- << Architecture << ParseInfo.Architecture;
- return true;
- }
-
- for (const auto &Feat : ParseInfo.Features) {
- auto BareFeat = StringRef{Feat}.substr(1);
- if (Feat[0] == '-') {
+ if (TA) {
+ ParsedTargetAttr ParseInfo =
+ S.getASTContext().getTargetInfo().parseTargetAttr(TA->getFeaturesStr());
+ if (!ParseInfo.CPU.empty() && !TargetInfo.validateCpuIs(ParseInfo.CPU)) {
S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
- << Feature << ("no-" + BareFeat).str();
+ << Architecture << ParseInfo.CPU;
return true;
}
+ for (const auto &Feat : ParseInfo.Features) {
+ auto BareFeat = StringRef{Feat}.substr(1);
+ if (Feat[0] == '-') {
+ S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+ << Feature << ("no-" + BareFeat).str();
+ return true;
+ }
- if (!TargetInfo.validateCpuSupports(BareFeat) ||
- !TargetInfo.isValidFeatureName(BareFeat)) {
- S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
- << Feature << BareFeat;
- return true;
+ if (!TargetInfo.validateCpuSupports(BareFeat) ||
+ !TargetInfo.isValidFeatureName(BareFeat)) {
+ S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+ << Feature << BareFeat;
+ return true;
+ }
+ }
+ }
+
+ if (TVA) {
+ llvm::SmallVector<StringRef, 8> Feats;
+ TVA->getFeatures(Feats);
+ for (const auto &Feat : Feats) {
+ if (!TargetInfo.validateCpuSupports(Feat)) {
+ S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
+ << Feature << Feat;
+ return true;
+ }
}
}
return false;
@@ -10643,6 +10938,10 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S,
if (MVKind != MultiVersionKind::Target)
return Diagnose(S, A);
break;
+ case attr::TargetVersion:
+ if (MVKind != MultiVersionKind::TargetVersion)
+ return Diagnose(S, A);
+ break;
case attr::TargetClones:
if (MVKind != MultiVersionKind::TargetClones)
return Diagnose(S, A);
@@ -10815,18 +11114,18 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
/// This sets NewFD->isInvalidDecl() to true if there was an error.
///
/// Returns true if there was an error, false otherwise.
-static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD,
- MultiVersionKind MVKind,
- const TargetAttr *TA) {
+static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) {
+ MultiVersionKind MVKind = FD->getMultiVersionKind();
assert(MVKind != MultiVersionKind::None &&
"Function lacks multiversion attribute");
-
- // Target only causes MV if it is default, otherwise this is a normal
- // function.
- if (MVKind == MultiVersionKind::Target && !TA->isDefaultVersion())
+ const auto *TA = FD->getAttr<TargetAttr>();
+ const auto *TVA = FD->getAttr<TargetVersionAttr>();
+ // Target and target_version only causes MV if it is default, otherwise this
+ // is a normal function.
+ if ((TA && !TA->isDefaultVersion()) || (TVA && !TVA->isDefaultVersion()))
return false;
- if (MVKind == MultiVersionKind::Target && CheckMultiVersionValue(S, FD)) {
+ if ((TA || TVA) && CheckMultiVersionValue(S, FD)) {
FD->setInvalidDecl();
return true;
}
@@ -10849,23 +11148,27 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) {
return false;
}
-static bool CheckTargetCausesMultiVersioning(
- Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, const TargetAttr *NewTA,
- bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) {
+static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
+ FunctionDecl *NewFD,
+ bool &Redeclaration,
+ NamedDecl *&OldDecl,
+ LookupResult &Previous) {
+ const auto *NewTA = NewFD->getAttr<TargetAttr>();
+ const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
const auto *OldTA = OldFD->getAttr<TargetAttr>();
- ParsedTargetAttr NewParsed = NewTA->parse();
- // Sort order doesn't matter, it just needs to be consistent.
- llvm::sort(NewParsed.Features);
-
+ const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();
// If the old decl is NOT MultiVersioned yet, and we don't cause that
// to change, this is a simple redeclaration.
- if (!NewTA->isDefaultVersion() &&
- (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()))
+ if ((NewTA && !NewTA->isDefaultVersion() &&
+ (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) ||
+ (NewTVA && !NewTVA->isDefaultVersion() &&
+ (!OldTVA || OldTVA->getName() == NewTVA->getName())))
return false;
// Otherwise, this decl causes MultiVersioning.
if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true,
- MultiVersionKind::Target)) {
+ NewTVA ? MultiVersionKind::TargetVersion
+ : MultiVersionKind::Target)) {
NewFD->setInvalidDecl();
return true;
}
@@ -10876,7 +11179,9 @@ static bool CheckTargetCausesMultiVersioning(
}
// If this is 'default', permit the forward declaration.
- if (!OldFD->isMultiVersion() && !OldTA && NewTA->isDefaultVersion()) {
+ if (!OldFD->isMultiVersion() &&
+ ((NewTA && NewTA->isDefaultVersion() && !OldTA) ||
+ (NewTVA && NewTVA->isDefaultVersion() && !OldTVA))) {
Redeclaration = true;
OldDecl = OldFD;
OldFD->setIsMultiVersion();
@@ -10890,23 +11195,50 @@ static bool CheckTargetCausesMultiVersioning(
return true;
}
- ParsedTargetAttr OldParsed = OldTA->parse(std::less<std::string>());
+ if (NewTA) {
+ ParsedTargetAttr OldParsed =
+ S.getASTContext().getTargetInfo().parseTargetAttr(
+ OldTA->getFeaturesStr());
+ llvm::sort(OldParsed.Features);
+ ParsedTargetAttr NewParsed =
+ S.getASTContext().getTargetInfo().parseTargetAttr(
+ NewTA->getFeaturesStr());
+ // Sort order doesn't matter, it just needs to be consistent.
+ llvm::sort(NewParsed.Features);
+ if (OldParsed == NewParsed) {
+ S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
+ S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
+ NewFD->setInvalidDecl();
+ return true;
+ }
+ }
- if (OldParsed == NewParsed) {
- S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
- S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
- NewFD->setInvalidDecl();
- return true;
+ if (NewTVA) {
+ llvm::SmallVector<StringRef, 8> Feats;
+ OldTVA->getFeatures(Feats);
+ llvm::sort(Feats);
+ llvm::SmallVector<StringRef, 8> NewFeats;
+ NewTVA->getFeatures(NewFeats);
+ llvm::sort(NewFeats);
+
+ if (Feats == NewFeats) {
+ S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
+ S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
+ NewFD->setInvalidDecl();
+ return true;
+ }
}
for (const auto *FD : OldFD->redecls()) {
const auto *CurTA = FD->getAttr<TargetAttr>();
+ const auto *CurTVA = FD->getAttr<TargetVersionAttr>();
// We allow forward declarations before ANY multiversioning attributes, but
// nothing after the fact.
if (PreviousDeclsHaveMultiVersionAttribute(FD) &&
- (!CurTA || CurTA->isInherited())) {
+ ((NewTA && (!CurTA || CurTA->isInherited())) ||
+ (NewTVA && (!CurTVA || CurTVA->isInherited())))) {
S.Diag(FD->getLocation(), diag::err_multiversion_required_in_redecl)
- << 0;
+ << (NewTA ? 0 : 2);
S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
NewFD->setInvalidDecl();
return true;
@@ -10937,11 +11269,11 @@ static bool MultiVersionTypesCompatible(MultiVersionKind Old,
/// multiversioned declaration collection.
static bool CheckMultiVersionAdditionalDecl(
Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD,
- MultiVersionKind NewMVKind, const TargetAttr *NewTA,
- const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec,
- const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl,
- LookupResult &Previous) {
-
+ MultiVersionKind NewMVKind, const CPUDispatchAttr *NewCPUDisp,
+ const CPUSpecificAttr *NewCPUSpec, const TargetClonesAttr *NewClones,
+ bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) {
+ const auto *NewTA = NewFD->getAttr<TargetAttr>();
+ const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
MultiVersionKind OldMVKind = OldFD->getMultiVersionKind();
// Disallow mixing of multiversioning types.
if (!MultiVersionTypesCompatible(OldMVKind, NewMVKind)) {
@@ -10953,9 +11285,15 @@ static bool CheckMultiVersionAdditionalDecl(
ParsedTargetAttr NewParsed;
if (NewTA) {
- NewParsed = NewTA->parse();
+ NewParsed = S.getASTContext().getTargetInfo().parseTargetAttr(
+ NewTA->getFeaturesStr());
llvm::sort(NewParsed.Features);
}
+ llvm::SmallVector<StringRef, 8> NewFeats;
+ if (NewTVA) {
+ NewTVA->getFeatures(NewFeats);
+ llvm::sort(NewFeats);
+ }
bool UseMemberUsingDeclRules =
S.CurContext->isRecord() && !NewFD->getFriendObjectKind();
@@ -10963,16 +11301,30 @@ static bool CheckMultiVersionAdditionalDecl(
bool MayNeedOverloadableChecks =
AllowOverloadingOfFunction(Previous, S.Context, NewFD);
- // Next, check ALL non-overloads to see if this is a redeclaration of a
- // previous member of the MultiVersion set.
+ // Next, check ALL non-invalid non-overloads to see if this is a redeclaration
+ // of a previous member of the MultiVersion set.
for (NamedDecl *ND : Previous) {
FunctionDecl *CurFD = ND->getAsFunction();
- if (!CurFD)
+ if (!CurFD || CurFD->isInvalidDecl())
continue;
if (MayNeedOverloadableChecks &&
S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))
continue;
+ if (NewMVKind == MultiVersionKind::None &&
+ OldMVKind == MultiVersionKind::TargetVersion) {
+ NewFD->addAttr(TargetVersionAttr::CreateImplicit(
+ S.Context, "default", NewFD->getSourceRange(),
+ AttributeCommonInfo::AS_GNU));
+ NewFD->setIsMultiVersion();
+ NewMVKind = MultiVersionKind::TargetVersion;
+ if (!NewTVA) {
+ NewTVA = NewFD->getAttr<TargetVersionAttr>();
+ NewTVA->getFeatures(NewFeats);
+ llvm::sort(NewFeats);
+ }
+ }
+
switch (NewMVKind) {
case MultiVersionKind::None:
assert(OldMVKind == MultiVersionKind::TargetClones &&
@@ -10987,7 +11339,10 @@ static bool CheckMultiVersionAdditionalDecl(
return false;
}
- ParsedTargetAttr CurParsed = CurTA->parse(std::less<std::string>());
+ ParsedTargetAttr CurParsed =
+ S.getASTContext().getTargetInfo().parseTargetAttr(
+ CurTA->getFeaturesStr());
+ llvm::sort(CurParsed.Features);
if (CurParsed == NewParsed) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
S.Diag(CurFD->getLocation(), diag::note_previous_declaration);
@@ -10996,6 +11351,27 @@ static bool CheckMultiVersionAdditionalDecl(
}
break;
}
+ case MultiVersionKind::TargetVersion: {
+ const auto *CurTVA = CurFD->getAttr<TargetVersionAttr>();
+ if (CurTVA->getName() == NewTVA->getName()) {
+ NewFD->setIsMultiVersion();
+ Redeclaration = true;
+ OldDecl = ND;
+ return false;
+ }
+ llvm::SmallVector<StringRef, 8> CurFeats;
+ if (CurTVA) {
+ CurTVA->getFeatures(CurFeats);
+ llvm::sort(CurFeats);
+ }
+ if (CurFeats == NewFeats) {
+ S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate);
+ S.Diag(CurFD->getLocation(), diag::note_previous_declaration);
+ NewFD->setInvalidDecl();
+ return true;
+ }
+ break;
+ }
case MultiVersionKind::TargetClones: {
const auto *CurClones = CurFD->getAttr<TargetClonesAttr>();
Redeclaration = true;
@@ -11078,7 +11454,8 @@ static bool CheckMultiVersionAdditionalDecl(
// Else, this is simply a non-redecl case. Checking the 'value' is only
// necessary in the Target case, since The CPUSpecific/Dispatch cases are
// handled in the attribute adding step.
- if (NewMVKind == MultiVersionKind::Target &&
+ if ((NewMVKind == MultiVersionKind::TargetVersion ||
+ NewMVKind == MultiVersionKind::Target) &&
CheckMultiVersionValue(S, NewFD)) {
NewFD->setInvalidDecl();
return true;
@@ -11116,16 +11493,20 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
bool &Redeclaration, NamedDecl *&OldDecl,
LookupResult &Previous) {
const auto *NewTA = NewFD->getAttr<TargetAttr>();
+ const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>();
const auto *NewCPUSpec = NewFD->getAttr<CPUSpecificAttr>();
const auto *NewClones = NewFD->getAttr<TargetClonesAttr>();
MultiVersionKind MVKind = NewFD->getMultiVersionKind();
// Main isn't allowed to become a multiversion function, however it IS
- // permitted to have 'main' be marked with the 'target' optimization hint.
+ // permitted to have 'main' be marked with the 'target' optimization hint,
+ // for 'target_version' only default is allowed.
if (NewFD->isMain()) {
if (MVKind != MultiVersionKind::None &&
- !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion())) {
+ !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion()) &&
+ !(MVKind == MultiVersionKind::TargetVersion &&
+ NewTVA->isDefaultVersion())) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main);
NewFD->setInvalidDecl();
return true;
@@ -11140,18 +11521,34 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
// multiversioning, this isn't an error condition.
if (MVKind == MultiVersionKind::None)
return false;
- return CheckMultiVersionFirstFunction(S, NewFD, MVKind, NewTA);
+ return CheckMultiVersionFirstFunction(S, NewFD);
}
FunctionDecl *OldFD = OldDecl->getAsFunction();
- if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None)
+ if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) {
+ // No target_version attributes mean default
+ if (!NewTVA) {
+ const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();
+ if (OldTVA) {
+ NewFD->addAttr(TargetVersionAttr::CreateImplicit(
+ S.Context, "default", NewFD->getSourceRange(),
+ AttributeCommonInfo::AS_GNU));
+ NewFD->setIsMultiVersion();
+ OldFD->setIsMultiVersion();
+ OldDecl = OldFD;
+ Redeclaration = true;
+ return true;
+ }
+ }
return false;
+ }
// Multiversioned redeclarations aren't allowed to omit the attribute, except
- // for target_clones.
+ // for target_clones and target_version.
if (OldFD->isMultiVersion() && MVKind == MultiVersionKind::None &&
- OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones) {
+ OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones &&
+ OldFD->getMultiVersionKind() != MultiVersionKind::TargetVersion) {
S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl)
<< (OldFD->getMultiVersionKind() != MultiVersionKind::Target);
NewFD->setInvalidDecl();
@@ -11161,8 +11558,9 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
if (!OldFD->isMultiVersion()) {
switch (MVKind) {
case MultiVersionKind::Target:
- return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA,
- Redeclaration, OldDecl, Previous);
+ case MultiVersionKind::TargetVersion:
+ return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, Redeclaration,
+ OldDecl, Previous);
case MultiVersionKind::TargetClones:
if (OldFD->isUsed(false)) {
NewFD->setInvalidDecl();
@@ -11170,6 +11568,7 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
}
OldFD->setIsMultiVersion();
break;
+
case MultiVersionKind::CPUDispatch:
case MultiVersionKind::CPUSpecific:
case MultiVersionKind::None:
@@ -11180,9 +11579,9 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
// At this point, we have a multiversion function decl (in OldFD) AND an
// appropriate attribute in the current function decl. Resolve that these are
// still compatible with previous declarations.
- return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewTA,
- NewCPUDisp, NewCPUSpec, NewClones,
- Redeclaration, OldDecl, Previous);
+ return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewCPUDisp,
+ NewCPUSpec, NewClones, Redeclaration,
+ OldDecl, Previous);
}
/// Perform semantic checking of a new function declaration.
@@ -11410,16 +11809,20 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
CheckConstructor(Constructor);
} else if (CXXDestructorDecl *Destructor =
- dyn_cast<CXXDestructorDecl>(NewFD)) {
- CXXRecordDecl *Record = Destructor->getParent();
- QualType ClassType = Context.getTypeDeclType(Record);
-
- // FIXME: Shouldn't we be able to perform this check even when the class
- // type is dependent? Both gcc and edg can handle that.
- if (!ClassType->isDependentType()) {
- DeclarationName Name
- = Context.DeclarationNames.getCXXDestructorName(
- Context.getCanonicalType(ClassType));
+ dyn_cast<CXXDestructorDecl>(NewFD)) {
+ // We check here for invalid destructor names.
+ // If we have a friend destructor declaration that is dependent, we can't
+ // diagnose right away because cases like this are still valid:
+ // template <class T> struct A { friend T::X::~Y(); };
+ // struct B { struct Y { ~Y(); }; using X = Y; };
+ // template struct A<B>;
+ if (NewFD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None ||
+ !Destructor->getThisType()->isDependentType()) {
+ CXXRecordDecl *Record = Destructor->getParent();
+ QualType ClassType = Context.getTypeDeclType(Record);
+
+ DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(
+ Context.getCanonicalType(ClassType));
if (NewFD->getDeclName() != Name) {
Diag(NewFD->getLocation(), diag::err_destructor_name);
NewFD->setInvalidDecl();
@@ -11756,6 +12159,34 @@ void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) {
}
}
+void Sema::CheckHLSLEntryPoint(FunctionDecl *FD) {
+ auto &TargetInfo = getASTContext().getTargetInfo();
+ auto const Triple = TargetInfo.getTriple();
+ switch (Triple.getEnvironment()) {
+ default:
+ // FIXME: check all shader profiles.
+ break;
+ case llvm::Triple::EnvironmentType::Compute:
+ if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
+ Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
+ << Triple.getEnvironmentName();
+ FD->setInvalidDecl();
+ }
+ break;
+ }
+
+ for (const auto *Param : FD->parameters()) {
+ if (!Param->hasAttr<HLSLAnnotationAttr>()) {
+ // FIXME: Handle struct parameters where annotations are on struct fields.
+ // See: https://github.com/llvm/llvm-project/issues/57875
+ Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
+ Diag(Param->getLocation(), diag::note_previous_decl) << Param;
+ FD->setInvalidDecl();
+ }
+ }
+ // FIXME: Verify return type semantic annotation.
+}
+
bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
// FIXME: Need strict checking. In C89, we need to check for
// any assignment, increment, decrement, function-calls, or
@@ -11822,7 +12253,7 @@ namespace {
// Track and increment the index here.
isInitList = true;
InitFieldIndex.push_back(0);
- for (auto Child : InitList->children()) {
+ for (auto *Child : InitList->children()) {
CheckExpr(cast<Expr>(Child));
++InitFieldIndex.back();
}
@@ -12224,7 +12655,10 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
Type.getQualifiers());
QualType DeducedType;
- if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) {
+ TemplateDeductionInfo Info(DeduceInit->getExprLoc());
+ TemplateDeductionResult Result =
+ DeduceAutoType(TSI->getTypeLoc(), DeduceInit, DeducedType, Info);
+ if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) {
if (!IsInitCapture)
DiagnoseAutoDeductionFailure(VDecl, DeduceInit);
else if (isa<InitListExpr>(Init))
@@ -12303,7 +12737,7 @@ void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init,
InitType.hasNonTrivialToPrimitiveCopyCUnion()) &&
"shouldn't be called if type doesn't have a non-trivial C struct");
if (auto *ILE = dyn_cast<InitListExpr>(Init)) {
- for (auto I : ILE->inits()) {
+ for (auto *I : ILE->inits()) {
if (!I->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() &&
!I->getType().hasNonTrivialToPrimitiveCopyCUnion())
continue;
@@ -12621,8 +13055,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
return;
}
+ // C99 6.7.8p5. If the declaration of an identifier has block scope, and
+ // the identifier has external or internal linkage, the declaration shall
+ // have no initializer for the identifier.
+ // C++14 [dcl.init]p5 is the same restriction for C++.
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
- // C99 6.7.8p5. C++ has no such restriction, but that is a defect.
Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
VDecl->setInvalidDecl();
return;
@@ -12648,6 +13085,16 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
VDecl->setInvalidDecl();
}
+ // C++ [module.import/6] external definitions are not permitted in header
+ // units.
+ if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() &&
+ VDecl->isThisDeclarationADefinition() &&
+ VDecl->getFormalLinkage() == Linkage::ExternalLinkage &&
+ !VDecl->isInline()) {
+ Diag(VDecl->getLocation(), diag::err_extern_def_in_header_unit);
+ VDecl->setInvalidDecl();
+ }
+
// If adding the initializer will turn this declaration into a definition,
// and we already have a definition for this variable, diagnose or otherwise
// handle the situation.
@@ -12722,6 +13169,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// Perform the initialization.
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+ bool IsParenListInit = false;
if (!VDecl->isInvalidDecl()) {
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
InitializationKind Kind = InitializationKind::CreateForInit(
@@ -12764,6 +13212,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
}
Init = Result.getAs<Expr>();
+ IsParenListInit = !InitSeq.steps().empty() &&
+ InitSeq.step_begin()->Kind ==
+ InitializationSequence::SK_ParenthesizedListInit;
}
// Check for self-references within variable initializers.
@@ -13012,7 +13463,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// class type.
if (CXXDirectInit) {
assert(DirectInit && "Call-style initializer must be direct init.");
- VDecl->setInitStyle(VarDecl::CallInit);
+ VDecl->setInitStyle(IsParenListInit ? VarDecl::ParenListInit
+ : VarDecl::CallInit);
} else if (DirectInit) {
// This must be list-initialization. No other way is direct-initialization.
VDecl->setInitStyle(VarDecl::ListInit);
@@ -13177,7 +13629,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// that has an in-class initializer, so we type-check this like
// a declaration.
//
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case VarDecl::DeclarationOnly:
// It's only a declaration.
@@ -13247,8 +13699,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
// Provide a specific diagnostic for uninitialized variable
// definitions with incomplete array type.
if (Type->isIncompleteArrayType()) {
- Diag(Var->getLocation(),
- diag::err_typecheck_incomplete_array_needs_initializer);
+ if (Var->isConstexpr())
+ Diag(Var->getLocation(), diag::err_constexpr_var_requires_const_init)
+ << Var;
+ else
+ Diag(Var->getLocation(),
+ diag::err_typecheck_incomplete_array_needs_initializer);
Var->setInvalidDecl();
return;
}
@@ -13332,8 +13788,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
InitializationKind Kind
= InitializationKind::CreateDefault(Var->getLocation());
- InitializationSequence InitSeq(*this, Entity, Kind, None);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None);
+ InitializationSequence InitSeq(*this, Entity, Kind, std::nullopt);
+ ExprResult Init = InitSeq.Perform(*this, Entity, Kind, std::nullopt);
if (Init.get()) {
Var->setInit(MaybeCreateExprWithCleanups(Init.get()));
@@ -13499,7 +13955,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
// Cache the result of checking for constant initialization.
- Optional<bool> CacheHasConstInit;
+ std::optional<bool> CacheHasConstInit;
const Expr *CacheCulprit = nullptr;
auto checkConstInit = [&]() mutable {
if (!CacheHasConstInit)
@@ -13770,6 +14226,26 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) {
}
}
+void Sema::CheckThreadLocalForLargeAlignment(VarDecl *VD) {
+ assert(VD->getTLSKind());
+
+ // Perform TLS alignment check here after attributes attached to the variable
+ // which may affect the alignment have been processed. Only perform the check
+ // if the target has a maximum TLS alignment (zero means no constraints).
+ if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
+ // Protect the check so that it's not performed on dependent types and
+ // dependent alignments (we can't determine the alignment in that case).
+ if (!VD->hasDependentAlignment()) {
+ CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
+ if (Context.getDeclAlign(VD) > MaxAlignChars) {
+ Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
+ << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD
+ << (unsigned)MaxAlignChars.getQuantity();
+ }
+ }
+ }
+}
+
/// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform
/// any semantic actions necessary after any initializer has been attached.
void Sema::FinalizeDeclaration(Decl *ThisDecl) {
@@ -13813,25 +14289,12 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
checkAttributesAfterMerging(*this, *VD);
- // Perform TLS alignment check here after attributes attached to the variable
- // which may affect the alignment have been processed. Only perform the check
- // if the target has a maximum TLS alignment (zero means no constraints).
- if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) {
- // Protect the check so that it's not performed on dependent types and
- // dependent alignments (we can't determine the alignment in that case).
- if (VD->getTLSKind() && !VD->hasDependentAlignment()) {
- CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign);
- if (Context.getDeclAlign(VD) > MaxAlignChars) {
- Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
- << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD
- << (unsigned)MaxAlignChars.getQuantity();
- }
- }
- }
-
if (VD->isStaticLocal())
CheckStaticLocalForDllExport(VD);
+ if (VD->getTLSKind())
+ CheckThreadLocalForLargeAlignment(VD);
+
// Perform check for initializers of device-side global variables.
// CUDA allows empty constructors as initializers (see E.2.3.1, CUDA
// 7.5). We must also apply the same checks to all __shared__
@@ -13917,7 +14380,7 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (!MagicValueExpr) {
continue;
}
- Optional<llvm::APSInt> MagicValueInt;
+ std::optional<llvm::APSInt> MagicValueInt;
if (!(MagicValueInt = MagicValueExpr->getIntegerConstantExpr(Context))) {
Diag(I->getRange().getBegin(),
diag::err_type_tag_for_datatype_not_ice)
@@ -14462,6 +14925,21 @@ void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) {
Consumer.HandleInlineFunctionDefinition(D);
}
+static bool FindPossiblePrototype(const FunctionDecl *FD,
+ const FunctionDecl *&PossiblePrototype) {
+ for (const FunctionDecl *Prev = FD->getPreviousDecl(); Prev;
+ Prev = Prev->getPreviousDecl()) {
+ // Ignore any declarations that occur in function or method
+ // scope, because they aren't visible from the header.
+ if (Prev->getLexicalDeclContext()->isFunctionOrMethod())
+ continue;
+
+ PossiblePrototype = Prev;
+ return Prev->getType()->isFunctionProtoType();
+ }
+ return false;
+}
+
static bool
ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
const FunctionDecl *&PossiblePrototype) {
@@ -14508,16 +14986,9 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
if (!FD->isExternallyVisible())
return false;
- for (const FunctionDecl *Prev = FD->getPreviousDecl();
- Prev; Prev = Prev->getPreviousDecl()) {
- // Ignore any declarations that occur in function or method
- // scope, because they aren't visible from the header.
- if (Prev->getLexicalDeclContext()->isFunctionOrMethod())
- continue;
-
- PossiblePrototype = Prev;
- return Prev->getType()->isFunctionNoProtoType();
- }
+ // If we were able to find a potential prototype, don't warn.
+ if (FindPossiblePrototype(FD, PossiblePrototype))
+ return false;
return true;
}
@@ -14604,7 +15075,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
auto I = LambdaClass->field_begin();
for (const auto &C : LambdaClass->captures()) {
if (C.capturesVariable()) {
- VarDecl *VD = C.getCapturedVar();
+ ValueDecl *VD = C.getCapturedVar();
if (VD->isInitCapture())
S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
const bool ByRef = C.getCaptureKind() == LCK_ByRef;
@@ -14646,8 +15117,12 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
// Do not push if it is a lambda because one is already pushed when building
// the lambda in ActOnStartOfLambdaDefinition().
if (!isLambdaCallOperator(FD))
+ // [expr.const]/p14.1
+ // An expression or conversion is in an immediate function context if it is
+ // potentially evaluated and either: its innermost enclosing non-block scope
+ // is a function parameter scope of an immediate function.
PushExpressionEvaluationContext(
- FD->isConsteval() ? ExpressionEvaluationContext::ConstantEvaluated
+ FD->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext
: ExprEvalContexts.back().Context);
// Check for defining attributes before the check for redefinition.
@@ -14661,6 +15136,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
FD->dropAttr<IFuncAttr>();
FD->setInvalidDecl();
}
+ if (const auto *Attr = FD->getAttr<TargetVersionAttr>()) {
+ if (!Context.getTargetInfo().hasFeature("fmv") &&
+ !Attr->isDefaultVersion()) {
+ // If function multi versioning disabled skip parsing function body
+ // defined with non-default target_version attribute
+ if (SkipBody)
+ SkipBody->ShouldSkip = true;
+ return nullptr;
+ }
+ }
if (auto *Ctor = dyn_cast<CXXConstructorDecl>(FD)) {
if (Ctor->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
@@ -14757,7 +15242,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
}
// Introduce our parameters into the function scope
- for (auto Param : FD->parameters()) {
+ for (auto *Param : FD->parameters()) {
Param->setOwningFunction(FD);
// If this has an identifier, add it to the scope stack.
@@ -14768,6 +15253,20 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
}
}
+ // C++ [module.import/6] external definitions are not permitted in header
+ // units. Deleted and Defaulted functions are implicitly inline (but the
+ // inline state is not set at this point, so check the BodyKind explicitly).
+ // FIXME: Consider an alternate location for the test where the inlined()
+ // state is complete.
+ if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() &&
+ FD->getFormalLinkage() == Linkage::ExternalLinkage &&
+ !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete &&
+ BodyKind != FnBodyKind::Default && !FD->isInlined()) {
+ assert(FD->isThisDeclarationADefinition());
+ Diag(FD->getLocation(), diag::err_extern_def_in_header_unit);
+ FD->setInvalidDecl();
+ }
+
// Ensure that the function's exception specification is instantiated.
if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>())
ResolveExceptionSpec(D->getLocation(), FPT);
@@ -15081,6 +15580,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
}
}
+ // We might not have found a prototype because we didn't wish to warn on
+ // the lack of a missing prototype. Try again without the checks for
+ // whether we want to warn on the missing prototype.
+ if (!PossiblePrototype)
+ (void)FindPossiblePrototype(FD, PossiblePrototype);
+
// If the function being defined does not have a prototype, then we may
// need to diagnose it as changing behavior in C2x because we now know
// whether the function accepts arguments or not. This only handles the
@@ -15405,8 +15910,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// Because typo correction is expensive, only do it if the implicit
// function declaration is going to be treated as an error.
//
- // Perform the corection before issuing the main diagnostic, as some consumers
- // use typo-correction callbacks to enhance the main diagnostic.
+ // Perform the correction before issuing the main diagnostic, as some
+ // consumers use typo-correction callbacks to enhance the main diagnostic.
if (S && !ExternCPrev &&
(Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error)) {
DeclFilterCCC<FunctionDecl> CCC{};
@@ -15459,8 +15964,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
- /*DeclsInPrototype=*/None, Loc,
- Loc, D),
+ /*DeclsInPrototype=*/std::nullopt,
+ Loc, Loc, D),
std::move(DS.getAttributes()), SourceLocation());
D.SetIdentifier(&II, Loc);
@@ -15488,7 +15993,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(
FD->getDeclName().getCXXOverloadedOperator() != OO_Array_New)
return;
- Optional<unsigned> AlignmentParam;
+ std::optional<unsigned> AlignmentParam;
bool IsNothrow = false;
if (!FD->isReplaceableGlobalAllocationFunction(&AlignmentParam, &IsNothrow))
return;
@@ -15529,7 +16034,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(
// specified by the value of this argument.
if (AlignmentParam && !FD->hasAttr<AllocAlignAttr>()) {
FD->addAttr(AllocAlignAttr::CreateImplicit(
- Context, ParamIdx(AlignmentParam.value(), FD), FD->getLocation()));
+ Context, ParamIdx(*AlignmentParam, FD), FD->getLocation()));
}
// FIXME:
@@ -15594,11 +16099,20 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
FD->addAttr(CallbackAttr::CreateImplicit(
Context, Encoding.data(), Encoding.size(), FD->getLocation()));
- // Mark const if we don't care about errno and that is the only thing
- // preventing the function from being const. This allows IRgen to use LLVM
- // intrinsics for such functions.
- if (!getLangOpts().MathErrno && !FD->hasAttr<ConstAttr>() &&
- Context.BuiltinInfo.isConstWithoutErrno(BuiltinID))
+ // Mark const if we don't care about errno and/or floating point exceptions
+ // that are the only thing preventing the function from being const. This
+ // allows IRgen to use LLVM intrinsics for such functions.
+ bool NoExceptions =
+ getLangOpts().getDefaultExceptionMode() == LangOptions::FPE_Ignore;
+ bool ConstWithoutErrnoAndExceptions =
+ Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID);
+ bool ConstWithoutExceptions =
+ Context.BuiltinInfo.isConstWithoutExceptions(BuiltinID);
+ if (!FD->hasAttr<ConstAttr>() &&
+ (ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) &&
+ (!ConstWithoutErrnoAndExceptions ||
+ (!getLangOpts().MathErrno && NoExceptions)) &&
+ (!ConstWithoutExceptions || NoExceptions))
FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
// We make "fma" on GNU or Windows const because we know it does not set
@@ -15674,6 +16188,24 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
default:
break;
}
+
+ // Add lifetime attribute to std::move, std::fowrard et al.
+ switch (BuiltinID) {
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
+ case Builtin::BI__builtin_addressof:
+ case Builtin::BIas_const:
+ case Builtin::BIforward:
+ case Builtin::BImove:
+ case Builtin::BImove_if_noexcept:
+ if (ParmVarDecl *P = FD->getParamDecl(0u);
+ !P->hasAttr<LifetimeBoundAttr>())
+ P->addAttr(
+ LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
+ break;
+ default:
+ break;
+ }
}
AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
@@ -16075,17 +16607,17 @@ static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC,
///
/// \param SkipBody If non-null, will be set to indicate if the caller should
/// skip the definition of this tag and treat it as if it were a declaration.
-Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
- SourceLocation KWLoc, CXXScopeSpec &SS,
- IdentifierInfo *Name, SourceLocation NameLoc,
- const ParsedAttributesView &Attrs, AccessSpecifier AS,
- SourceLocation ModulePrivateLoc,
- MultiTemplateParamsArg TemplateParameterLists,
- bool &OwnedDecl, bool &IsDependent,
- SourceLocation ScopedEnumKWLoc,
- bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
- bool IsTypeSpecifier, bool IsTemplateParamOrArg,
- SkipBodyInfo *SkipBody) {
+DeclResult
+Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
+ CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
+ const ParsedAttributesView &Attrs, AccessSpecifier AS,
+ SourceLocation ModulePrivateLoc,
+ MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl,
+ bool &IsDependent, SourceLocation ScopedEnumKWLoc,
+ bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
+ bool IsTypeSpecifier, bool IsTemplateParamOrArg,
+ OffsetOfKind OOK, UsingShadowDecl *&FoundUsingShadow,
+ SkipBodyInfo *SkipBody) {
// If this is not a definition, it must have a name.
IdentifierInfo *OrigName = Name;
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -16111,7 +16643,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TUK == TUK_Friend, isMemberSpecialization, Invalid)) {
if (Kind == TTK_Enum) {
Diag(KWLoc, diag::err_enum_template);
- return nullptr;
+ return true;
}
if (TemplateParams->size() > 0) {
@@ -16119,7 +16651,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// be a member of another template).
if (Invalid)
- return nullptr;
+ return true;
OwnedDecl = false;
DeclResult Result = CheckClassTemplate(
@@ -16138,7 +16670,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (!TemplateParameterLists.empty() && isMemberSpecialization &&
CheckTemplateDeclScope(S, TemplateParameterLists.back()))
- return nullptr;
+ return true;
}
// Figure out the underlying type if this a enum declaration. We need to do
@@ -16210,7 +16742,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
else
ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0));
QualType EnumTy = ED->getIntegerType();
- ED->setPromotionType(EnumTy->isPromotableIntegerType()
+ ED->setPromotionType(Context.isPromotableIntegerType(EnumTy)
? Context.getPromotedIntegerType(EnumTy)
: EnumTy);
}
@@ -16254,26 +16786,26 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
DC = computeDeclContext(SS, false);
if (!DC) {
IsDependent = true;
- return nullptr;
+ return true;
}
} else {
DC = computeDeclContext(SS, true);
if (!DC) {
Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec)
<< SS.getRange();
- return nullptr;
+ return true;
}
}
if (RequireCompleteDeclContext(SS, DC))
- return nullptr;
+ return true;
SearchDC = DC;
// Look-up name inside 'foo::'.
LookupQualifiedName(Previous, DC);
if (Previous.isAmbiguous())
- return nullptr;
+ return true;
if (Previous.empty()) {
// Name lookup did not find anything. However, if the
@@ -16285,7 +16817,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.wasNotFoundInCurrentInstantiation() &&
(TUK == TUK_Reference || TUK == TUK_Friend)) {
IsDependent = true;
- return nullptr;
+ return true;
}
// A tag 'foo::bar' must already exist.
@@ -16302,7 +16834,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// -- every member of class T that is itself a type
if (TUK != TUK_Reference && TUK != TUK_Friend &&
DiagnoseClassNameShadow(SearchDC, DeclarationNameInfo(Name, NameLoc)))
- return nullptr;
+ return true;
// If this is a named struct, check to see if there was a previous forward
// declaration or definition.
@@ -16366,7 +16898,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Note: there used to be some attempt at recovery here.
if (Previous.isAmbiguous())
- return nullptr;
+ return true;
if (!getLangOpts().CPlusPlus && TUK != TUK_Reference) {
// FIXME: This makes sure that we ignore the contexts associated
@@ -16520,6 +17052,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// redefinition if either context is within the other.
if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) {
auto *OldTag = dyn_cast<TagDecl>(PrevDecl);
+ FoundUsingShadow = Shadow;
if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend &&
isDeclInScope(Shadow, SearchDC, S, isMemberSpecialization) &&
!(OldTag && isAcceptableTagRedeclContext(
@@ -16836,7 +17369,7 @@ CreateNewDecl:
else
ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0));
QualType EnumTy = ED->getIntegerType();
- ED->setPromotionType(EnumTy->isPromotableIntegerType()
+ ED->setPromotionType(Context.isPromotableIntegerType(EnumTy)
? Context.getPromotedIntegerType(EnumTy)
: EnumTy);
assert(ED->isComplete() && "enum with type should be complete");
@@ -16858,10 +17391,14 @@ CreateNewDecl:
cast_or_null<RecordDecl>(PrevDecl));
}
+ if (OOK != OOK_Outside && TUK == TUK_Definition && !getLangOpts().CPlusPlus)
+ Diag(New->getLocation(), diag::ext_type_defined_in_offsetof)
+ << (OOK == OOK_Macro) << New->getSourceRange();
+
// C++11 [dcl.type]p3:
// A type-specifier-seq shall not define a class or enumeration [...].
- if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) &&
- TUK == TUK_Definition) {
+ if (!Invalid && getLangOpts().CPlusPlus &&
+ (IsTypeSpecifier || IsTemplateParamOrArg) && TUK == TUK_Definition) {
Diag(New->getLocation(), diag::err_type_defined_in_type_specifier)
<< Context.getTagDeclType(New);
Invalid = true;
@@ -17017,7 +17554,7 @@ CreateNewDecl:
if (New->isBeingDefined())
if (auto RD = dyn_cast<RecordDecl>(New))
RD->completeDefinition();
- return nullptr;
+ return true;
} else if (SkipBody && SkipBody->ShouldSkip) {
return SkipBody->Previous;
} else {
@@ -17805,7 +18342,6 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
AllIvarDecls.push_back(Ivar);
}
-namespace {
/// [class.dtor]p4:
/// At the end of the definition of a class, overload resolution is
/// performed among the prospective destructors declared in that class with
@@ -17814,7 +18350,7 @@ namespace {
///
/// We do the overload resolution here, then mark the selected constructor in the AST.
/// Later CXXRecordDecl::getDestructor() will return the selected constructor.
-void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) {
+static void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) {
if (!Record->hasUserDeclaredDestructor()) {
return;
}
@@ -17872,7 +18408,145 @@ void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) {
Record->addedSelectedDestructor(dyn_cast<CXXDestructorDecl>(OCS.begin()->Function));
}
}
-} // namespace
+
+/// [class.mem.special]p5
+/// Two special member functions are of the same kind if:
+/// - they are both default constructors,
+/// - they are both copy or move constructors with the same first parameter
+/// type, or
+/// - they are both copy or move assignment operators with the same first
+/// parameter type and the same cv-qualifiers and ref-qualifier, if any.
+static bool AreSpecialMemberFunctionsSameKind(ASTContext &Context,
+ CXXMethodDecl *M1,
+ CXXMethodDecl *M2,
+ Sema::CXXSpecialMember CSM) {
+ // We don't want to compare templates to non-templates: See
+ // https://github.com/llvm/llvm-project/issues/59206
+ if (CSM == Sema::CXXDefaultConstructor)
+ return bool(M1->getDescribedFunctionTemplate()) ==
+ bool(M2->getDescribedFunctionTemplate());
+ if (!Context.hasSameType(M1->getParamDecl(0)->getType(),
+ M2->getParamDecl(0)->getType()))
+ return false;
+ if (!Context.hasSameType(M1->getThisType(), M2->getThisType()))
+ return false;
+
+ return true;
+}
+
+/// [class.mem.special]p6:
+/// An eligible special member function is a special member function for which:
+/// - the function is not deleted,
+/// - the associated constraints, if any, are satisfied, and
+/// - no special member function of the same kind whose associated constraints
+/// [CWG2595], if any, are satisfied is more constrained.
+static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record,
+ ArrayRef<CXXMethodDecl *> Methods,
+ Sema::CXXSpecialMember CSM) {
+ SmallVector<bool, 4> SatisfactionStatus;
+
+ for (CXXMethodDecl *Method : Methods) {
+ const Expr *Constraints = Method->getTrailingRequiresClause();
+ if (!Constraints)
+ SatisfactionStatus.push_back(true);
+ else {
+ ConstraintSatisfaction Satisfaction;
+ if (S.CheckFunctionConstraints(Method, Satisfaction))
+ SatisfactionStatus.push_back(false);
+ else
+ SatisfactionStatus.push_back(Satisfaction.IsSatisfied);
+ }
+ }
+
+ for (size_t i = 0; i < Methods.size(); i++) {
+ if (!SatisfactionStatus[i])
+ continue;
+ CXXMethodDecl *Method = Methods[i];
+ CXXMethodDecl *OrigMethod = Method;
+ if (FunctionDecl *MF = OrigMethod->getInstantiatedFromMemberFunction())
+ OrigMethod = cast<CXXMethodDecl>(MF);
+
+ const Expr *Constraints = OrigMethod->getTrailingRequiresClause();
+ bool AnotherMethodIsMoreConstrained = false;
+ for (size_t j = 0; j < Methods.size(); j++) {
+ if (i == j || !SatisfactionStatus[j])
+ continue;
+ CXXMethodDecl *OtherMethod = Methods[j];
+ if (FunctionDecl *MF = OtherMethod->getInstantiatedFromMemberFunction())
+ OtherMethod = cast<CXXMethodDecl>(MF);
+
+ if (!AreSpecialMemberFunctionsSameKind(S.Context, OrigMethod, OtherMethod,
+ CSM))
+ continue;
+
+ const Expr *OtherConstraints = OtherMethod->getTrailingRequiresClause();
+ if (!OtherConstraints)
+ continue;
+ if (!Constraints) {
+ AnotherMethodIsMoreConstrained = true;
+ break;
+ }
+ if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, OrigMethod,
+ {Constraints},
+ AnotherMethodIsMoreConstrained)) {
+ // There was an error with the constraints comparison. Exit the loop
+ // and don't consider this function eligible.
+ AnotherMethodIsMoreConstrained = true;
+ }
+ if (AnotherMethodIsMoreConstrained)
+ break;
+ }
+ // FIXME: Do not consider deleted methods as eligible after implementing
+ // DR1734 and DR1496.
+ if (!AnotherMethodIsMoreConstrained) {
+ Method->setIneligibleOrNotSelected(false);
+ Record->addedEligibleSpecialMemberFunction(Method, 1 << CSM);
+ }
+ }
+}
+
+static void ComputeSpecialMemberFunctionsEligiblity(Sema &S,
+ CXXRecordDecl *Record) {
+ SmallVector<CXXMethodDecl *, 4> DefaultConstructors;
+ SmallVector<CXXMethodDecl *, 4> CopyConstructors;
+ SmallVector<CXXMethodDecl *, 4> MoveConstructors;
+ SmallVector<CXXMethodDecl *, 4> CopyAssignmentOperators;
+ SmallVector<CXXMethodDecl *, 4> MoveAssignmentOperators;
+
+ for (auto *Decl : Record->decls()) {
+ auto *MD = dyn_cast<CXXMethodDecl>(Decl);
+ if (!MD) {
+ auto *FTD = dyn_cast<FunctionTemplateDecl>(Decl);
+ if (FTD)
+ MD = dyn_cast<CXXMethodDecl>(FTD->getTemplatedDecl());
+ }
+ if (!MD)
+ continue;
+ if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
+ if (CD->isInvalidDecl())
+ continue;
+ if (CD->isDefaultConstructor())
+ DefaultConstructors.push_back(MD);
+ else if (CD->isCopyConstructor())
+ CopyConstructors.push_back(MD);
+ else if (CD->isMoveConstructor())
+ MoveConstructors.push_back(MD);
+ } else if (MD->isCopyAssignmentOperator()) {
+ CopyAssignmentOperators.push_back(MD);
+ } else if (MD->isMoveAssignmentOperator()) {
+ MoveAssignmentOperators.push_back(MD);
+ }
+ }
+
+ SetEligibleMethods(S, Record, DefaultConstructors,
+ Sema::CXXDefaultConstructor);
+ SetEligibleMethods(S, Record, CopyConstructors, Sema::CXXCopyConstructor);
+ SetEligibleMethods(S, Record, MoveConstructors, Sema::CXXMoveConstructor);
+ SetEligibleMethods(S, Record, CopyAssignmentOperators,
+ Sema::CXXCopyAssignment);
+ SetEligibleMethods(S, Record, MoveAssignmentOperators,
+ Sema::CXXMoveAssignment);
+}
void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
ArrayRef<Decl *> Fields, SourceLocation LBrac,
@@ -17900,9 +18574,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(EnclosingDecl);
- if (CXXRecord && !CXXRecord->isDependentType())
- ComputeSelectedDestructor(*this, CXXRecord);
-
// Start counting up the number of named members; make sure to include
// members of anonymous structs and unions in the total.
unsigned NumNamedMembers = 0;
@@ -18188,6 +18859,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Completed = true;
}
}
+ ComputeSelectedDestructor(*this, CXXRecord);
+ ComputeSpecialMemberFunctionsEligiblity(*this, CXXRecord);
}
}
@@ -18910,7 +19583,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
}
}
- // If we have have an empty set of enumerators we still need one bit.
+ // If we have an empty set of enumerators we still need one bit.
// From [dcl.enum]p8
// If the enumerator-list is empty, the values of the enumeration are as if
// the enumeration had a single enumerator with value 0
@@ -18942,7 +19615,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
// target, promote that type instead of analyzing the enumerators.
if (Enum->isComplete()) {
BestType = Enum->getIntegerType();
- if (BestType->isPromotableIntegerType())
+ if (Context.isPromotableIntegerType(BestType))
BestPromotionType = Context.getPromotedIntegerType(BestType);
else
BestPromotionType = BestType;
@@ -19107,6 +19780,12 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
return New;
}
+Decl *Sema::ActOnTopLevelStmtDecl(Stmt *Statement) {
+ auto *New = TopLevelStmtDecl::Create(Context, Statement);
+ Context.getTranslationUnitDecl()->addDecl(New);
+ return New;
+}
+
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
IdentifierInfo* AliasName,
SourceLocation PragmaLoc,
@@ -19129,7 +19808,7 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
else
Diag(PrevDecl->getLocation(), diag::warn_redefine_extname_not_applied)
<< /*Variable*/(isa<FunctionDecl>(PrevDecl) ? 0 : 1) << PrevDecl;
- // Otherwise, add a label atttibute to ExtnameUndeclaredIdentifiers.
+ // Otherwise, add a label attribute to ExtnameUndeclaredIdentifiers.
} else
(void)ExtnameUndeclaredIdentifiers.insert(std::make_pair(Name, Attr));
}
@@ -19195,7 +19874,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
if (LangOpts.OpenMPIsDevice) {
// In OpenMP device mode we will not emit host only functions, or functions
// we don't need due to their linkage.
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
// DevTy may be changed later by
// #pragma omp declare target to(*) device_type(*).
@@ -19217,7 +19896,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
// In OpenMP host compilation prior to 5.0 everything was an emitted host
// function. In 5.0, no_host was introduced which might cause a function to
// be ommitted.
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
if (DevTy)
if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 838fd48357fb..a303c7f57280 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/DarwinSDKInfo.h"
+#include "clang/Basic/HLSLRuntime.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -38,7 +39,6 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Assumptions.h"
@@ -46,6 +46,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -201,7 +202,7 @@ static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
/// A helper function to provide Attribute Location for the Attr types
/// AND the ParsedAttr.
template <typename AttrInfo>
-static std::enable_if_t<std::is_base_of<Attr, AttrInfo>::value, SourceLocation>
+static std::enable_if_t<std::is_base_of_v<Attr, AttrInfo>, SourceLocation>
getAttrLoc(const AttrInfo &AL) {
return AL.getLocation();
}
@@ -216,7 +217,7 @@ template <typename AttrInfo>
static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,
uint32_t &Val, unsigned Idx = UINT_MAX,
bool StrictlyUnsigned = false) {
- Optional<llvm::APSInt> I = llvm::APSInt(32);
+ std::optional<llvm::APSInt> I = llvm::APSInt(32);
if (Expr->isTypeDependent() ||
!(I = Expr->getIntegerConstantExpr(S.Context))) {
if (Idx != UINT_MAX)
@@ -308,7 +309,7 @@ static bool checkFunctionOrMethodParameterIndex(
unsigned NumParams =
(HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam;
- Optional<llvm::APSInt> IdxInt;
+ std::optional<llvm::APSInt> IdxInt;
if (IdxExpr->isTypeDependent() ||
!(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) {
S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
@@ -1689,7 +1690,7 @@ void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
}
if (!E->isValueDependent()) {
- Optional<llvm::APSInt> I = llvm::APSInt(64);
+ std::optional<llvm::APSInt> I = llvm::APSInt(64);
if (!(I = E->getIntegerConstantExpr(Context))) {
if (OE)
Diag(AttrLoc, diag::err_attribute_argument_n_type)
@@ -1876,8 +1877,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
for (const auto *I : D->specific_attrs<OwnershipAttr>()) {
// Cannot have two ownership attributes of different kinds for the same
// index.
- if (I->getOwnKind() != K && I->args_end() !=
- std::find(I->args_begin(), I->args_end(), Idx)) {
+ if (I->getOwnKind() != K && llvm::is_contained(I->args(), Idx)) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I;
return;
} else if (K == OwnershipAttr::Returns &&
@@ -2329,6 +2329,10 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
uint32_t priority = ConstructorAttr::DefaultPriority;
+ if (S.getLangOpts().HLSL && AL.getNumArgs()) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
+ return;
+ }
if (AL.getNumArgs() &&
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
return;
@@ -2630,7 +2634,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
if (II->isStr("fuchsia")) {
- Optional<unsigned> Min, Sub;
+ std::optional<unsigned> Min, Sub;
if ((Min = Introduced.Version.getMinor()) ||
(Sub = Introduced.Version.getSubminor())) {
S.Diag(AL.getLoc(), diag::warn_availability_fuchsia_unavailable_minor);
@@ -2672,8 +2676,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (IOSToWatchOSMapping) {
if (auto MappedVersion = IOSToWatchOSMapping->map(
- Version, MinimumWatchOSVersion, None)) {
- return MappedVersion.value();
+ Version, MinimumWatchOSVersion, std::nullopt)) {
+ return *MappedVersion;
}
}
@@ -2682,10 +2686,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (NewMajor >= 2) {
if (Version.getMinor()) {
if (Version.getSubminor())
- return VersionTuple(NewMajor, Version.getMinor().value(),
- Version.getSubminor().value());
+ return VersionTuple(NewMajor, *Version.getMinor(),
+ *Version.getSubminor());
else
- return VersionTuple(NewMajor, Version.getMinor().value());
+ return VersionTuple(NewMajor, *Version.getMinor());
}
return VersionTuple(NewMajor);
}
@@ -2727,8 +2731,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return Version;
if (IOSToTvOSMapping) {
- if (auto MappedVersion =
- IOSToTvOSMapping->map(Version, VersionTuple(0, 0), None)) {
+ if (auto MappedVersion = IOSToTvOSMapping->map(
+ Version, VersionTuple(0, 0), std::nullopt)) {
return *MappedVersion;
}
}
@@ -2791,24 +2795,25 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// attributes that are inferred from 'ios'.
NewII = &S.Context.Idents.get("maccatalyst");
auto RemapMacOSVersion =
- [&](const VersionTuple &V) -> Optional<VersionTuple> {
+ [&](const VersionTuple &V) -> std::optional<VersionTuple> {
if (V.empty())
- return None;
+ return std::nullopt;
// API_TO_BE_DEPRECATED is 100000.
if (V.getMajor() == 100000)
return VersionTuple(100000);
// The minimum iosmac version is 13.1
- return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1), None);
+ return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1),
+ std::nullopt);
};
- Optional<VersionTuple> NewIntroduced =
- RemapMacOSVersion(Introduced.Version),
- NewDeprecated =
- RemapMacOSVersion(Deprecated.Version),
- NewObsoleted =
- RemapMacOSVersion(Obsoleted.Version);
+ std::optional<VersionTuple> NewIntroduced =
+ RemapMacOSVersion(Introduced.Version),
+ NewDeprecated =
+ RemapMacOSVersion(Deprecated.Version),
+ NewObsoleted =
+ RemapMacOSVersion(Obsoleted.Version);
if (NewIntroduced || NewDeprecated || NewObsoleted) {
auto VersionOrEmptyVersion =
- [](const Optional<VersionTuple> &V) -> VersionTuple {
+ [](const std::optional<VersionTuple> &V) -> VersionTuple {
return V ? *V : VersionTuple();
};
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
@@ -3032,7 +3037,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel;
if (AL.getNumArgs() > 0) {
Expr *E = AL.getArgAsExpr(0);
- Optional<llvm::APSInt> Idx = llvm::APSInt(32);
+ std::optional<llvm::APSInt> Idx = llvm::APSInt(32);
if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
<< AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange();
@@ -3051,7 +3056,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos;
if (AL.getNumArgs() > 1) {
Expr *E = AL.getArgAsExpr(1);
- Optional<llvm::APSInt> Idx = llvm::APSInt(32);
+ std::optional<llvm::APSInt> Idx = llvm::APSInt(32);
if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
<< AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange();
@@ -3146,7 +3151,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
if (LO.CPlusPlus && !LO.CPlusPlus20)
S.Diag(AL.getLoc(), diag::ext_cxx20_attr) << AL;
- // Since this this is spelled [[nodiscard]], get the optional string
+ // Since 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.
@@ -3391,7 +3396,7 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// handled later in the process, once we know how many exist.
bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
enum FirstParam { Unsupported, Duplicate, Unknown };
- enum SecondParam { None, Architecture, Tune };
+ enum SecondParam { None, CPU, Tune };
enum ThirdParam { Target, TargetClones };
if (AttrStr.contains("fpmath="))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
@@ -3403,24 +3408,22 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "tune=" << Target;
- ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
+ ParsedTargetAttr ParsedAttrs =
+ Context.getTargetInfo().parseTargetAttr(AttrStr);
- if (!ParsedAttrs.Architecture.empty() &&
- !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
+ if (!ParsedAttrs.CPU.empty() &&
+ !Context.getTargetInfo().isValidCPUName(ParsedAttrs.CPU))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Unknown << Architecture << ParsedAttrs.Architecture << Target;
+ << Unknown << CPU << ParsedAttrs.CPU << Target;
if (!ParsedAttrs.Tune.empty() &&
!Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unknown << Tune << ParsedAttrs.Tune << Target;
- if (ParsedAttrs.DuplicateArchitecture)
- return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Duplicate << None << "arch=" << Target;
- if (ParsedAttrs.DuplicateTune)
+ if (ParsedAttrs.Duplicate != "")
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Duplicate << None << "tune=" << Target;
+ << Duplicate << None << ParsedAttrs.Duplicate << Target;
for (const auto &Feature : ParsedAttrs.Features) {
auto CurFeature = StringRef(Feature).drop_front(); // remove + or -.
@@ -3434,8 +3437,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
if (ParsedAttrs.BranchProtection.empty())
return false;
if (!Context.getTargetInfo().validateBranchProtection(
- ParsedAttrs.BranchProtection, ParsedAttrs.Architecture, BPI,
- DiagMsg)) {
+ ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI, DiagMsg)) {
if (DiagMsg.empty())
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "branch-protection" << Target;
@@ -3448,6 +3450,42 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
return false;
}
+// Check Target Version attrs
+bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr,
+ bool &isDefault) {
+ enum FirstParam { Unsupported };
+ enum SecondParam { None };
+ enum ThirdParam { Target, TargetClones, TargetVersion };
+ if (AttrStr.trim() == "default")
+ isDefault = true;
+ llvm::SmallVector<StringRef, 8> Features;
+ AttrStr.split(Features, "+");
+ for (auto &CurFeature : Features) {
+ CurFeature = CurFeature.trim();
+ if (CurFeature == "default")
+ continue;
+ if (!Context.getTargetInfo().validateCpuSupports(CurFeature))
+ return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << CurFeature << TargetVersion;
+ }
+ return false;
+}
+
+static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ StringRef Str;
+ SourceLocation LiteralLoc;
+ bool isDefault = false;
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
+ S.checkTargetVersionAttr(LiteralLoc, Str, isDefault))
+ return;
+ // Do not create default only target_version attribute
+ if (!isDefault) {
+ TargetVersionAttr *NewAttr =
+ ::new (S.Context) TargetVersionAttr(S.Context, AL, Str);
+ D->addAttr(NewAttr);
+ }
+}
+
static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
SourceLocation LiteralLoc;
@@ -3459,12 +3497,12 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(NewAttr);
}
-bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
- const StringLiteral *Literal,
- bool &HasDefault, bool &HasCommas,
- SmallVectorImpl<StringRef> &Strings) {
+bool Sema::checkTargetClonesAttrString(
+ SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal,
+ bool &HasDefault, bool &HasCommas, bool &HasNotDefault,
+ SmallVectorImpl<SmallString<64>> &StringsBuffer) {
enum FirstParam { Unsupported, Duplicate, Unknown };
- enum SecondParam { None, Architecture, Tune };
+ enum SecondParam { None, CPU, Tune };
enum ThirdParam { Target, TargetClones };
HasCommas = HasCommas || Str.contains(',');
// Warn on empty at the beginning of a string.
@@ -3481,29 +3519,75 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
getLangOpts(), Context.getTargetInfo());
bool DefaultIsDupe = false;
+ bool HasCodeGenImpact = false;
if (Cur.empty())
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "" << TargetClones;
- if (Cur.startswith("arch=")) {
- if (!Context.getTargetInfo().isValidCPUName(
- Cur.drop_front(sizeof("arch=") - 1)))
+ if (Context.getTargetInfo().getTriple().isAArch64()) {
+ // AArch64 target clones specific
+ if (Cur == "default") {
+ DefaultIsDupe = HasDefault;
+ HasDefault = true;
+ if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe)
+ Diag(CurLoc, diag::warn_target_clone_duplicate_options);
+ else
+ StringsBuffer.push_back(Cur);
+ } else {
+ std::pair<StringRef, StringRef> CurParts = {{}, Cur};
+ llvm::SmallVector<StringRef, 8> CurFeatures;
+ while (!CurParts.second.empty()) {
+ CurParts = CurParts.second.split('+');
+ StringRef CurFeature = CurParts.first.trim();
+ if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) {
+ Diag(CurLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << None << CurFeature << TargetClones;
+ continue;
+ }
+ std::string Options;
+ if (Context.getTargetInfo().getFeatureDepOptions(CurFeature, Options))
+ HasCodeGenImpact = true;
+ CurFeatures.push_back(CurFeature);
+ }
+ // Canonize TargetClones Attributes
+ llvm::sort(CurFeatures);
+ SmallString<64> Res;
+ for (auto &CurFeat : CurFeatures) {
+ if (!Res.equals(""))
+ Res.append("+");
+ Res.append(CurFeat);
+ }
+ if (llvm::is_contained(StringsBuffer, Res) || DefaultIsDupe)
+ Diag(CurLoc, diag::warn_target_clone_duplicate_options);
+ else if (!HasCodeGenImpact)
+ // Ignore features in target_clone attribute that don't impact
+ // code generation
+ Diag(CurLoc, diag::warn_target_clone_no_impact_options);
+ else if (!Res.empty()) {
+ StringsBuffer.push_back(Res);
+ HasNotDefault = true;
+ }
+ }
+ } else {
+ // Other targets ( currently X86 )
+ if (Cur.startswith("arch=")) {
+ if (!Context.getTargetInfo().isValidCPUName(
+ Cur.drop_front(sizeof("arch=") - 1)))
+ return Diag(CurLoc, diag::warn_unsupported_target_attribute)
+ << Unsupported << CPU << Cur.drop_front(sizeof("arch=") - 1)
+ << TargetClones;
+ } else if (Cur == "default") {
+ DefaultIsDupe = HasDefault;
+ HasDefault = true;
+ } else if (!Context.getTargetInfo().isValidFeatureName(Cur))
return Diag(CurLoc, diag::warn_unsupported_target_attribute)
- << Unsupported << Architecture
- << Cur.drop_front(sizeof("arch=") - 1) << TargetClones;
- } else if (Cur == "default") {
- DefaultIsDupe = HasDefault;
- HasDefault = true;
- } else if (!Context.getTargetInfo().isValidFeatureName(Cur))
- return Diag(CurLoc, diag::warn_unsupported_target_attribute)
- << Unsupported << None << Cur << TargetClones;
-
- if (llvm::is_contained(Strings, Cur) || DefaultIsDupe)
- Diag(CurLoc, diag::warn_target_clone_duplicate_options);
- // Note: Add even if there are duplicates, since it changes name mangling.
- Strings.push_back(Cur);
+ << Unsupported << None << Cur << TargetClones;
+ if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe)
+ Diag(CurLoc, diag::warn_target_clone_duplicate_options);
+ // Note: Add even if there are duplicates, since it changes name mangling.
+ StringsBuffer.push_back(Cur);
+ }
}
-
if (Str.rtrim().endswith(","))
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Unsupported << None << "" << TargetClones;
@@ -3511,6 +3595,10 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
}
static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (S.Context.getTargetInfo().getTriple().isAArch64() &&
+ !S.Context.getTargetInfo().hasFeature("fmv"))
+ return;
+
// Ensure we don't combine these with themselves, since that causes some
// confusing behavior.
if (const auto *Other = D->getAttr<TargetClonesAttr>()) {
@@ -3522,7 +3610,8 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
SmallVector<StringRef, 2> Strings;
- bool HasCommas = false, HasDefault = false;
+ SmallVector<SmallString<64>, 2> StringsBuffer;
+ bool HasCommas = false, HasDefault = false, HasNotDefault = false;
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
StringRef CurStr;
@@ -3531,13 +3620,21 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.checkTargetClonesAttrString(
LiteralLoc, CurStr,
cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()),
- HasDefault, HasCommas, Strings))
+ HasDefault, HasCommas, HasNotDefault, StringsBuffer))
return;
}
+ for (auto &SmallStr : StringsBuffer)
+ Strings.push_back(SmallStr.str());
if (HasCommas && AL.getNumArgs() > 1)
S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values);
+ if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasDefault) {
+ // Add default attribute if there is no one
+ HasDefault = true;
+ Strings.push_back("default");
+ }
+
if (!HasDefault) {
S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default);
return;
@@ -3554,6 +3651,10 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
+ // No multiversion if we have default version only.
+ if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasNotDefault)
+ return;
+
cast<FunctionDecl>(D)->setIsMultiVersion();
TargetClonesAttr *NewAttr = ::new (S.Context)
TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size());
@@ -3730,6 +3831,11 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
return;
}
+
+ if (S.getLangOpts().HLSL) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported);
+ return;
+ }
if (S.getCurFunctionOrMethodDecl()) {
S.Diag(AL.getLoc(), diag::err_init_priority_object_attr);
@@ -3884,27 +3990,38 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3))
return;
- // check if the function is variadic if the 3rd argument non-zero
+ // FirstArg == 0 is is always valid.
if (FirstArg != 0) {
- if (isFunctionOrMethodVariadic(D))
- ++NumArgs; // +1 for ...
- else
- S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL;
- }
-
- // strftime requires FirstArg to be 0 because it doesn't read from any
- // variable the input is just the current time + the format string.
- if (Kind == StrftimeFormat) {
- if (FirstArg != 0) {
+ if (Kind == StrftimeFormat) {
+ // If the kind is strftime, FirstArg must be 0 because strftime does not
+ // use any variadic arguments.
S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter)
- << FirstArgExpr->getSourceRange();
- return;
+ << FirstArgExpr->getSourceRange()
+ << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(), "0");
+ return;
+ } else if (isFunctionOrMethodVariadic(D)) {
+ // Else, if the function is variadic, then FirstArg must be 0 or the
+ // "position" of the ... parameter. It's unusual to use 0 with variadic
+ // functions, so the fixit proposes the latter.
+ if (FirstArg != NumArgs + 1) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << AL << 3 << FirstArgExpr->getSourceRange()
+ << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(),
+ std::to_string(NumArgs + 1));
+ return;
+ }
+ } else {
+ // Inescapable GCC compatibility diagnostic.
+ S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL;
+ if (FirstArg <= Idx) {
+ // Else, the function is not variadic, and FirstArg must be 0 or any
+ // parameter after the format parameter. We don't offer a fixit because
+ // there are too many possible good values.
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << AL << 3 << FirstArgExpr->getSourceRange();
+ return;
+ }
}
- // if 0 it disables parameter checking (to use with e.g. va_list)
- } else if (FirstArg != 0 && FirstArg != NumArgs) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << 3 << FirstArgExpr->getSourceRange();
- return;
}
FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg);
@@ -4335,7 +4452,7 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
}
const auto *VD = dyn_cast<VarDecl>(D);
- if (VD && Context.getTargetInfo().isTLSSupported()) {
+ if (VD) {
unsigned MaxTLSAlign =
Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign())
.getQuantity();
@@ -4500,7 +4617,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
break;
case 7:
if (Str == "pointer")
- DestWidth = S.Context.getTargetInfo().getPointerWidth(0);
+ DestWidth = S.Context.getTargetInfo().getPointerWidth(LangAS::Default);
break;
case 11:
if (Str == "unwind_word")
@@ -5388,7 +5505,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E,
if (E->isValueDependent())
return E;
- Optional<llvm::APSInt> I = llvm::APSInt(64);
+ std::optional<llvm::APSInt> I = llvm::APSInt(64);
if (!(I = E->getIntegerConstantExpr(S.Context))) {
S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type)
<< &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange();
@@ -5543,9 +5660,10 @@ static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
const char *IntrinNames) {
if (AliasName.startswith("__arm_"))
AliasName = AliasName.substr(6);
- const IntrinToName *It = std::lower_bound(
- Map.begin(), Map.end(), BuiltinID,
- [](const IntrinToName &L, unsigned Id) { return L.Id < Id; });
+ const IntrinToName *It =
+ llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
+ return L.Id < Id;
+ });
if (It == Map.end() || It->Id != BuiltinID)
return false;
StringRef FullName(&IntrinNames[It->FullName]);
@@ -6433,9 +6551,9 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc,
}
StringRef CurrentParam;
- llvm::Optional<unsigned> SelfLocation;
+ std::optional<unsigned> SelfLocation;
unsigned NewValueCount = 0;
- llvm::Optional<unsigned> NewValueLocation;
+ std::optional<unsigned> NewValueLocation;
do {
std::tie(CurrentParam, Parameters) = Parameters.split(':');
@@ -6813,12 +6931,12 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
using llvm::Triple;
Triple Target = S.Context.getTargetInfo().getTriple();
+ auto Env = S.Context.getTargetInfo().getTriple().getEnvironment();
if (!llvm::is_contained({Triple::Compute, Triple::Mesh, Triple::Amplification,
Triple::Library},
- Target.getEnvironment())) {
+ Env)) {
uint32_t Pipeline =
- (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() -
- (uint32_t)llvm::Triple::Pixel;
+ static_cast<uint32_t>(hlsl::getStageFromEnvironment(Env));
S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
<< AL << Pipeline << "Compute, Amplification, Mesh or Library";
return;
@@ -6885,8 +7003,35 @@ HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D,
static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
using llvm::Triple;
+ auto Env = S.Context.getTargetInfo().getTriple().getEnvironment();
+ if (Env != Triple::Compute && Env != Triple::Library) {
+ // FIXME: it is OK for a compute shader entry and pixel shader entry live in
+ // same HLSL file. Issue https://github.com/llvm/llvm-project/issues/57880.
+ ShaderStage Pipeline = hlsl::getStageFromEnvironment(Env);
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
+ << AL << (uint32_t)Pipeline << "Compute";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL));
+}
+
+static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) {
+ if (!T->hasUnsignedIntegerRepresentation())
+ return false;
+ if (const auto *VT = T->getAs<VectorType>())
+ return VT->getNumElements() <= 3;
+ return true;
+}
+
+static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ using llvm::Triple;
Triple Target = S.Context.getTargetInfo().getTriple();
- if (Target.getEnvironment() != Triple::Compute) {
+ // FIXME: it is OK for a compute shader entry and pixel shader entry live in
+ // same HLSL file.Issue https://github.com/llvm/llvm-project/issues/57880.
+ if (Target.getEnvironment() != Triple::Compute &&
+ Target.getEnvironment() != Triple::Library) {
uint32_t Pipeline =
(uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() -
(uint32_t)llvm::Triple::Pixel;
@@ -6895,7 +7040,25 @@ static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL));
+ // FIXME: report warning and ignore semantic when cannot apply on the Decl.
+ // See https://github.com/llvm/llvm-project/issues/57916.
+
+ // FIXME: support semantic on field.
+ // See https://github.com/llvm/llvm-project/issues/57889.
+ if (isa<FieldDecl>(D)) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
+ << AL << "parameter";
+ return;
+ }
+
+ auto *VD = cast<ValueDecl>(D);
+ if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
+ S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
+ << AL << "uint/uint2/uint3";
+ return;
+ }
+
+ D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL));
}
static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6905,7 +7068,11 @@ static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
HLSLShaderAttr::ShaderType ShaderType;
- if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) {
+ if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType) ||
+ // Library is added to help convert HLSLShaderAttr::ShaderType to
+ // llvm::Triple::EnviromentType. It is not a legal
+ // HLSLShaderAttr::ShaderType.
+ ShaderType == HLSLShaderAttr::Library) {
S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
<< AL << Str << ArgLoc;
return;
@@ -6931,6 +7098,78 @@ Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL,
return HLSLShaderAttr::Create(Context, ShaderType, AL);
}
+static void handleHLSLResourceBindingAttr(Sema &S, Decl *D,
+ const ParsedAttr &AL) {
+ StringRef Space = "space0";
+ StringRef Slot = "";
+
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierLoc *Loc = AL.getArgAsIdent(0);
+ StringRef Str = Loc->Ident->getName();
+ SourceLocation ArgLoc = Loc->Loc;
+
+ SourceLocation SpaceArgLoc;
+ if (AL.getNumArgs() == 2) {
+ Slot = Str;
+ if (!AL.isArgIdent(1)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierLoc *Loc = AL.getArgAsIdent(1);
+ Space = Loc->Ident->getName();
+ SpaceArgLoc = Loc->Loc;
+ } else {
+ Slot = Str;
+ }
+
+ // Validate.
+ if (!Slot.empty()) {
+ switch (Slot[0]) {
+ case 'u':
+ case 'b':
+ case 's':
+ case 't':
+ break;
+ default:
+ S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
+ << Slot.substr(0, 1);
+ return;
+ }
+
+ StringRef SlotNum = Slot.substr(1);
+ unsigned Num = 0;
+ if (SlotNum.getAsInteger(10, Num)) {
+ S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
+ return;
+ }
+ }
+
+ if (!Space.startswith("space")) {
+ S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+ StringRef SpaceNum = Space.substr(5);
+ unsigned Num = 0;
+ if (SpaceNum.getAsInteger(10, Num)) {
+ S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
+ return;
+ }
+
+ // FIXME: check reg type match decl. Issue
+ // https://github.com/llvm/llvm-project/issues/57886.
+ HLSLResourceBindingAttr *NewAttr =
+ HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL);
+ if (NewAttr)
+ D->addAttr(NewAttr);
+}
+
static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.LangOpts.CPlusPlus) {
S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
@@ -7050,7 +7289,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
- Optional<llvm::APSInt> NumParams = llvm::APSInt(32);
+ std::optional<llvm::APSInt> NumParams = llvm::APSInt(32);
if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(S.Context))) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIntegerConstant
@@ -7252,7 +7491,7 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) {
// Add preserve_access_index attribute to all fields and inner records.
- for (auto D : RD->decls()) {
+ for (auto *D : RD->decls()) {
if (D->hasAttr<BPFPreserveAccessIndexAttr>())
continue;
@@ -7874,8 +8113,8 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
SanitizerName != "coverage")
S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName;
else if (isGlobalVar(D) && !isSanitizerAttributeAllowedOnGlobals(SanitizerName))
- S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
- << AL << ExpectedFunctionOrMethod;
+ S.Diag(D->getLocation(), diag::warn_attribute_type_not_supported_global)
+ << AL << SanitizerName;
Sanitizers.push_back(SanitizerName);
}
@@ -8458,6 +8697,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_X86ForceAlignArgPointer:
handleX86ForceAlignArgPointerAttr(S, D, AL);
break;
+ case ParsedAttr::AT_ReadOnlyPlacement:
+ handleSimpleAttribute<ReadOnlyPlacementAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_DLLExport:
case ParsedAttr::AT_DLLImport:
handleDLLAttr(S, D, AL);
@@ -8634,6 +8876,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_NoEscape:
handleNoEscapeAttr(S, D, AL);
break;
+ case ParsedAttr::AT_MaybeUndef:
+ handleSimpleAttribute<MaybeUndefAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_AssumeAligned:
handleAssumeAlignedAttr(S, D, AL);
break;
@@ -8761,6 +9006,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_Target:
handleTargetAttr(S, D, AL);
break;
+ case ParsedAttr::AT_TargetVersion:
+ handleTargetVersionAttr(S, D, AL);
+ break;
case ParsedAttr::AT_TargetClones:
handleTargetClonesAttr(S, D, AL);
break;
@@ -8904,9 +9152,15 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_HLSLSV_GroupIndex:
handleHLSLSVGroupIndexAttr(S, D, AL);
break;
+ case ParsedAttr::AT_HLSLSV_DispatchThreadID:
+ handleHLSLSV_DispatchThreadIDAttr(S, D, AL);
+ break;
case ParsedAttr::AT_HLSLShader:
handleHLSLShaderAttr(S, D, AL);
break;
+ case ParsedAttr::AT_HLSLResourceBinding:
+ handleHLSLResourceBindingAttr(S, D, AL);
+ break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 221cbd14da97..348092fc62e8 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17,6 +17,8 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -44,6 +46,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include <map>
+#include <optional>
#include <set>
using namespace clang;
@@ -86,7 +89,11 @@ bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) {
/// determine whether this declaration can be used in the default
/// argument expression.
bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
- const NamedDecl *Decl = DRE->getDecl();
+ const ValueDecl *Decl = dyn_cast<ValueDecl>(DRE->getDecl());
+
+ if (!isa<VarDecl, BindingDecl>(Decl))
+ return false;
+
if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) {
// C++ [dcl.fct.default]p9:
// [...] parameters of a function shall not be used in default
@@ -100,7 +107,7 @@ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
return S.Diag(DRE->getBeginLoc(),
diag::err_param_default_argument_references_param)
<< Param->getDeclName() << DefaultArg->getSourceRange();
- } else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) {
+ } else if (auto *VD = Decl->getPotentiallyDecomposedVarDecl()) {
// C++ [dcl.fct.default]p7:
// Local variables shall not be used in default argument
// expressions.
@@ -110,14 +117,14 @@ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
// expression in a default argument.
//
// C++20 [dcl.fct.default]p7 (DR as part of P0588R1, see also CWG 2346):
- // Note: A local variable cannot be odr-used (6.3) in a default argument.
+ // Note: A local variable cannot be odr-used (6.3) in a default
+ // argument.
//
- if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse())
+ if (VD->isLocalVarDecl() && !DRE->isNonOdrUse())
return S.Diag(DRE->getBeginLoc(),
diag::err_param_default_argument_references_local)
- << VDecl->getDeclName() << DefaultArg->getSourceRange();
+ << Decl << DefaultArg->getSourceRange();
}
-
return false;
}
@@ -147,13 +154,20 @@ bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(
}
bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) {
- // C++11 [expr.lambda.prim]p13:
- // A lambda-expression appearing in a default argument shall not
- // implicitly or explicitly capture any entity.
- if (Lambda->capture_begin() == Lambda->capture_end())
- return false;
-
- return S.Diag(Lambda->getBeginLoc(), diag::err_lambda_capture_default_arg);
+ // [expr.prim.lambda.capture]p9
+ // a lambda-expression appearing in a default argument cannot implicitly or
+ // explicitly capture any local entity. Such a lambda-expression can still
+ // have an init-capture if any full-expression in its initializer satisfies
+ // the constraints of an expression appearing in a default argument.
+ bool Invalid = false;
+ for (const LambdaCapture &LC : Lambda->captures()) {
+ if (!Lambda->isInitCapture(&LC))
+ return S.Diag(LC.getLocation(), diag::err_lambda_capture_default_arg);
+ // Init captures are always VarDecl.
+ auto *D = cast<VarDecl>(LC.getCapturedVar());
+ Invalid |= Visit(D->getInit());
+ }
+ return Invalid;
}
} // namespace
@@ -744,11 +758,16 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
// C++17 [dcl.dcl]/8:
// The decl-specifier-seq shall contain only the type-specifier auto
// and cv-qualifiers.
- // C++2a [dcl.dcl]/8:
+ // C++20 [dcl.dcl]/8:
// If decl-specifier-seq contains any decl-specifier other than static,
// thread_local, auto, or cv-qualifiers, the program is ill-formed.
+ // C++2b [dcl.pre]/6:
+ // Each decl-specifier in the decl-specifier-seq shall be static,
+ // thread_local, auto (9.2.9.6 [dcl.spec.auto]), or a cv-qualifier.
auto &DS = D.getDeclSpec();
{
+ // Note: While constrained-auto needs to be checked, we do so separately so
+ // we can emit a better diagnostic.
SmallVector<StringRef, 8> BadSpecifiers;
SmallVector<SourceLocation, 8> BadSpecifierLocs;
SmallVector<StringRef, 8> CPlusPlus20Specifiers;
@@ -775,6 +794,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
BadSpecifiers.push_back("inline");
BadSpecifierLocs.push_back(DS.getInlineSpecLoc());
}
+
if (!BadSpecifiers.empty()) {
auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);
Err << (int)BadSpecifiers.size()
@@ -835,6 +855,20 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
D.setInvalidType();
}
+ // Constrained auto is prohibited by [decl.pre]p6, so check that here.
+ if (DS.isConstrainedAuto()) {
+ TemplateIdAnnotation *TemplRep = DS.getRepAsTemplateId();
+ assert(TemplRep->Kind == TNK_Concept_template &&
+ "No other template kind should be possible for a constrained auto");
+
+ SourceRange TemplRange{TemplRep->TemplateNameLoc,
+ TemplRep->RAngleLoc.isValid()
+ ? TemplRep->RAngleLoc
+ : TemplRep->TemplateNameLoc};
+ Diag(TemplRep->TemplateNameLoc, diag::err_decomp_decl_constraint)
+ << TemplRange << FixItHint::CreateRemoval(TemplRange);
+ }
+
// Build the BindingDecls.
SmallVector<BindingDecl*, 8> Bindings;
@@ -1229,7 +1263,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
if (E.isInvalid())
return true;
- E = S.BuildCallExpr(nullptr, E.get(), Loc, None, Loc);
+ E = S.BuildCallExpr(nullptr, E.get(), Loc, std::nullopt, Loc);
} else {
// Otherwise, the initializer is get<i-1>(e), where get is looked up
// in the associated namespaces.
@@ -3084,7 +3118,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) {
return;
if (MD && !MD->isVirtual()) {
- // If we have a non-virtual method, check if if hides a virtual method.
+ // If we have a non-virtual method, check if it hides a virtual method.
// (In that case, it's most likely the method has the wrong type.)
SmallVector<CXXMethodDecl *, 8> OverloadedMethods;
FindHiddenVirtualMethods(MD, OverloadedMethods);
@@ -3776,7 +3810,7 @@ namespace {
void CheckInitListExpr(InitListExpr *ILE) {
InitFieldIndex.push_back(0);
- for (auto Child : ILE->children()) {
+ for (auto *Child : ILE->children()) {
if (InitListExpr *SubList = dyn_cast<InitListExpr>(Child)) {
CheckInitListExpr(SubList);
} else {
@@ -3847,7 +3881,7 @@ namespace {
Expr *Callee = E->getCallee();
if (isa<MemberExpr>(Callee)) {
HandleValue(Callee, false /*AddressOf*/);
- for (auto Arg : E->arguments())
+ for (auto *Arg : E->arguments())
Visit(Arg);
return;
}
@@ -3872,7 +3906,7 @@ namespace {
return Inherited::VisitCXXOperatorCallExpr(E);
Visit(Callee);
- for (auto Arg : E->arguments())
+ for (auto *Arg : E->arguments())
HandleValue(Arg->IgnoreParenImpCasts(), false /*AddressOf*/);
}
@@ -4023,6 +4057,21 @@ ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) {
return ConstraintExpr;
}
+ExprResult Sema::ConvertMemberDefaultInitExpression(FieldDecl *FD,
+ Expr *InitExpr,
+ SourceLocation InitLoc) {
+ InitializedEntity Entity =
+ InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD);
+ InitializationKind Kind =
+ FD->getInClassInitStyle() == ICIS_ListInit
+ ? InitializationKind::CreateDirectList(InitExpr->getBeginLoc(),
+ InitExpr->getBeginLoc(),
+ InitExpr->getEndLoc())
+ : InitializationKind::CreateCopy(InitExpr->getBeginLoc(), InitLoc);
+ InitializationSequence Seq(*this, Entity, Kind, InitExpr);
+ return Seq.Perform(*this, Entity, Kind, InitExpr);
+}
+
/// This is invoked after parsing an in-class initializer for a
/// non-static C++ class member, and after instantiating an in-class initializer
/// in a class template. Such actions are deferred until the class is complete.
@@ -4049,36 +4098,23 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
return;
}
- ExprResult Init = InitExpr;
- if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
- InitializedEntity Entity =
- InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD);
- InitializationKind Kind =
- FD->getInClassInitStyle() == ICIS_ListInit
- ? InitializationKind::CreateDirectList(InitExpr->getBeginLoc(),
- InitExpr->getBeginLoc(),
- InitExpr->getEndLoc())
- : InitializationKind::CreateCopy(InitExpr->getBeginLoc(), InitLoc);
- InitializationSequence Seq(*this, Entity, Kind, InitExpr);
- Init = Seq.Perform(*this, Entity, Kind, InitExpr);
+ ExprResult Init = CorrectDelayedTyposInExpr(InitExpr, /*InitDecl=*/nullptr,
+ /*RecoverUncorrectedTypos=*/true);
+ assert(Init.isUsable() && "Init should at least have a RecoveryExpr");
+ if (!FD->getType()->isDependentType() && !Init.get()->isTypeDependent()) {
+ Init = ConvertMemberDefaultInitExpression(FD, Init.get(), InitLoc);
+ // C++11 [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ if (!Init.isInvalid())
+ Init = ActOnFinishFullExpr(Init.get(), /*DiscarededValue=*/false);
if (Init.isInvalid()) {
FD->setInvalidDecl();
return;
}
}
- // C++11 [class.base.init]p7:
- // The initialization of each base and member constitutes a
- // full-expression.
- Init = ActOnFinishFullExpr(Init.get(), InitLoc, /*DiscardedValue*/ false);
- if (Init.isInvalid()) {
- FD->setInvalidDecl();
- return;
- }
-
- InitExpr = Init.get();
-
- FD->setInClassInitializer(InitExpr);
+ FD->setInClassInitializer(Init.get());
}
/// Find the direct and/or virtual base specifiers that
@@ -4308,11 +4344,21 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
}
if (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20) {
- auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>();
- if (UnqualifiedBase) {
- Diag(IdLoc, diag::ext_unqualified_base_class)
- << SourceRange(IdLoc, Init->getSourceRange().getEnd());
- BaseType = UnqualifiedBase->getInjectedClassNameSpecialization();
+ if (auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>()) {
+ auto *TempSpec = cast<TemplateSpecializationType>(
+ UnqualifiedBase->getInjectedClassNameSpecialization());
+ TemplateName TN = TempSpec->getTemplateName();
+ for (auto const &Base : ClassDecl->bases()) {
+ auto BaseTemplate =
+ Base.getType()->getAs<TemplateSpecializationType>();
+ if (BaseTemplate && Context.hasSameTemplateName(
+ BaseTemplate->getTemplateName(), TN)) {
+ Diag(IdLoc, diag::ext_unqualified_base_class)
+ << SourceRange(IdLoc, Init->getSourceRange().getEnd());
+ BaseType = Base.getType();
+ break;
+ }
+ }
}
}
@@ -4362,17 +4408,13 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
}
if (BaseType.isNull()) {
- BaseType = Context.getTypeDeclType(TyD);
+ BaseType = getElaboratedType(ETK_None, SS, Context.getTypeDeclType(TyD));
MarkAnyDeclReferenced(TyD->getLocation(), TyD, /*OdrUse=*/false);
- if (SS.isSet()) {
- BaseType = Context.getElaboratedType(ETK_None, SS.getScopeRep(),
- BaseType);
- TInfo = Context.CreateTypeSourceInfo(BaseType);
- ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>();
- TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
- TL.setElaboratedKeywordLoc(SourceLocation());
- TL.setQualifierLoc(SS.getWithLocInContext(Context));
- }
+ TInfo = Context.CreateTypeSourceInfo(BaseType);
+ ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>();
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
+ TL.setElaboratedKeywordLoc(SourceLocation());
+ TL.setQualifierLoc(SS.getWithLocInContext(Context));
}
}
@@ -4468,10 +4510,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
MemInitResult
Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
CXXRecordDecl *ClassDecl) {
- SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ SourceLocation NameLoc = TInfo->getTypeLoc().getSourceRange().getBegin();
if (!LangOpts.CPlusPlus11)
return Diag(NameLoc, diag::err_delegating_ctor)
- << TInfo->getTypeLoc().getLocalSourceRange();
+ << TInfo->getTypeLoc().getSourceRange();
Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor);
bool InitList = true;
@@ -4532,12 +4574,11 @@ MemInitResult
Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
Expr *Init, CXXRecordDecl *ClassDecl,
SourceLocation EllipsisLoc) {
- SourceLocation BaseLoc
- = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getBeginLoc();
if (!BaseType->isDependentType() && !BaseType->isRecordType())
return Diag(BaseLoc, diag::err_base_init_does_not_name_class)
- << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange();
+ << BaseType << BaseTInfo->getTypeLoc().getSourceRange();
// C++ [class.base.init]p2:
// [...] Unless the mem-initializer-id names a nonstatic data
@@ -4595,8 +4636,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
Dependent = true;
else
return Diag(BaseLoc, diag::err_not_direct_base_or_virtual)
- << BaseType << Context.getTypeDeclType(ClassDecl)
- << BaseTInfo->getTypeLoc().getLocalSourceRange();
+ << BaseType << Context.getTypeDeclType(ClassDecl)
+ << BaseTInfo->getTypeLoc().getSourceRange();
}
}
@@ -4670,10 +4711,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
}
// Create a static_cast\<T&&>(expr).
-static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) {
- if (T.isNull()) T = E->getType();
- QualType TargetType = SemaRef.BuildReferenceType(
- T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName());
+static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
+ QualType TargetType =
+ SemaRef.BuildReferenceType(E->getType(), /*SpelledAsLValue*/ false,
+ SourceLocation(), DeclarationName());
SourceLocation ExprLoc = E->getBeginLoc();
TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo(
TargetType, ExprLoc);
@@ -4709,8 +4750,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
case IIK_Default: {
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None);
- BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, None);
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt);
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt);
break;
}
@@ -4874,9 +4915,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
InitializationKind InitKind =
InitializationKind::CreateDefault(Loc);
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None);
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt);
ExprResult MemberInit =
- InitSeq.Perform(SemaRef, InitEntity, InitKind, None);
+ InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt);
MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit);
if (MemberInit.isInvalid())
@@ -5644,7 +5685,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
continue;
CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
- assert(Dtor && "No dtor found for FieldClassDecl!");
+ // Dtor might still be missing, e.g because it's invalid.
+ if (!Dtor)
+ continue;
CheckDestructorAccess(Field->getLocation(), Dtor,
PDiag(diag::err_access_dtor_field)
<< Field->getDeclName()
@@ -5690,7 +5733,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
- assert(Dtor && "No dtor found for BaseClassDecl!");
+ // Dtor might still be missing, e.g because it's invalid.
+ if (!Dtor)
+ continue;
// FIXME: caret should be on the start of the class name
CheckDestructorAccess(Base.getBeginLoc(), Dtor,
@@ -5727,7 +5772,9 @@ void Sema::MarkVirtualBaseDestructorsReferenced(
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
- assert(Dtor && "No dtor found for BaseClassDecl!");
+ // Dtor might still be missing, e.g because it's invalid.
+ if (!Dtor)
+ continue;
if (CheckDestructorAccess(
ClassDecl->getLocation(), Dtor,
PDiag(diag::err_access_dtor_vbase)
@@ -6612,7 +6659,7 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false;
bool DtorIsTrivialForCall = false;
- // If a class has at least one non-deleted, trivial copy constructor, it
+ // If a class has at least one eligible, trivial copy constructor, it
// is passed according to the C ABI. Otherwise, it is passed indirectly.
//
// Note: This permits classes with non-trivial copy or move ctors to be
@@ -6627,7 +6674,8 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
}
} else {
for (const CXXConstructorDecl *CD : D->ctors()) {
- if (CD->isCopyConstructor() && !CD->isDeleted()) {
+ if (CD->isCopyConstructor() && !CD->isDeleted() &&
+ !CD->isIneligibleOrNotSelected()) {
if (CD->isTrivial())
CopyCtorIsTrivial = true;
if (CD->isTrivialForCall())
@@ -6947,7 +6995,8 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
// 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())
+ if (CSM != CXXInvalid && !M->isDeleted() && M->isDefaulted() &&
+ M->isConstexpr() && M->size_overridden_methods())
DefineDefaultedFunction(*this, M, M->getLocation());
if (!Incomplete)
@@ -7178,6 +7227,11 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
bool ConstRHS,
CXXConstructorDecl *InheritedCtor = nullptr,
Sema::InheritedConstructorInfo *Inherited = nullptr) {
+ // Suppress duplicate constraint checking here, in case a constraint check
+ // caused us to decide to do this. Any truely recursive checks will get
+ // caught during these checks anyway.
+ Sema::SatisfactionStackResetRAII SSRAII{S};
+
// If we're inheriting a constructor, see if we need to call it for this base
// class.
if (InheritedCtor) {
@@ -7274,8 +7328,8 @@ static bool defaultedSpecialMemberIsConstexpr(
// class is a constexpr function, and
for (const auto &B : ClassDecl->bases()) {
const RecordType *BaseType = B.getType()->getAs<RecordType>();
- if (!BaseType) continue;
-
+ if (!BaseType)
+ continue;
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg,
InheritedCtor, Inherited))
@@ -7402,13 +7456,15 @@ void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) {
if (DefKind.isSpecialMember()
? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD),
- DefKind.asSpecialMember())
+ DefKind.asSpecialMember(),
+ FD->getDefaultLoc())
: CheckExplicitlyDefaultedComparison(S, FD, DefKind.asComparison()))
FD->setInvalidDecl();
}
bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
- CXXSpecialMember CSM) {
+ CXXSpecialMember CSM,
+ SourceLocation DefaultLoc) {
CXXRecordDecl *RD = MD->getParent();
assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid &&
@@ -7470,6 +7526,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
ReturnType = Type->getReturnType();
QualType DeclType = Context.getTypeDeclType(RD);
+ DeclType = Context.getElaboratedType(ETK_None, nullptr, DeclType, nullptr);
DeclType = Context.getAddrSpaceQualType(DeclType, MD->getMethodQualifiers().getAddressSpace());
QualType ExpectedReturnType = Context.getLValueReferenceType(DeclType);
@@ -7544,6 +7601,17 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
// FIXME: This should not apply if the member is deleted.
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
HasConstParam);
+
+ // C++14 [dcl.constexpr]p6 (CWG DR647/CWG DR1358):
+ // If the instantiated template specialization of a constexpr function
+ // template or member function of a class template would fail to satisfy
+ // the requirements for a constexpr function or constexpr constructor, that
+ // specialization is still a constexpr function or constexpr constructor,
+ // even though a call to such a function cannot appear in a constant
+ // expression.
+ if (MD->isTemplateInstantiation() && MD->isConstexpr())
+ Constexpr = true;
+
if ((getLangOpts().CPlusPlus20 ||
(getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
: isa<CXXConstructorDecl>(MD))) &&
@@ -7575,10 +7643,8 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
EPI.ExceptionSpec.Type = EST_Unevaluated;
EPI.ExceptionSpec.SourceDecl = MD;
- MD->setType(Context.getFunctionType(ReturnType,
- llvm::makeArrayRef(&ArgType,
- ExpectedParams),
- EPI));
+ MD->setType(Context.getFunctionType(
+ ReturnType, llvm::ArrayRef(&ArgType, ExpectedParams), EPI));
}
}
@@ -7589,8 +7655,11 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
Diag(MD->getLocation(), diag::warn_defaulted_method_deleted) << CSM;
if (ShouldDeleteForTypeMismatch) {
Diag(MD->getLocation(), diag::note_deleted_type_mismatch) << CSM;
- } else {
- ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true);
+ } else if (ShouldDeleteSpecialMember(MD, CSM, nullptr,
+ /*Diagnose*/ true) &&
+ DefaultLoc.isValid()) {
+ Diag(DefaultLoc, diag::note_replace_equals_default_to_delete)
+ << FixItHint::CreateReplacement(DefaultLoc, "delete");
}
}
if (ShouldDeleteForTypeMismatch && !HadError) {
@@ -7848,7 +7917,8 @@ private:
OverloadCandidateSet CandidateSet(
FD->getLocation(), OverloadCandidateSet::CSK_Operator,
OverloadCandidateSet::OperatorRewriteInfo(
- OO, /*AllowRewrittenCandidates=*/!SpaceshipCandidates));
+ OO, FD->getLocation(),
+ /*AllowRewrittenCandidates=*/!SpaceshipCandidates));
/// C++2a [class.compare.default]p1 [P2002R0]:
/// [...] the defaulted function itself is never a candidate for overload
@@ -7987,7 +8057,7 @@ private:
"invalid builtin comparison");
if (NeedsDeducing) {
- Optional<ComparisonCategoryType> Cat =
+ std::optional<ComparisonCategoryType> Cat =
getComparisonCategoryForBuiltinCmp(T);
assert(Cat && "no category for builtin comparison?");
R.Category = *Cat;
@@ -8642,10 +8712,11 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
// C++2a [class.spaceship]p2 [P2002R0]:
// Let R be the declared return type [...]. If R is auto, [...]. Otherwise,
// R shall not contain a placeholder type.
- if (DCK == DefaultedComparisonKind::ThreeWay &&
- FD->getDeclaredReturnType()->getContainedDeducedType() &&
- !Context.hasSameType(FD->getDeclaredReturnType(),
- Context.getAutoDeductType())) {
+ if (QualType RT = FD->getDeclaredReturnType();
+ DCK == DefaultedComparisonKind::ThreeWay &&
+ RT->getContainedDeducedType() &&
+ (!Context.hasSameType(RT, Context.getAutoDeductType()) ||
+ RT->getContainedAutoType()->isConstrained())) {
Diag(FD->getLocation(),
diag::err_defaulted_comparison_deduced_return_type_not_auto)
<< (int)DCK << FD->getDeclaredReturnType() << Context.AutoDeductTy
@@ -8664,10 +8735,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
bool First = FD == FD->getCanonicalDecl();
- // If we want to delete the function, then do so; there's nothing else to
- // check in that case.
- if (Info.Deleted) {
- if (!First) {
+ if (!First) {
+ if (Info.Deleted) {
// C++11 [dcl.fct.def.default]p4:
// [For a] user-provided explicitly-defaulted function [...] if such a
// function is implicitly defined as deleted, the program is ill-formed.
@@ -8681,7 +8750,21 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
.visit();
return true;
}
+ if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) {
+ // C++20 [class.compare.default]p1:
+ // [...] A definition of a comparison operator as defaulted that appears
+ // in a class shall be the first declaration of that function.
+ Diag(FD->getLocation(), diag::err_non_first_default_compare_in_class)
+ << (int)DCK;
+ Diag(FD->getCanonicalDecl()->getLocation(),
+ diag::note_previous_declaration);
+ return true;
+ }
+ }
+ // If we want to delete the function, then do so; there's nothing else to
+ // check in that case.
+ if (Info.Deleted) {
SetDeclDeleted(FD, FD->getLocation());
if (!inTemplateInstantiation() && !FD->isImplicit()) {
Diag(FD->getLocation(), diag::warn_defaulted_comparison_deleted)
@@ -8689,6 +8772,9 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD,
DefaultedComparisonAnalyzer(*this, RD, FD, DCK,
DefaultedComparisonAnalyzer::ExplainDeleted)
.visit();
+ if (FD->getDefaultLoc().isValid())
+ Diag(FD->getDefaultLoc(), diag::note_replace_equals_default_to_delete)
+ << FixItHint::CreateReplacement(FD->getDefaultLoc(), "delete");
}
return false;
}
@@ -10130,10 +10216,12 @@ void Sema::ActOnFinishCXXMemberSpecification(
Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) << AL;
}
- ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef(
- // strict aliasing violation!
- reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
- FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);
+ ActOnFields(S, RLoc, TagDecl,
+ llvm::ArrayRef(
+ // strict aliasing violation!
+ reinterpret_cast<Decl **>(FieldCollector->getCurFields()),
+ FieldCollector->getCurNumFields()),
+ LBrac, RBrac, AttrList);
CheckCompletedCXXClass(S, cast<CXXRecordDecl>(TagDecl));
}
@@ -10699,7 +10787,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
EPI.Variadic = false;
EPI.TypeQuals = Qualifiers();
EPI.RefQualifier = RQ_None;
- return Context.getFunctionType(Context.VoidTy, None, EPI);
+ return Context.getFunctionType(Context.VoidTy, std::nullopt, EPI);
}
static void extendLeft(SourceRange &R, SourceRange Before) {
@@ -10802,7 +10890,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
PastFunctionChunk = true;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorChunk::Array:
NeedsTypedef = true;
extendRight(After, Chunk.getSourceRange());
@@ -10875,7 +10963,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// of the errors above fired) and with the conversion type as the
// return type.
if (D.isInvalidType())
- R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());
+ R = Context.getFunctionType(ConvType, std::nullopt,
+ Proto->getExtProtoInfo());
// C++0x explicit conversion operators.
if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus20)
@@ -11037,6 +11126,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
// Check that the return type is written as a specialization of
// the template specified as the deduction-guide's name.
+ // The template name may not be qualified. [temp.deduct.guide]
ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType();
TypeSourceInfo *TSI = nullptr;
QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI);
@@ -11044,13 +11134,17 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
bool AcceptableReturnType = false;
bool MightInstantiateToSpecialization = false;
if (auto RetTST =
- TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) {
+ TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) {
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
bool TemplateMatches =
Context.hasSameTemplateName(SpecifiedName, GuidedTemplate);
- // FIXME: We should consider other template kinds (using, qualified),
- // otherwise we will emit bogus diagnostics.
- if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches)
+ auto TKind = SpecifiedName.getKind();
+ // A Using TemplateName can't actually be valid (either it's qualified, or
+ // we're in the wrong scope). But we have diagnosed these problems
+ // already.
+ bool SimplyWritten = TKind == TemplateName::Template ||
+ TKind == TemplateName::UsingTemplate;
+ if (SimplyWritten && TemplateMatches)
AcceptableReturnType = true;
else {
// This could still instantiate to the right type, unless we know it
@@ -11111,10 +11205,13 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc,
/// ActOnStartNamespaceDef - This is called at the start of a namespace
/// definition.
-Decl *Sema::ActOnStartNamespaceDef(
- Scope *NamespcScope, SourceLocation InlineLoc, SourceLocation NamespaceLoc,
- SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation LBrace,
- const ParsedAttributesView &AttrList, UsingDirectiveDecl *&UD) {
+Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
+ SourceLocation InlineLoc,
+ SourceLocation NamespaceLoc,
+ SourceLocation IdentLoc, IdentifierInfo *II,
+ SourceLocation LBrace,
+ const ParsedAttributesView &AttrList,
+ UsingDirectiveDecl *&UD, bool IsNested) {
SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc;
// For anonymous namespace, take the location of the left brace.
SourceLocation Loc = II ? IdentLoc : LBrace;
@@ -11184,8 +11281,8 @@ Decl *Sema::ActOnStartNamespaceDef(
&IsInline, PrevNS);
}
- NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline,
- StartLoc, Loc, II, PrevNS);
+ NamespaceDecl *Namespc = NamespaceDecl::Create(
+ Context, CurContext, IsInline, StartLoc, Loc, II, PrevNS, IsNested);
if (IsInvalid)
Namespc->setInvalidDecl();
@@ -11446,12 +11543,11 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind,
NamespaceDecl *Sema::getOrCreateStdNamespace() {
if (!StdNamespace) {
// The "std" namespace has not yet been defined, so build one implicitly.
- StdNamespace = NamespaceDecl::Create(Context,
- Context.getTranslationUnitDecl(),
- /*Inline=*/false,
- SourceLocation(), SourceLocation(),
- &PP.getIdentifierTable().get("std"),
- /*PrevDecl=*/nullptr);
+ StdNamespace = NamespaceDecl::Create(
+ Context, Context.getTranslationUnitDecl(),
+ /*Inline=*/false, SourceLocation(), SourceLocation(),
+ &PP.getIdentifierTable().get("std"),
+ /*PrevDecl=*/nullptr, /*Nested=*/false);
getStdNamespace()->setImplicit(true);
}
@@ -11484,7 +11580,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
Ty->getAs<TemplateSpecializationType>()) {
Template = dyn_cast_or_null<ClassTemplateDecl>(
TST->getTemplateName().getAsTemplateDecl());
- Arguments = TST->getArgs();
+ Arguments = TST->template_arguments().begin();
}
if (!Template)
return false;
@@ -11563,7 +11659,9 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) {
Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element),
Context.getTrivialTypeSourceInfo(Element,
Loc)));
- return Context.getCanonicalType(
+ return Context.getElaboratedType(
+ ElaboratedTypeKeyword::ETK_None,
+ NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()),
CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args));
}
@@ -11825,30 +11923,40 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS,
Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
SourceLocation EnumLoc,
- const DeclSpec &DS) {
- switch (DS.getTypeSpecType()) {
- case DeclSpec::TST_error:
- // This will already have been diagnosed
+ SourceLocation IdentLoc,
+ IdentifierInfo &II, CXXScopeSpec *SS) {
+ assert(!SS->isInvalid() && "ScopeSpec is invalid");
+ TypeSourceInfo *TSI = nullptr;
+ QualType EnumTy = GetTypeFromParser(
+ getTypeName(II, IdentLoc, S, SS, /*isClassName=*/false,
+ /*HasTrailingDot=*/false,
+ /*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
+ /*WantNontrivialTypeSourceInfo=*/true),
+ &TSI);
+ if (EnumTy.isNull()) {
+ Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS)
+ ? diag::err_using_enum_is_dependent
+ : diag::err_unknown_typename)
+ << II.getName()
+ << SourceRange(SS ? SS->getBeginLoc() : IdentLoc, IdentLoc);
return nullptr;
+ }
- case DeclSpec::TST_enum:
- break;
-
- case DeclSpec::TST_typename:
- Diag(DS.getTypeSpecTypeLoc(), diag::err_using_enum_is_dependent);
+ auto *Enum = dyn_cast_if_present<EnumDecl>(EnumTy->getAsTagDecl());
+ if (!Enum) {
+ Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy;
return nullptr;
-
- default:
- llvm_unreachable("unexpected DeclSpec type");
}
- // As with enum-decls, we ignore attributes for now.
- auto *Enum = cast<EnumDecl>(DS.getRepAsDecl());
if (auto *Def = Enum->getDefinition())
Enum = Def;
- auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc,
- DS.getTypeSpecTypeNameLoc(), Enum);
+ if (TSI == nullptr)
+ TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc);
+
+ auto *UD =
+ BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, TSI, Enum);
+
if (UD)
PushOnScopeChains(UD, S, /*AddToContext*/ false);
@@ -12540,6 +12648,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
SourceLocation EnumLoc,
SourceLocation NameLoc,
+ TypeSourceInfo *EnumType,
EnumDecl *ED) {
bool Invalid = false;
@@ -12566,7 +12675,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
Invalid = true;
UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc,
- EnumLoc, NameLoc, ED);
+ EnumLoc, NameLoc, EnumType);
UD->setAccess(AS);
CurContext->addDecl(UD);
@@ -12908,7 +13017,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename,
// Salient point: SS doesn't have to name a base class as long as
// lookup only finds members from base classes. Therefore we can
- // diagnose here only if we can prove that that can't happen,
+ // diagnose here only if we can prove that can't happen,
// i.e. if the class hierarchies provably don't intersect.
// TODO: it would be nice if "definitely valid" results were cached
@@ -12988,7 +13097,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
Previous.clear();
}
- assert(Name.Kind == UnqualifiedIdKind::IK_Identifier &&
+ assert(Name.getKind() == UnqualifiedIdKind::IK_Identifier &&
"name in alias declaration must be an identifier");
TypeAliasDecl *NewTD = TypeAliasDecl::Create(Context, CurContext, UsingLoc,
Name.StartLocation,
@@ -13443,7 +13552,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
- setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, None);
+ setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, std::nullopt);
if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDefaultConstructor,
@@ -13723,7 +13832,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
- setupImplicitSpecialMemberType(Destructor, Context.VoidTy, None);
+ setupImplicitSpecialMemberType(Destructor, Context.VoidTy, std::nullopt);
if (getLangOpts().CUDA)
inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDestructor,
@@ -13884,7 +13993,8 @@ void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) {
FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
EPI.ExceptionSpec.Type = EST_Unevaluated;
EPI.ExceptionSpec.SourceDecl = Destructor;
- Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
+ Destructor->setType(
+ Context.getFunctionType(Context.VoidTy, std::nullopt, EPI));
// FIXME: If the destructor has a body that could throw, and the newly created
// spec doesn't allow exceptions, we should emit a warning, because this
@@ -14332,6 +14442,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
return nullptr;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ArgType, AS);
@@ -14410,13 +14521,10 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
CXXRecordDecl *RD = CopyOp->getParent();
CXXMethodDecl *UserDeclaredOperation = nullptr;
- // In Microsoft mode, assignment operations don't affect constructors and
- // vice versa.
if (RD->hasUserDeclaredDestructor()) {
UserDeclaredOperation = RD->getDestructor();
} else if (!isa<CXXConstructorDecl>(CopyOp) &&
- RD->hasUserDeclaredCopyConstructor() &&
- !S.getLangOpts().MSVCCompat) {
+ RD->hasUserDeclaredCopyConstructor()) {
// Find any user-declared copy constructor.
for (auto *I : RD->ctors()) {
if (I->isCopyConstructor()) {
@@ -14426,8 +14534,7 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) {
}
assert(UserDeclaredOperation);
} else if (isa<CXXConstructorDecl>(CopyOp) &&
- RD->hasUserDeclaredCopyAssignment() &&
- !S.getLangOpts().MSVCCompat) {
+ RD->hasUserDeclaredCopyAssignment()) {
// Find any user-declared move assignment operator.
for (auto *I : RD->methods()) {
if (I->isCopyAssignmentOperator()) {
@@ -14612,7 +14719,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
MemberBuilder From(OtherRef, OtherRefType, /*IsArrow=*/false, MemberLookup);
- MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/true, MemberLookup);
+ MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/!LangOpts.HLSL,
+ MemberLookup);
// Build the copy of this field.
StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType,
@@ -14630,9 +14738,16 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
if (!Invalid) {
// Add a "return *this;"
- ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
+ Expr *ThisExpr = nullptr;
+ if (!LangOpts.HLSL) {
+ ExprResult ThisObj =
+ CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc));
+ ThisExpr = ThisObj.get();
+ } else {
+ ThisExpr = This.build(*this, Loc);
+ }
- StmtResult Return = BuildReturnStmt(Loc, ThisObj.get());
+ StmtResult Return = BuildReturnStmt(Loc, ThisExpr);
if (Return.isInvalid())
Invalid = true;
else
@@ -14670,6 +14785,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// constructor rules.
QualType ArgType = Context.getTypeDeclType(ClassDecl);
+ ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ArgType, AS);
@@ -15042,6 +15158,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
+ ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
bool Const = ClassDecl->implicitCopyConstructorHasConstParam();
if (Const)
ArgType = ArgType.withConst();
@@ -15165,7 +15282,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
: CopyConstructor->getLocation();
Sema::CompoundScopeRAII CompoundScope(*this);
CopyConstructor->setBody(
- ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>());
+ ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false)
+ .getAs<Stmt>());
CopyConstructor->markUsed(Context);
}
@@ -15185,6 +15303,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
+ ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr);
LangAS AS = getDefaultCXXMethodAddrSpace();
if (AS != LangAS::Default)
ArgType = Context.getAddrSpaceQualType(ClassType, AS);
@@ -15290,8 +15409,9 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
? MoveConstructor->getEndLoc()
: MoveConstructor->getLocation();
Sema::CompoundScopeRAII CompoundScope(*this);
- MoveConstructor->setBody(ActOnCompoundStmt(
- Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>());
+ MoveConstructor->setBody(
+ ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false)
+ .getAs<Stmt>());
MoveConstructor->markUsed(Context);
}
@@ -15316,7 +15436,8 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
CXXRecordDecl *Lambda = Conv->getParent();
FunctionDecl *CallOp = Lambda->getLambdaCallOperator();
- FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(CC);
+ FunctionDecl *Invoker =
+ CallOp->isStatic() ? CallOp : Lambda->getLambdaStaticInvoker(CC);
if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) {
CallOp = InstantiateFunctionDeclaration(
@@ -15324,10 +15445,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
if (!CallOp)
return;
- Invoker = InstantiateFunctionDeclaration(
- Invoker->getDescribedFunctionTemplate(), TemplateArgs, CurrentLocation);
- if (!Invoker)
- return;
+ if (CallOp != Invoker) {
+ Invoker = InstantiateFunctionDeclaration(
+ Invoker->getDescribedFunctionTemplate(), TemplateArgs,
+ CurrentLocation);
+ if (!Invoker)
+ return;
+ }
}
if (CallOp->isInvalidDecl())
@@ -15340,17 +15464,19 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// to the PendingInstantiations.
MarkFunctionReferenced(CurrentLocation, CallOp);
- // Fill in the __invoke function with a dummy implementation. IR generation
- // will fill in the actual details. Update its type in case it contained
- // an 'auto'.
- Invoker->markUsed(Context);
- Invoker->setReferenced();
- Invoker->setType(Conv->getReturnType()->getPointeeType());
- Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+ if (Invoker != CallOp) {
+ // Fill in the __invoke function with a dummy implementation. IR generation
+ // will fill in the actual details. Update its type in case it contained
+ // an 'auto'.
+ Invoker->markUsed(Context);
+ Invoker->setReferenced();
+ Invoker->setType(Conv->getReturnType()->getPointeeType());
+ Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation()));
+ }
// Construct the body of the conversion function { return __invoke; }.
- Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(),
- VK_LValue, Conv->getLocation());
+ Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(), VK_LValue,
+ Conv->getLocation());
assert(FunctionRef && "Can't refer to __invoke function?");
Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get();
Conv->setBody(CompoundStmt::Create(Context, Return, FPOptionsOverride(),
@@ -15360,16 +15486,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
- L->CompletedImplicitDefinition(Invoker);
+ if (Invoker != CallOp)
+ L->CompletedImplicitDefinition(Invoker);
}
}
-
-
void Sema::DefineImplicitLambdaToBlockPointerConversion(
- SourceLocation CurrentLocation,
- CXXConversionDecl *Conv)
-{
+ SourceLocation CurrentLocation, CXXConversionDecl *Conv) {
assert(!Conv->getParent()->isGenericLambda());
SynthesizedFunctionScope Scope(*this, Conv);
@@ -15429,7 +15552,7 @@ static bool hasOneRealArgument(MultiExprArg Args) {
if (!Args[1]->isDefaultArgument())
return false;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 1:
return !Args[0]->isDefaultArgument();
}
@@ -15498,7 +15621,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
SourceRange ParenRange) {
if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
- if (DiagnoseUseOfDecl(Constructor, ConstructLoc))
+ // The only way to get here is if we did overlaod resolution to find the
+ // shadow decl, so we don't need to worry about re-checking the trailing
+ // requires clause.
+ if (DiagnoseUseOfOverloadedDecl(Constructor, ConstructLoc))
return ExprError();
}
@@ -15542,70 +15668,6 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
Constructor);
}
-ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
- assert(Field->hasInClassInitializer());
-
- // If we already have the in-class initializer nothing needs to be done.
- if (Field->getInClassInitializer())
- return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext);
-
- // If we might have already tried and failed to instantiate, don't try again.
- if (Field->isInvalidDecl())
- return ExprError();
-
- // Maybe we haven't instantiated the in-class initializer. Go check the
- // pattern FieldDecl to see if it has one.
- CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent());
-
- if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) {
- CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
- DeclContext::lookup_result Lookup =
- ClassPattern->lookup(Field->getDeclName());
-
- FieldDecl *Pattern = nullptr;
- for (auto L : Lookup) {
- if (isa<FieldDecl>(L)) {
- Pattern = cast<FieldDecl>(L);
- break;
- }
- }
- assert(Pattern && "We must have set the Pattern!");
-
- if (!Pattern->hasInClassInitializer() ||
- InstantiateInClassInitializer(Loc, Field, Pattern,
- getTemplateInstantiationArgs(Field))) {
- // Don't diagnose this again.
- Field->setInvalidDecl();
- return ExprError();
- }
- return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext);
- }
-
- // DR1351:
- // If the brace-or-equal-initializer of a non-static data member
- // invokes a defaulted default constructor of its class or of an
- // enclosing class in a potentially evaluated subexpression, the
- // program is ill-formed.
- //
- // This resolution is unworkable: the exception specification of the
- // default constructor can be needed in an unevaluated context, in
- // particular, in the operand of a noexcept-expression, and we can be
- // unable to compute an exception specification for an enclosed class.
- //
- // Any attempt to resolve the exception specification of a defaulted default
- // constructor before the initializer is lexically complete will ultimately
- // come here at which point we can diagnose it.
- RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext();
- Diag(Loc, diag::err_default_member_initializer_not_yet_parsed)
- << OutermostClass << Field;
- Diag(Field->getEndLoc(),
- diag::note_default_member_initializer_not_yet_parsed);
- // Recover by marking the field invalid, unless we're in a SFINAE context.
- if (!isSFINAEContext())
- Field->setInvalidDecl();
- return ExprError();
-}
-
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
if (VD->isInvalidDecl()) return;
// If initializing the variable failed, don't also diagnose problems with
@@ -15690,19 +15752,16 @@ bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
SmallVector<Expr *, 8> AllArgs;
- bool Invalid = GatherArgumentsForCall(Loc, Constructor,
- Proto, 0,
- llvm::makeArrayRef(Args, NumArgs),
- AllArgs,
- CallType, AllowExplicit,
- IsListInitialization);
+ bool Invalid = GatherArgumentsForCall(
+ Loc, Constructor, Proto, 0, llvm::ArrayRef(Args, NumArgs), AllArgs,
+ CallType, AllowExplicit, IsListInitialization);
ConvertedArgs.append(AllArgs.begin(), AllArgs.end());
DiagnoseSentinelCalls(Constructor, Loc, AllArgs);
CheckConstructorCall(Constructor, DeclInitType,
- llvm::makeArrayRef(AllArgs.data(), AllArgs.size()),
- Proto, Loc);
+ llvm::ArrayRef(AllArgs.data(), AllArgs.size()), Proto,
+ Loc);
return Invalid;
}
@@ -15901,18 +15960,28 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
if (Op == OO_New || Op == OO_Array_New)
return CheckOperatorNewDeclaration(*this, FnDecl);
- // C++ [over.oper]p6:
- // An operator function shall either be a non-static member
- // function or be a non-member function and have at least one
- // parameter whose type is a class, a reference to a class, an
- // enumeration, or a reference to an enumeration.
+ // C++ [over.oper]p7:
+ // An operator function shall either be a member function or
+ // be a non-member function and have at least one parameter
+ // whose type is a class, a reference to a class, an enumeration,
+ // or a reference to an enumeration.
+ // Note: Before C++23, a member function could not be static. The only member
+ // function allowed to be static is the call operator function.
if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) {
- if (MethodDecl->isStatic())
- return Diag(FnDecl->getLocation(),
- diag::err_operator_overload_static) << FnDecl->getDeclName();
+ if (MethodDecl->isStatic()) {
+ if (Op == OO_Call || Op == OO_Subscript)
+ Diag(FnDecl->getLocation(),
+ (LangOpts.CPlusPlus2b
+ ? diag::warn_cxx20_compat_operator_overload_static
+ : diag::ext_operator_overload_static))
+ << FnDecl;
+ else
+ return Diag(FnDecl->getLocation(), diag::err_operator_overload_static)
+ << FnDecl;
+ }
} else {
bool ClassOrEnumParam = false;
- for (auto Param : FnDecl->parameters()) {
+ for (auto *Param : FnDecl->parameters()) {
QualType ParamType = Param->getType().getNonReferenceType();
if (ParamType->isDependentType() || ParamType->isRecordType() ||
ParamType->isEnumeralType()) {
@@ -15935,7 +16004,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// operator (CWG2507) allow default arguments.
if (Op != OO_Call) {
ParmVarDecl *FirstDefaultedParam = nullptr;
- for (auto Param : FnDecl->parameters()) {
+ for (auto *Param : FnDecl->parameters()) {
if (Param->hasDefaultArg()) {
FirstDefaultedParam = Param;
break;
@@ -16008,7 +16077,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
<< FnDecl->getDeclName();
}
- // Some operators must be non-static member functions.
+ // Some operators must be member functions.
if (MustBeMemberOperator && !isa<CXXMethodDecl>(FnDecl)) {
return Diag(FnDecl->getLocation(),
diag::err_operator_overload_must_be_member)
@@ -16241,7 +16310,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
// A parameter-declaration-clause containing a default argument is not
// equivalent to any of the permitted forms.
- for (auto Param : FnDecl->parameters()) {
+ for (auto *Param : FnDecl->parameters()) {
if (Param->hasDefaultArg()) {
Diag(Param->getDefaultArgRange().getBegin(),
diag::err_literal_operator_default_argument)
@@ -16559,6 +16628,137 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc,
AssertMessage, RParenLoc, false);
}
+/// Convert \V to a string we can present to the user in a diagnostic
+/// \T is the type of the expression that has been evaluated into \V
+static bool ConvertAPValueToString(const APValue &V, QualType T,
+ SmallVectorImpl<char> &Str) {
+ if (!V.hasValue())
+ return false;
+
+ switch (V.getKind()) {
+ case APValue::ValueKind::Int:
+ if (T->isBooleanType()) {
+ // Bools are reduced to ints during evaluation, but for
+ // diagnostic purposes we want to print them as
+ // true or false.
+ int64_t BoolValue = V.getInt().getExtValue();
+ assert((BoolValue == 0 || BoolValue == 1) &&
+ "Bool type, but value is not 0 or 1");
+ llvm::raw_svector_ostream OS(Str);
+ OS << (BoolValue ? "true" : "false");
+ } else if (T->isCharType()) {
+ // Same is true for chars.
+ Str.push_back('\'');
+ Str.push_back(V.getInt().getExtValue());
+ Str.push_back('\'');
+ } else
+ V.getInt().toString(Str);
+
+ break;
+
+ case APValue::ValueKind::Float:
+ V.getFloat().toString(Str);
+ break;
+
+ case APValue::ValueKind::LValue:
+ if (V.isNullPointer()) {
+ llvm::raw_svector_ostream OS(Str);
+ OS << "nullptr";
+ } else
+ return false;
+ break;
+
+ case APValue::ValueKind::ComplexFloat: {
+ llvm::raw_svector_ostream OS(Str);
+ OS << '(';
+ V.getComplexFloatReal().toString(Str);
+ OS << " + ";
+ V.getComplexFloatImag().toString(Str);
+ OS << "i)";
+ } break;
+
+ case APValue::ValueKind::ComplexInt: {
+ llvm::raw_svector_ostream OS(Str);
+ OS << '(';
+ V.getComplexIntReal().toString(Str);
+ OS << " + ";
+ V.getComplexIntImag().toString(Str);
+ OS << "i)";
+ } break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/// Some Expression types are not useful to print notes about,
+/// e.g. literals and values that have already been expanded
+/// before such as int-valued template parameters.
+static bool UsefulToPrintExpr(const Expr *E) {
+ E = E->IgnoreParenImpCasts();
+ // Literals are pretty easy for humans to understand.
+ if (isa<IntegerLiteral, FloatingLiteral, CharacterLiteral, CXXBoolLiteralExpr,
+ CXXNullPtrLiteralExpr, FixedPointLiteral, ImaginaryLiteral>(E))
+ return false;
+
+ // These have been substituted from template parameters
+ // and appear as literals in the static assert error.
+ if (isa<SubstNonTypeTemplateParmExpr>(E))
+ return false;
+
+ // -5 is also simple to understand.
+ if (const auto *UnaryOp = dyn_cast<UnaryOperator>(E))
+ return UsefulToPrintExpr(UnaryOp->getSubExpr());
+
+ // Ignore nested binary operators. This could be a FIXME for improvements
+ // to the diagnostics in the future.
+ if (isa<BinaryOperator>(E))
+ return false;
+
+ return true;
+}
+
+/// Try to print more useful information about a failed static_assert
+/// with expression \E
+void Sema::DiagnoseStaticAssertDetails(const Expr *E) {
+ if (const auto *Op = dyn_cast<BinaryOperator>(E)) {
+ const Expr *LHS = Op->getLHS()->IgnoreParenImpCasts();
+ const Expr *RHS = Op->getRHS()->IgnoreParenImpCasts();
+
+ // Ignore comparisons of boolean expressions with a boolean literal.
+ if ((isa<CXXBoolLiteralExpr>(LHS) && RHS->getType()->isBooleanType()) ||
+ (isa<CXXBoolLiteralExpr>(RHS) && LHS->getType()->isBooleanType()))
+ return;
+
+ // Don't print obvious expressions.
+ if (!UsefulToPrintExpr(LHS) && !UsefulToPrintExpr(RHS))
+ return;
+
+ struct {
+ const clang::Expr *Cond;
+ Expr::EvalResult Result;
+ SmallString<12> ValueString;
+ bool Print;
+ } DiagSide[2] = {{LHS, Expr::EvalResult(), {}, false},
+ {RHS, Expr::EvalResult(), {}, false}};
+ for (unsigned I = 0; I < 2; I++) {
+ const Expr *Side = DiagSide[I].Cond;
+
+ Side->EvaluateAsRValue(DiagSide[I].Result, Context, true);
+
+ DiagSide[I].Print = ConvertAPValueToString(
+ DiagSide[I].Result.Val, Side->getType(), DiagSide[I].ValueString);
+ }
+ if (DiagSide[0].Print && DiagSide[1].Print) {
+ Diag(Op->getExprLoc(), diag::note_expr_evaluates_to)
+ << DiagSide[0].ValueString << Op->getOpcodeStr()
+ << DiagSide[1].ValueString << Op->getSourceRange();
+ }
+ }
+}
+
Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Expr *AssertExpr,
StringLiteral *AssertMessage,
@@ -16583,10 +16783,20 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
AssertExpr = FullAssertExpr.get();
llvm::APSInt Cond;
+ Expr *BaseExpr = AssertExpr;
+ AllowFoldKind FoldKind = NoFold;
+
+ if (!getLangOpts().CPlusPlus) {
+ // In C mode, allow folding as an extension for better compatibility with
+ // C++ in terms of expressions like static_assert("test") or
+ // static_assert(nullptr).
+ FoldKind = AllowFold;
+ }
+
if (!Failed && VerifyIntegerConstantExpression(
- AssertExpr, &Cond,
- diag::err_static_assert_expression_is_not_constant)
- .isInvalid())
+ BaseExpr, &Cond,
+ diag::err_static_assert_expression_is_not_constant,
+ FoldKind).isInvalid())
Failed = true;
if (!Failed && !Cond) {
@@ -16617,6 +16827,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
<< InnerCondDescription << !AssertMessage
<< Msg.str() << InnerCond->getSourceRange();
+ DiagnoseStaticAssertDetails(InnerCond);
} else {
Diag(StaticAssertLoc, diag::err_static_assert_failed)
<< !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
@@ -16650,7 +16861,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
QualType T = TSInfo->getType();
- SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange();
+ SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
// C++03 [class.friend]p2:
// An elaborated-type-specifier shall be used in a friend declaration
@@ -16716,12 +16927,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
/// Handle a friend tag declaration where the scope specifier was
/// templated.
-Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
- unsigned TagSpec, SourceLocation TagLoc,
- CXXScopeSpec &SS, IdentifierInfo *Name,
- SourceLocation NameLoc,
- const ParsedAttributesView &Attr,
- MultiTemplateParamsArg TempParamLists) {
+DeclResult Sema::ActOnTemplatedFriendTag(
+ Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc,
+ CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
+ const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
bool IsMemberSpecialization = false;
@@ -16734,7 +16943,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (TemplateParams->size() > 0) {
// This is a declaration of a class template.
if (Invalid)
- return nullptr;
+ return true;
return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name,
NameLoc, Attr, TemplateParams, AS_public,
@@ -16749,7 +16958,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
}
}
- if (Invalid) return nullptr;
+ if (Invalid) return true;
bool isAllExplicitSpecializations = true;
for (unsigned I = TempParamLists.size(); I-- > 0; ) {
@@ -16768,15 +16977,16 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (SS.isEmpty()) {
bool Owned = false;
bool IsDependent = false;
- return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc,
- Attr, AS_public,
+ UsingShadowDecl* FoundUsing = nullptr;
+ return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr,
+ AS_public,
/*ModulePrivateLoc=*/SourceLocation(),
MultiTemplateParamsArg(), Owned, IsDependent,
/*ScopedEnumKWLoc=*/SourceLocation(),
/*ScopedEnumUsesClassTag=*/false,
/*UnderlyingType=*/TypeResult(),
/*IsTypeSpecifier=*/false,
- /*IsTemplateParamOrArg=*/false);
+ /*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside, FoundUsing);
}
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
@@ -16785,7 +16995,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc,
*Name, NameLoc);
if (T.isNull())
- return nullptr;
+ return true;
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
@@ -17353,6 +17563,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
FD->setDefaulted();
FD->setExplicitlyDefaulted();
+ FD->setDefaultLoc(DefaultLoc);
// Defer checking functions that are defaulted in a dependent context.
if (FD->isDependentContext())
@@ -17392,7 +17603,8 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
} else {
auto *MD = cast<CXXMethodDecl>(FD);
- if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember()))
+ if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember(),
+ DefaultLoc))
MD->setInvalidDecl();
else
DefineDefaultedFunction(*this, MD, DefaultLoc);
@@ -17817,7 +18029,7 @@ bool Sema::DefineUsedVTables() {
// definition.
bool IsExplicitInstantiationDeclaration =
ClassTSK == TSK_ExplicitInstantiationDeclaration;
- for (auto R : Class->redecls()) {
+ for (auto *R : Class->redecls()) {
TemplateSpecializationKind TSK
= cast<CXXRecordDecl>(R)->getTemplateSpecializationKind();
if (TSK == TSK_ExplicitInstantiationDeclaration)
@@ -17929,9 +18141,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) {
InitializationKind InitKind =
InitializationKind::CreateDefault(ObjCImplementation->getLocation());
- InitializationSequence InitSeq(*this, InitEntity, InitKind, None);
+ InitializationSequence InitSeq(*this, InitEntity, InitKind, std::nullopt);
ExprResult MemberInit =
- InitSeq.Perform(*this, InitEntity, InitKind, None);
+ InitSeq.Perform(*this, InitEntity, InitKind, std::nullopt);
MemberInit = MaybeCreateExprWithCleanups(MemberInit);
// Note, MemberInit could actually come back empty if no initialization
// is required (e.g., because it would call a trivial default constructor)
@@ -18032,8 +18244,8 @@ void Sema::CheckDelegatingCtorCycles() {
llvm::SmallPtrSet<CXXConstructorDecl*, 4> Valid, Invalid, Current;
for (DelegatingCtorDeclsType::iterator
- I = DelegatingCtorDecls.begin(ExternalSource),
- E = DelegatingCtorDecls.end();
+ I = DelegatingCtorDecls.begin(ExternalSource.get()),
+ E = DelegatingCtorDecls.end();
I != E; ++I)
DelegatingCycleHelper(*I, Valid, Invalid, Current, *this);
@@ -18123,7 +18335,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
case EST_NoexceptTrue:
if (!Finder.TraverseStmt(Proto->getNoexceptExpr()))
return true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case EST_Dynamic:
for (const auto &E : Proto->exceptions()) {
@@ -18149,27 +18361,27 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
else if (const auto *G = dyn_cast<PtGuardedByAttr>(A))
Arg = G->getArg();
else if (const auto *AA = dyn_cast<AcquiredAfterAttr>(A))
- Args = llvm::makeArrayRef(AA->args_begin(), AA->args_size());
+ Args = llvm::ArrayRef(AA->args_begin(), AA->args_size());
else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A))
- Args = llvm::makeArrayRef(AB->args_begin(), AB->args_size());
+ Args = llvm::ArrayRef(AB->args_begin(), AB->args_size());
else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) {
Arg = ETLF->getSuccessValue();
- Args = llvm::makeArrayRef(ETLF->args_begin(), ETLF->args_size());
+ Args = llvm::ArrayRef(ETLF->args_begin(), ETLF->args_size());
} else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) {
Arg = STLF->getSuccessValue();
- Args = llvm::makeArrayRef(STLF->args_begin(), STLF->args_size());
+ Args = llvm::ArrayRef(STLF->args_begin(), STLF->args_size());
} else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
Arg = LR->getArg();
else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A))
- Args = llvm::makeArrayRef(LE->args_begin(), LE->args_size());
+ Args = llvm::ArrayRef(LE->args_begin(), LE->args_size());
else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A))
- Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size());
+ Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A))
- Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size());
+ Args = llvm::ArrayRef(AC->args_begin(), AC->args_size());
else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A))
- Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size());
+ Args = llvm::ArrayRef(AC->args_begin(), AC->args_size());
else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A))
- Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size());
+ Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
if (Arg && !Finder.TraverseStmt(Arg))
return true;
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index a574a5539330..fdfc6d312b38 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -782,7 +782,7 @@ ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S,
// scope until later (after the instance variable block), but we want the
// diagnostics to occur right after we parse the type parameter list.
llvm::SmallDenseMap<IdentifierInfo *, ObjCTypeParamDecl *> knownParams;
- for (auto typeParam : typeParams) {
+ for (auto *typeParam : typeParams) {
auto known = knownParams.find(typeParam->getIdentifier());
if (known != knownParams.end()) {
Diag(typeParam->getLocation(), diag::err_objc_type_param_redecl)
@@ -803,7 +803,7 @@ ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S,
}
void Sema::popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList) {
- for (auto typeParam : *typeParamList) {
+ for (auto *typeParam : *typeParamList) {
if (!typeParam->isInvalidDecl()) {
S->RemoveDecl(typeParam);
IdResolver.RemoveDecl(typeParam);
@@ -978,7 +978,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
ArrayRef<ParsedType> SuperTypeArgs, SourceRange SuperTypeArgsRange,
Decl *const *ProtoRefs, unsigned NumProtoRefs,
const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc,
- const ParsedAttributesView &AttrList) {
+ const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody) {
assert(ClassName && "Missing class identifier");
// Check for another declaration kind with the same name.
@@ -1029,7 +1029,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
// Clone the type parameter list.
SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams;
- for (auto typeParam : *prevTypeParamList) {
+ for (auto *typeParam : *prevTypeParamList) {
clonedTypeParams.push_back(
ObjCTypeParamDecl::Create(
Context,
@@ -1057,10 +1057,16 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
if (PrevIDecl) {
// Class already seen. Was it a definition?
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
- Diag(AtInterfaceLoc, diag::err_duplicate_class_def)
- << PrevIDecl->getDeclName();
- Diag(Def->getLocation(), diag::note_previous_definition);
- IDecl->setInvalidDecl();
+ if (SkipBody && !hasVisibleDefinition(Def)) {
+ SkipBody->CheckSameAsPrevious = true;
+ SkipBody->New = IDecl;
+ SkipBody->Previous = Def;
+ } else {
+ Diag(AtInterfaceLoc, diag::err_duplicate_class_def)
+ << PrevIDecl->getDeclName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ IDecl->setInvalidDecl();
+ }
}
}
@@ -1075,7 +1081,9 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(
// Start the definition of this class. If we're in a redefinition case, there
// may already be a definition, so we'll end up adding to it.
- if (!IDecl->hasDefinition())
+ if (SkipBody && SkipBody->CheckSameAsPrevious)
+ IDecl->startDuplicateDefinitionForComparison();
+ else if (!IDecl->hasDefinition())
IDecl->startDefinition();
if (SuperName) {
@@ -1213,7 +1221,7 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface(
SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName,
SourceLocation ProtocolLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs,
const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc,
- const ParsedAttributesView &AttrList) {
+ const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody) {
bool err = false;
// FIXME: Deal with AttrList.
assert(ProtocolName && "Missing protocol identifier");
@@ -1221,23 +1229,29 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface(
forRedeclarationInCurContext());
ObjCProtocolDecl *PDecl = nullptr;
if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) {
- // If we already have a definition, complain.
- Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
- Diag(Def->getLocation(), diag::note_previous_definition);
-
// Create a new protocol that is completely distinct from previous
// declarations, and do not make this protocol available for name lookup.
// That way, we'll end up completely ignoring the duplicate.
// FIXME: Can we turn this into an error?
PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName,
ProtocolLoc, AtProtoInterfaceLoc,
- /*PrevDecl=*/nullptr);
+ /*PrevDecl=*/Def);
+
+ if (SkipBody && !hasVisibleDefinition(Def)) {
+ SkipBody->CheckSameAsPrevious = true;
+ SkipBody->New = PDecl;
+ SkipBody->Previous = Def;
+ } else {
+ // If we already have a definition, complain.
+ Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
// If we are using modules, add the decl to the context in order to
// serialize something meaningful.
if (getLangOpts().Modules)
PushOnScopeChains(PDecl, TUScope);
- PDecl->startDefinition();
+ PDecl->startDuplicateDefinitionForComparison();
} else {
if (PrevDecl) {
// Check for circular dependencies among protocol declarations. This can
@@ -1502,7 +1516,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> knownProtocols;
Context.CollectInheritedProtocols(baseClass, knownProtocols);
bool allProtocolsDeclared = true;
- for (auto proto : protocols) {
+ for (auto *proto : protocols) {
if (knownProtocols.count(static_cast<ObjCProtocolDecl *>(proto)) == 0) {
allProtocolsDeclared = false;
break;
@@ -2355,21 +2369,17 @@ static bool CheckMethodOverrideReturn(Sema &S,
!S.Context.hasSameNullabilityTypeQualifier(MethodImpl->getReturnType(),
MethodDecl->getReturnType(),
false)) {
- auto nullabilityMethodImpl =
- *MethodImpl->getReturnType()->getNullability(S.Context);
- auto nullabilityMethodDecl =
- *MethodDecl->getReturnType()->getNullability(S.Context);
- S.Diag(MethodImpl->getLocation(),
- diag::warn_conflicting_nullability_attr_overriding_ret_types)
- << DiagNullabilityKind(
- nullabilityMethodImpl,
- ((MethodImpl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- != 0))
- << DiagNullabilityKind(
- nullabilityMethodDecl,
- ((MethodDecl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- != 0));
- S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
+ auto nullabilityMethodImpl = *MethodImpl->getReturnType()->getNullability();
+ auto nullabilityMethodDecl = *MethodDecl->getReturnType()->getNullability();
+ S.Diag(MethodImpl->getLocation(),
+ diag::warn_conflicting_nullability_attr_overriding_ret_types)
+ << DiagNullabilityKind(nullabilityMethodImpl,
+ ((MethodImpl->getObjCDeclQualifier() &
+ Decl::OBJC_TQ_CSNullability) != 0))
+ << DiagNullabilityKind(nullabilityMethodDecl,
+ ((MethodDecl->getObjCDeclQualifier() &
+ Decl::OBJC_TQ_CSNullability) != 0));
+ S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
}
if (S.Context.hasSameUnqualifiedType(MethodImpl->getReturnType(),
@@ -2447,14 +2457,12 @@ static bool CheckMethodOverrideParam(Sema &S,
!S.Context.hasSameNullabilityTypeQualifier(ImplTy, IfaceTy, true)) {
S.Diag(ImplVar->getLocation(),
diag::warn_conflicting_nullability_attr_overriding_param_types)
- << DiagNullabilityKind(
- *ImplTy->getNullability(S.Context),
- ((ImplVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- != 0))
- << DiagNullabilityKind(
- *IfaceTy->getNullability(S.Context),
- ((IfaceVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability)
- != 0));
+ << DiagNullabilityKind(*ImplTy->getNullability(),
+ ((ImplVar->getObjCDeclQualifier() &
+ Decl::OBJC_TQ_CSNullability) != 0))
+ << DiagNullabilityKind(*IfaceTy->getNullability(),
+ ((IfaceVar->getObjCDeclQualifier() &
+ Decl::OBJC_TQ_CSNullability) != 0));
S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration);
}
if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy))
@@ -3754,7 +3762,7 @@ Sema::SelectorsForTypoCorrection(Selector Sel,
/// DiagnoseDuplicateIvars -
/// Check for duplicate ivars in the entire class at the start of
-/// \@implementation. This becomes necesssary because class extension can
+/// \@implementation. This becomes necessary because class extension can
/// add ivars to a class in random order which will not be known until
/// class's \@implementation is seen.
void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID,
@@ -3855,7 +3863,7 @@ static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) {
// Check if variable sized ivar is in interface and visible to subclasses.
if (!isa<ObjCInterfaceDecl>(OCD)) {
- for (auto ivar : Ivars) {
+ for (auto *ivar : Ivars) {
if (!ivar->isInvalidDecl() && IsVariableSizedType(ivar->getType())) {
S.Diag(ivar->getLocation(), diag::warn_variable_sized_ivar_visibility)
<< ivar->getDeclName() << ivar->getType();
@@ -3990,7 +3998,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
// they are overridden by an explicit method that is encountered
// later.
if (auto *OID = dyn_cast<ObjCImplementationDecl>(CurContext)) {
- for (auto PropImpl : OID->property_impls()) {
+ for (auto *PropImpl : OID->property_impls()) {
if (auto *Getter = PropImpl->getGetterMethodDecl())
if (Getter->isSynthesizedAccessorStub())
OID->addDecl(Getter);
@@ -4432,6 +4440,11 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
ResultTypeCompatibilityKind RTC) {
if (!ObjCMethod)
return;
+ auto IsMethodInCurrentClass = [CurrentClass](const ObjCMethodDecl *M) {
+ // Checking canonical decl works across modules.
+ return M->getClassInterface()->getCanonicalDecl() ==
+ CurrentClass->getCanonicalDecl();
+ };
// Search for overridden methods and merge information down from them.
OverrideSearch overrides(*this, ObjCMethod);
// Keep track if the method overrides any method in the class's base classes,
@@ -4443,8 +4456,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
for (ObjCMethodDecl *overridden : overrides) {
if (!hasOverriddenMethodsInBaseOrProtocol) {
if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
- CurrentClass != overridden->getClassInterface() ||
- overridden->isOverriding()) {
+ !IsMethodInCurrentClass(overridden) || overridden->isOverriding()) {
CheckObjCMethodDirectOverrides(ObjCMethod, overridden);
hasOverriddenMethodsInBaseOrProtocol = true;
} else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {
@@ -4469,7 +4481,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod,
OverrideSearch overrides(*this, overridden);
for (ObjCMethodDecl *SuperOverridden : overrides) {
if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||
- CurrentClass != SuperOverridden->getClassInterface()) {
+ !IsMethodInCurrentClass(SuperOverridden)) {
CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden);
hasOverriddenMethodsInBaseOrProtocol = true;
overridden->setOverriding(true);
@@ -4533,8 +4545,8 @@ static QualType mergeTypeNullabilityForRedecl(Sema &S, SourceLocation loc,
QualType prevType,
bool prevUsesCSKeyword) {
// Determine the nullability of both types.
- auto nullability = type->getNullability(S.Context);
- auto prevNullability = prevType->getNullability(S.Context);
+ auto nullability = type->getNullability();
+ auto prevNullability = prevType->getNullability();
// Easy case: both have nullability.
if (nullability.has_value() == prevNullability.has_value()) {
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index d8344cfd01f9..a5a57c38bb48 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -21,6 +21,7 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include <optional>
namespace clang {
@@ -1289,6 +1290,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::StmtExprClass:
case Expr::ConvertVectorExprClass:
case Expr::VAArgExprClass:
+ case Expr::CXXParenListInitExprClass:
return canSubStmtsThrow(*this, S);
case Expr::CompoundLiteralExprClass:
@@ -1494,6 +1496,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OMPTaskLoopSimdDirectiveClass:
case Stmt::OMPTaskwaitDirectiveClass:
case Stmt::OMPTaskyieldDirectiveClass:
+ case Stmt::OMPErrorDirectiveClass:
case Stmt::OMPTeamsDirectiveClass:
case Stmt::OMPTeamsDistributeDirectiveClass:
case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
@@ -1545,7 +1548,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// For 'if constexpr', consider only the non-discarded case.
// FIXME: We should add a DiscardedStmt marker to the AST.
- if (Optional<const Stmt *> Case = IS->getNondiscardedCase(Context))
+ if (std::optional<const Stmt *> Case = IS->getNondiscardedCase(Context))
return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT;
CanThrowResult Then = canThrow(IS->getThen());
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0f79978b0911..2842add2cc4a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -56,6 +56,7 @@
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/TypeSize.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -136,7 +137,7 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
/// Determine whether a FunctionDecl was ever declared with an
/// explicit storage class.
static bool hasAnyExplicitStorageClass(const FunctionDecl *D) {
- for (auto I : D->redecls()) {
+ for (auto *I : D->redecls()) {
if (I->getStorageClass() != SC_None)
return true;
}
@@ -222,7 +223,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
const ObjCInterfaceDecl *UnknownObjCClass,
bool ObjCPropertyAccess,
bool AvoidPartialAvailabilityChecks,
- ObjCInterfaceDecl *ClassReceiver) {
+ ObjCInterfaceDecl *ClassReceiver,
+ bool SkipTrailingRequiresClause) {
SourceLocation Loc = Locs.front();
if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) {
// If there were any diagnostics suppressed by template argument deduction,
@@ -281,9 +283,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
// See if this is a function with constraints that need to be satisfied.
// Check this before deducing the return type, as it might instantiate the
// definition.
- if (FD->getTrailingRequiresClause()) {
+ if (!SkipTrailingRequiresClause && FD->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(FD, Satisfaction, Loc))
+ if (CheckFunctionConstraints(FD, Satisfaction, Loc,
+ /*ForOverloadResolution*/ true))
// A diagnostic will have already been generated (non-constant
// constraint expression, for example)
return true;
@@ -349,7 +352,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
// [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions
// List-items in map clauses on this construct may only refer to the declared
// variable var and entities that could be referenced by a procedure defined
- // at the same location
+ // at the same location.
+ // [OpenMP 5.2] Also allow iterator declared variables.
if (LangOpts.OpenMP && isa<VarDecl>(D) &&
!isOpenMPDeclareMapperVarDeclAllowed(cast<VarDecl>(D))) {
Diag(Loc, diag::err_omp_declare_mapper_wrong_var)
@@ -837,7 +841,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
E = ImpCastExprToType(E, PTy, CK_IntegralCast).get();
return E;
}
- if (Ty->isPromotableIntegerType()) {
+ if (Context.isPromotableIntegerType(Ty)) {
QualType PT = Context.getPromotedIntegerType(Ty);
E = ImpCastExprToType(E, PT, CK_IntegralCast).get();
return E;
@@ -976,7 +980,7 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) {
DiagRuntimeBehavior(
E->getBeginLoc(), nullptr,
PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) << Ty << CT);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case VAK_Valid:
if (Ty->isRecordType()) {
// This is unlikely to be what the user intended. If the class has a
@@ -1056,7 +1060,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
return ExprError();
ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(),
- None, E->getEndLoc());
+ std::nullopt, E->getEndLoc());
if (Call.isInvalid())
return ExprError();
@@ -1088,7 +1092,7 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true;
if (SkipCast) return false;
if (IntTy->isIntegerType()) {
- QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType();
+ QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType();
IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating);
IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy,
CK_FloatingRealToComplex);
@@ -1100,60 +1104,59 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
return false;
}
+// This handles complex/complex, complex/float, or float/complex.
+// When both operands are complex, the shorter operand is converted to the
+// type of the longer, and that is the type of the result. This corresponds
+// to what is done when combining two real floating-point operands.
+// The fun begins when size promotion occur across type domains.
+// From H&S 6.3.4: When one operand is complex and the other is a real
+// floating-point type, the less precise type is converted, within it's
+// real or complex domain, to the precision of the other type. For example,
+// when combining a "long double" with a "double _Complex", the
+// "double _Complex" is promoted to "long double _Complex".
+static QualType handleComplexFloatConversion(Sema &S, ExprResult &Shorter,
+ QualType ShorterType,
+ QualType LongerType,
+ bool PromotePrecision) {
+ bool LongerIsComplex = isa<ComplexType>(LongerType.getCanonicalType());
+ QualType Result =
+ LongerIsComplex ? LongerType : S.Context.getComplexType(LongerType);
+
+ if (PromotePrecision) {
+ if (isa<ComplexType>(ShorterType.getCanonicalType())) {
+ Shorter =
+ S.ImpCastExprToType(Shorter.get(), Result, CK_FloatingComplexCast);
+ } else {
+ if (LongerIsComplex)
+ LongerType = LongerType->castAs<ComplexType>()->getElementType();
+ Shorter = S.ImpCastExprToType(Shorter.get(), LongerType, CK_FloatingCast);
+ }
+ }
+ return Result;
+}
+
/// Handle arithmetic conversion with complex types. Helper function of
/// UsualArithmeticConversions()
-static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
- ExprResult &RHS, QualType LHSType,
- QualType RHSType,
- bool IsCompAssign) {
+static QualType handleComplexConversion(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, QualType LHSType,
+ QualType RHSType, bool IsCompAssign) {
// if we have an integer operand, the result is the complex type.
if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType,
- /*skipCast*/false))
+ /*SkipCast=*/false))
return LHSType;
if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType,
- /*skipCast*/IsCompAssign))
+ /*SkipCast=*/IsCompAssign))
return RHSType;
- // This handles complex/complex, complex/float, or float/complex.
- // When both operands are complex, the shorter operand is converted to the
- // type of the longer, and that is the type of the result. This corresponds
- // to what is done when combining two real floating-point operands.
- // The fun begins when size promotion occur across type domains.
- // From H&S 6.3.4: When one operand is complex and the other is a real
- // floating-point type, the less precise type is converted, within it's
- // real or complex domain, to the precision of the other type. For example,
- // when combining a "long double" with a "double _Complex", the
- // "double _Complex" is promoted to "long double _Complex".
-
// Compute the rank of the two types, regardless of whether they are complex.
int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
-
- auto *LHSComplexType = dyn_cast<ComplexType>(LHSType);
- auto *RHSComplexType = dyn_cast<ComplexType>(RHSType);
- QualType LHSElementType =
- LHSComplexType ? LHSComplexType->getElementType() : LHSType;
- QualType RHSElementType =
- RHSComplexType ? RHSComplexType->getElementType() : RHSType;
-
- QualType ResultType = S.Context.getComplexType(LHSElementType);
- if (Order < 0) {
+ if (Order < 0)
// Promote the precision of the LHS if not an assignment.
- ResultType = S.Context.getComplexType(RHSElementType);
- if (!IsCompAssign) {
- if (LHSComplexType)
- LHS =
- S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast);
- else
- LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast);
- }
- } else if (Order > 0) {
- // Promote the precision of the RHS.
- if (RHSComplexType)
- RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast);
- else
- RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast);
- }
- return ResultType;
+ return handleComplexFloatConversion(S, LHS, LHSType, RHSType,
+ /*PromotePrecision=*/!IsCompAssign);
+ // Promote the precision of the RHS unless it is already the same as the LHS.
+ return handleComplexFloatConversion(S, RHS, RHSType, LHSType,
+ /*PromotePrecision=*/Order > 0);
}
/// Handle arithmetic conversion from integer to float. Helper function
@@ -1539,18 +1542,16 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
- QualType LHSType =
- Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
- QualType RHSType =
- Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
+ QualType LHSType = LHS.get()->getType().getUnqualifiedType();
+ QualType RHSType = RHS.get()->getType().getUnqualifiedType();
// For conversion purposes, we ignore any atomic qualifier on the LHS.
if (const AtomicType *AtomicLHS = LHSType->getAs<AtomicType>())
LHSType = AtomicLHS->getValueType();
// If both types are identical, no conversion is needed.
- if (LHSType == RHSType)
- return LHSType;
+ if (Context.hasSameType(LHSType, RHSType))
+ return Context.getCommonSugaredType(LHSType, RHSType);
// If either side is a non-arithmetic type (e.g. a pointer), we are done.
// The caller can deal with this (e.g. pointer + int).
@@ -1559,7 +1560,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// Apply unary and bitfield promotions to the LHS's type.
QualType LHSUnpromotedType = LHSType;
- if (LHSType->isPromotableIntegerType())
+ if (Context.isPromotableIntegerType(LHSType))
LHSType = Context.getPromotedIntegerType(LHSType);
QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get());
if (!LHSBitfieldPromoteTy.isNull())
@@ -1568,8 +1569,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast);
// If both types are identical, no conversion is needed.
- if (LHSType == RHSType)
- return LHSType;
+ if (Context.hasSameType(LHSType, RHSType))
+ return Context.getCommonSugaredType(LHSType, RHSType);
// At this point, we have two different arithmetic types.
@@ -1580,8 +1581,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// Handle complex types first (C99 6.3.1.8p1).
if (LHSType->isComplexType() || RHSType->isComplexType())
- return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType,
- ACK == ACK_CompAssign);
+ return handleComplexConversion(*this, LHS, RHS, LHSType, RHSType,
+ ACK == ACK_CompAssign);
// Now handle "real" floating types (i.e. float, double, long double).
if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType())
@@ -1624,10 +1625,9 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
Types[i] = nullptr;
}
- ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
- ControllingExpr,
- llvm::makeArrayRef(Types, NumAssocs),
- ArgExprs);
+ ExprResult ER =
+ CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, ControllingExpr,
+ llvm::ArrayRef(Types, NumAssocs), ArgExprs);
delete [] Types;
return ER;
}
@@ -1839,7 +1839,7 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope,
OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc);
LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName);
- if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()),
+ if (S.LookupLiteralOperator(Scope, R, llvm::ArrayRef(ArgTy, Args.size()),
/*AllowRaw*/ false, /*AllowTemplate*/ false,
/*AllowStringTemplatePack*/ false,
/*DiagnoseMissing*/ true) == Sema::LOLR_Error)
@@ -1964,8 +1964,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
TemplateArgument Arg(Lit);
TemplateArgumentLocInfo ArgInfo(Lit);
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
- return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(),
- &ExplicitArgs);
+ return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt,
+ StringTokLocs.back(), &ExplicitArgs);
}
case LOLR_StringTemplatePack: {
@@ -1985,8 +1985,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) {
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
}
- return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(),
- &ExplicitArgs);
+ return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt,
+ StringTokLocs.back(), &ExplicitArgs);
}
case LOLR_Raw:
case LOLR_ErrorNoDiagnostic:
@@ -2082,9 +2082,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
NestedNameSpecifierLoc NNS, NamedDecl *FoundD,
SourceLocation TemplateKWLoc,
const TemplateArgumentListInfo *TemplateArgs) {
- bool RefersToCapturedVariable =
- isa<VarDecl>(D) &&
- NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
+ bool RefersToCapturedVariable = isa<VarDecl, BindingDecl>(D) &&
+ NeedToCaptureVariable(D, NameInfo.getLoc());
DeclRefExpr *E = DeclRefExpr::Create(
Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
@@ -2626,7 +2625,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// a template name, but we happen to have always already looked up the name
// before we get here if it must be a template name.
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr,
- None, &TE)) {
+ std::nullopt, &TE)) {
if (TE && KeywordReplacement) {
auto &State = getTypoExprState(TE);
auto BestTC = State.Consumer->getNextCorrection();
@@ -2738,6 +2737,10 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
ExprResult Sema::BuildQualifiedDeclarationNameExpr(
CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) {
+ if (NameInfo.getName().isDependentName())
+ return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, /*TemplateArgs=*/nullptr);
+
DeclContext *DC = computeDeclContext(SS, false);
if (!DC)
return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
@@ -2947,7 +2950,7 @@ ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc,
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
getCurFunction()->recordUseOfWeak(Result);
}
- if (getLangOpts().ObjCAutoRefCount)
+ if (getLangOpts().ObjCAutoRefCount && !isUnevaluatedContext())
if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
@@ -3187,8 +3190,9 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
/// as an expression. This is only actually called for lookups that
/// were not overloaded, and it doesn't promise that the declaration
/// will in fact be used.
-static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) {
- if (D->isInvalidDecl())
+static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D,
+ bool AcceptInvalid) {
+ if (D->isInvalidDecl() && !AcceptInvalid)
return true;
if (isa<TypedefNameDecl>(D)) {
@@ -3234,7 +3238,8 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// result, because in the overloaded case the results can only be
// functions and function templates.
if (R.isSingleResult() && !ShouldLookupResultBeMultiVersionOverload(R) &&
- CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl()))
+ CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl(),
+ AcceptInvalidDecl))
return ExprError();
// Otherwise, just build an unresolved lookup expression. Suppress
@@ -3252,8 +3257,9 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return ULE;
}
-static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
- ValueDecl *var);
+static void diagnoseUncapturableValueReferenceOrBinding(Sema &S,
+ SourceLocation loc,
+ ValueDecl *var);
/// Complete semantic analysis for a reference to the given declaration.
ExprResult Sema::BuildDeclarationNameExpr(
@@ -3265,7 +3271,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
"Cannot refer unambiguously to a function template");
SourceLocation Loc = NameInfo.getLoc();
- if (CheckDeclInExpr(*this, Loc, D)) {
+ if (CheckDeclInExpr(*this, Loc, D, AcceptInvalidDecl)) {
// Recovery from invalid cases (e.g. D is an invalid Decl).
// We use the dependent type for the RecoveryExpr to prevent bogus follow-up
// diagnostics, as invalid decls use int as a fallback type.
@@ -3391,7 +3397,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
valueKind = VK_PRValue;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Decl::ImplicitParam:
case Decl::ParmVar: {
@@ -3411,20 +3417,11 @@ ExprResult Sema::BuildDeclarationNameExpr(
break;
}
- case Decl::Binding: {
+ case Decl::Binding:
// These are always lvalues.
valueKind = VK_LValue;
type = type.getNonReferenceType();
- // FIXME: Support lambda-capture of BindingDecls, once CWG actually
- // decides how that's supposed to work.
- auto *BD = cast<BindingDecl>(VD);
- if (BD->getDeclContext() != CurContext) {
- auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
- if (DD && DD->hasLocalStorage())
- diagnoseUncapturableValueReference(*this, Loc, BD);
- }
break;
- }
case Decl::Function: {
if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
@@ -3497,7 +3494,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
valueKind = VK_LValue;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Decl::CXXConversion:
case Decl::CXXDestructor:
@@ -3506,9 +3503,16 @@ ExprResult Sema::BuildDeclarationNameExpr(
break;
}
- return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
- /*FIXME: TemplateKWLoc*/ SourceLocation(),
- TemplateArgs);
+ auto *E =
+ BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD,
+ /*FIXME: TemplateKWLoc*/ SourceLocation(), TemplateArgs);
+ // Clang AST consumers assume a DeclRefExpr refers to a valid decl. We
+ // wrap a DeclRefExpr referring to an invalid decl with a dependent-type
+ // RecoveryExpr to avoid follow-up semantic analysis (thus prevent bogus
+ // diagnostics).
+ if (VD->isInvalidDecl() && E)
+ return CreateRecoveryExpr(E->getBeginLoc(), E->getEndLoc(), {E});
+ return E;
}
static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
@@ -3856,7 +3860,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
TemplateArgumentLocInfo ArgInfo;
ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
}
- return BuildLiteralOperatorCall(R, OpNameInfo, None, TokLoc,
+ return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, TokLoc,
&ExplicitArgs);
}
case LOLR_StringTemplatePack:
@@ -3949,16 +3953,6 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
} else {
QualType Ty;
- // 'long long' is a C99 or C++11 feature.
- if (!getLangOpts().C99 && Literal.isLongLong) {
- if (getLangOpts().CPlusPlus)
- Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
- else
- Diag(Tok.getLocation(), diag::ext_c99_longlong);
- }
-
// 'z/uz' literals are a C++2b feature.
if (Literal.isSizeT)
Diag(Tok.getLocation(), getLangOpts().CPlusPlus
@@ -4125,6 +4119,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
else if (AllowUnsigned)
Ty = Context.UnsignedLongLongTy;
Width = LongLongSize;
+
+ // 'long long' is a C99 or C++11 feature, whether the literal
+ // explicitly specified 'long long' or we needed the extra width.
+ if (getLangOpts().CPlusPlus)
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_longlong
+ : diag::ext_cxx11_longlong);
+ else if (!getLangOpts().C99)
+ Diag(Tok.getLocation(), diag::ext_c99_longlong);
}
}
@@ -4504,7 +4507,6 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::ConstantMatrix:
case Type::Record:
case Type::Enum:
- case Type::Elaborated:
case Type::TemplateSpecialization:
case Type::ObjCObject:
case Type::ObjCInterface:
@@ -4513,6 +4515,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
case Type::Pipe:
case Type::BitInt:
llvm_unreachable("type class is never variably-modified!");
+ case Type::Elaborated:
+ T = cast<ElaboratedType>(Ty)->getNamedType();
+ break;
case Type::Adjusted:
T = cast<AdjustedType>(Ty)->getOriginalType();
break;
@@ -5011,7 +5016,7 @@ ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx,
return nullptr;
}
- if (Optional<llvm::APSInt> Idx =
+ if (std::optional<llvm::APSInt> Idx =
IndexExpr->getIntegerConstantExpr(Context)) {
if ((*Idx < 0 || *Idx >= Dim)) {
Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range)
@@ -5415,6 +5420,10 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc,
} else {
CurContext->addDecl(VD);
}
+
+ /// Act on the iterator variable declaration.
+ ActOnOpenMPIteratorVarDecl(VD);
+
Expr *Begin = D.Range.Begin;
if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) {
ExprResult BeginRes =
@@ -5434,7 +5443,8 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc,
IsCorrect = false;
continue;
}
- Optional<llvm::APSInt> Result = Step->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> Result =
+ Step->getIntegerConstantExpr(Context);
// OpenMP 5.0, 2.1.6 Iterators, Restrictions
// If the step expression of a range-specification equals zero, the
// behavior is unspecified.
@@ -5856,8 +5866,10 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
}
bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
- ParmVarDecl *Param) {
+ ParmVarDecl *Param, Expr *RewrittenInit,
+ bool SkipImmediateInvocations) {
if (Param->hasUnparsedDefaultArg()) {
+ assert(!RewrittenInit && "Should not have a rewritten init expression yet");
// If we've already cleared out the location for the default argument,
// that means we're parsing it right now.
if (!UnparsedDefaultArgLocs.count(Param)) {
@@ -5874,11 +5886,14 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
return true;
}
- if (Param->hasUninstantiatedDefaultArg() &&
- InstantiateDefaultArgument(CallLoc, FD, Param))
- return true;
+ if (Param->hasUninstantiatedDefaultArg()) {
+ assert(!RewrittenInit && "Should not have a rewitten init expression yet");
+ if (InstantiateDefaultArgument(CallLoc, FD, Param))
+ return true;
+ }
- assert(Param->hasInit() && "default argument but no initializer?");
+ Expr *Init = RewrittenInit ? RewrittenInit : Param->getInit();
+ assert(Init && "default argument but no initializer?");
// If the default expression creates temporaries, we need to
// push them to the current stack of expression temporaries so they'll
@@ -5887,34 +5902,258 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// bound temporaries; see the comment in PR5810.
// We don't need to do that with block decls, though, because
// blocks in default argument expression can never capture anything.
- if (auto Init = dyn_cast<ExprWithCleanups>(Param->getInit())) {
+ if (auto *InitWithCleanup = dyn_cast<ExprWithCleanups>(Init)) {
// Set the "needs cleanups" bit regardless of whether there are
// any explicit objects.
- Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects());
-
+ Cleanup.setExprNeedsCleanups(InitWithCleanup->cleanupsHaveSideEffects());
// Append all the objects to the cleanup list. Right now, this
// should always be a no-op, because blocks in default argument
// expressions should never be able to capture anything.
- assert(!Init->getNumObjects() &&
+ assert(!InitWithCleanup->getNumObjects() &&
"default argument expression has capturing blocks?");
}
-
- // We already type-checked the argument, so we know it works.
- // Just mark all of the declarations in this potentially-evaluated expression
- // as being "referenced".
EnterExpressionEvaluationContext EvalContext(
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
- MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
- /*SkipLocalVariables=*/true);
+ ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
+ SkipImmediateInvocations;
+ MarkDeclarationsReferencedInExpr(Init, /*SkipLocalVariables*/ true);
return false;
}
+struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> {
+ bool HasImmediateCalls = false;
+
+ bool shouldVisitImplicitCode() const { return true; }
+
+ bool VisitCallExpr(CallExpr *E) {
+ if (const FunctionDecl *FD = E->getDirectCallee())
+ HasImmediateCalls |= FD->isConsteval();
+ return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
+ }
+
+ // SourceLocExpr are not immediate invocations
+ // but CXXDefaultInitExpr/CXXDefaultArgExpr containing a SourceLocExpr
+ // need to be rebuilt so that they refer to the correct SourceLocation and
+ // DeclContext.
+ bool VisitSourceLocExpr(SourceLocExpr *E) {
+ HasImmediateCalls = true;
+ return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
+ }
+
+ // A nested lambda might have parameters with immediate invocations
+ // in their default arguments.
+ // The compound statement is not visited (as it does not constitute a
+ // subexpression).
+ // FIXME: We should consider visiting and transforming captures
+ // with init expressions.
+ bool VisitLambdaExpr(LambdaExpr *E) {
+ return VisitCXXMethodDecl(E->getCallOperator());
+ }
+
+ // Blocks don't support default parameters, and, as for lambdas,
+ // we don't consider their body a subexpression.
+ bool VisitBlockDecl(BlockDecl *B) { return false; }
+
+ bool VisitCompoundStmt(CompoundStmt *B) { return false; }
+
+ bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ return TraverseStmt(E->getExpr());
+ }
+
+ bool VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ return TraverseStmt(E->getExpr());
+ }
+};
+
+struct EnsureImmediateInvocationInDefaultArgs
+ : TreeTransform<EnsureImmediateInvocationInDefaultArgs> {
+ EnsureImmediateInvocationInDefaultArgs(Sema &SemaRef)
+ : TreeTransform(SemaRef) {}
+
+ // Lambda can only have immediate invocations in the default
+ // args of their parameters, which is transformed upon calling the closure.
+ // The body is not a subexpression, so we have nothing to do.
+ // FIXME: Immediate calls in capture initializers should be transformed.
+ ExprResult TransformLambdaExpr(LambdaExpr *E) { return E; }
+ ExprResult TransformBlockExpr(BlockExpr *E) { return E; }
+
+ // Make sure we don't rebuild the this pointer as it would
+ // cause it to incorrectly point it to the outermost class
+ // in the case of nested struct initialization.
+ ExprResult TransformCXXThisExpr(CXXThisExpr *E) { return E; }
+};
+
ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
- FunctionDecl *FD, ParmVarDecl *Param) {
+ FunctionDecl *FD, ParmVarDecl *Param,
+ Expr *Init) {
assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
- if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
+
+ bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
+
+ std::optional<ExpressionEvaluationContextRecord::InitializationContext>
+ InitializationContext =
+ OutermostDeclarationWithDelayedImmediateInvocations();
+ if (!InitializationContext.has_value())
+ InitializationContext.emplace(CallLoc, Param, CurContext);
+
+ if (!Init && !Param->hasUnparsedDefaultArg()) {
+ // Mark that we are replacing a default argument first.
+ // If we are instantiating a template we won't have to
+ // retransform immediate calls.
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
+
+ if (Param->hasUninstantiatedDefaultArg()) {
+ if (InstantiateDefaultArgument(CallLoc, FD, Param))
+ return ExprError();
+ }
+ // CWG2631
+ // An immediate invocation that is not evaluated where it appears is
+ // evaluated and checked for whether it is a constant expression at the
+ // point where the enclosing initializer is used in a function call.
+ ImmediateCallVisitor V;
+ if (!NestedDefaultChecking)
+ V.TraverseDecl(Param);
+ if (V.HasImmediateCalls) {
+ ExprEvalContexts.back().DelayedDefaultInitializationContext = {
+ CallLoc, Param, CurContext};
+ EnsureImmediateInvocationInDefaultArgs Immediate(*this);
+ ExprResult Res = Immediate.TransformInitializer(Param->getInit(),
+ /*NotCopy=*/false);
+ if (Res.isInvalid())
+ return ExprError();
+ Res = ConvertParamDefaultArgument(Param, Res.get(),
+ Res.get()->getBeginLoc());
+ if (Res.isInvalid())
+ return ExprError();
+ Init = Res.get();
+ }
+ }
+
+ if (CheckCXXDefaultArgExpr(
+ CallLoc, FD, Param, Init,
+ /*SkipImmediateInvocations=*/NestedDefaultChecking))
return ExprError();
- return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext);
+
+ return CXXDefaultArgExpr::Create(Context, InitializationContext->Loc, Param,
+ Init, InitializationContext->Context);
+}
+
+ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
+ assert(Field->hasInClassInitializer());
+
+ // If we might have already tried and failed to instantiate, don't try again.
+ if (Field->isInvalidDecl())
+ return ExprError();
+
+ auto *ParentRD = cast<CXXRecordDecl>(Field->getParent());
+
+ std::optional<ExpressionEvaluationContextRecord::InitializationContext>
+ InitializationContext =
+ OutermostDeclarationWithDelayedImmediateInvocations();
+ if (!InitializationContext.has_value())
+ InitializationContext.emplace(Loc, Field, CurContext);
+
+ Expr *Init = nullptr;
+
+ bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
+
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
+
+ if (!Field->getInClassInitializer()) {
+ // Maybe we haven't instantiated the in-class initializer. Go check the
+ // pattern FieldDecl to see if it has one.
+ if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) {
+ CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
+ DeclContext::lookup_result Lookup =
+ ClassPattern->lookup(Field->getDeclName());
+
+ FieldDecl *Pattern = nullptr;
+ for (auto *L : Lookup) {
+ if ((Pattern = dyn_cast<FieldDecl>(L)))
+ break;
+ }
+ assert(Pattern && "We must have set the Pattern!");
+ if (!Pattern->hasInClassInitializer() ||
+ InstantiateInClassInitializer(Loc, Field, Pattern,
+ getTemplateInstantiationArgs(Field))) {
+ Field->setInvalidDecl();
+ return ExprError();
+ }
+ }
+ }
+
+ // CWG2631
+ // An immediate invocation that is not evaluated where it appears is
+ // evaluated and checked for whether it is a constant expression at the
+ // point where the enclosing initializer is used in a [...] a constructor
+ // definition, or an aggregate initialization.
+ ImmediateCallVisitor V;
+ if (!NestedDefaultChecking)
+ V.TraverseDecl(Field);
+ if (V.HasImmediateCalls) {
+ ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
+ CurContext};
+ ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
+ NestedDefaultChecking;
+
+ EnsureImmediateInvocationInDefaultArgs Immediate(*this);
+
+ ExprResult Res =
+ Immediate.TransformInitializer(Field->getInClassInitializer(),
+ /*CXXDirectInit=*/false);
+ if (!Res.isInvalid())
+ Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);
+ if (Res.isInvalid()) {
+ Field->setInvalidDecl();
+ return ExprError();
+ }
+ Init = Res.get();
+ }
+
+ if (Field->getInClassInitializer()) {
+ Expr *E = Init ? Init : Field->getInClassInitializer();
+ if (!NestedDefaultChecking)
+ MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false);
+ // C++11 [class.base.init]p7:
+ // The initialization of each base and member constitutes a
+ // full-expression.
+ ExprResult Res = ActOnFinishFullExpr(E, /*DiscardedValue=*/false);
+ if (Res.isInvalid()) {
+ Field->setInvalidDecl();
+ return ExprError();
+ }
+ Init = Res.get();
+
+ return CXXDefaultInitExpr::Create(Context, InitializationContext->Loc,
+ Field, InitializationContext->Context,
+ Init);
+ }
+
+ // DR1351:
+ // If the brace-or-equal-initializer of a non-static data member
+ // invokes a defaulted default constructor of its class or of an
+ // enclosing class in a potentially evaluated subexpression, the
+ // program is ill-formed.
+ //
+ // This resolution is unworkable: the exception specification of the
+ // default constructor can be needed in an unevaluated context, in
+ // particular, in the operand of a noexcept-expression, and we can be
+ // unable to compute an exception specification for an enclosed class.
+ //
+ // Any attempt to resolve the exception specification of a defaulted default
+ // constructor before the initializer is lexically complete will ultimately
+ // come here at which point we can diagnose it.
+ RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext();
+ Diag(Loc, diag::err_default_member_initializer_not_yet_parsed)
+ << OutermostClass << Field;
+ Diag(Field->getEndLoc(),
+ diag::note_default_member_initializer_not_yet_parsed);
+ // Recover by marking the field invalid, unless we're in a SFINAE context.
+ if (!isSFINAEContext())
+ Field->setInvalidDecl();
+ return ExprError();
}
Sema::VariadicCallType
@@ -6287,9 +6526,10 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc,
return;
}
- Optional<CharUnits> ArgSize =
+ std::optional<CharUnits> ArgSize =
getASTContext().getTypeSizeInCharsIfKnown(ArgCAT);
- Optional<CharUnits> ParmSize = getASTContext().getTypeSizeInCharsIfKnown(CAT);
+ std::optional<CharUnits> ParmSize =
+ getASTContext().getTypeSizeInCharsIfKnown(CAT);
if (ArgSize && ParmSize && *ArgSize < *ParmSize) {
Diag(CallLoc, diag::warn_static_array_too_small)
<< ArgExpr->getSourceRange() << (unsigned)ArgSize->getQuantity()
@@ -6762,8 +7002,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
nullptr, DRE->isNonOdrUse());
}
}
- } else if (isa<MemberExpr>(NakedFn))
- NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
+ } else if (auto *ME = dyn_cast<MemberExpr>(NakedFn))
+ NDecl = ME->getMemberDecl();
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable(
@@ -7035,7 +7275,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
TheCall = dyn_cast<CallExpr>(Result.get());
bool CorrectedTypos = TheCall != TheOldCall;
if (!TheCall) return Result;
- Args = llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs());
+ Args = llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs());
// A new call expression node was created if some typos were corrected.
// However it may not have been constructed with enough storage. In this
@@ -8165,23 +8405,6 @@ static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) {
return true;
}
-/// Handle when one or both operands are void type.
-static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
- ExprResult &RHS) {
- Expr *LHSExpr = LHS.get();
- Expr *RHSExpr = RHS.get();
-
- if (!LHSExpr->getType()->isVoidType())
- S.Diag(RHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void)
- << RHSExpr->getSourceRange();
- if (!RHSExpr->getType()->isVoidType())
- S.Diag(LHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void)
- << LHSExpr->getSourceRange();
- LHS = S.ImpCastExprToType(LHS.get(), S.Context.VoidTy, CK_ToVoid);
- RHS = S.ImpCastExprToType(RHS.get(), S.Context.VoidTy, CK_ToVoid);
- return S.Context.VoidTy;
-}
-
/// Return false if the NullExpr can be promoted to PointerTy,
/// true otherwise.
static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
@@ -8205,7 +8428,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
if (S.Context.hasSameType(LHSTy, RHSTy)) {
// Two identical pointers types are always compatible.
- return LHSTy;
+ return S.Context.getCommonSugaredType(LHSTy, RHSTy);
}
QualType lhptee, rhptee;
@@ -8275,7 +8498,9 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual);
rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual);
- QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee);
+ QualType CompositeTy = S.Context.mergeTypes(
+ lhptee, rhptee, /*OfBlockPointer=*/false, /*Unqualified=*/false,
+ /*BlockReturnType=*/false, /*IsConditionalOperator=*/true);
if (CompositeTy.isNull()) {
// In this situation, we assume void* type. No especially good
@@ -8707,7 +8932,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// And if they're both bfloat (which isn't arithmetic), that's fine too.
if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) {
- return LHSTy;
+ return Context.getCommonSugaredType(LHSTy, RHSTy);
}
// If both operands are the same structure or union type, the result is that
@@ -8717,16 +8942,37 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (LHSRT->getDecl() == RHSRT->getDecl())
// "If both the operands have structure or union type, the result has
// that type." This implies that CV qualifiers are dropped.
- return LHSTy.getUnqualifiedType();
+ return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(),
+ RHSTy.getUnqualifiedType());
// FIXME: Type of conditional expression must be complete in C mode.
}
// C99 6.5.15p5: "If both operands have void type, the result has void type."
// The following || allows only one side to be void (a GCC-ism).
if (LHSTy->isVoidType() || RHSTy->isVoidType()) {
- return checkConditionalVoidType(*this, LHS, RHS);
+ QualType ResTy;
+ if (LHSTy->isVoidType() && RHSTy->isVoidType()) {
+ ResTy = Context.getCommonSugaredType(LHSTy, RHSTy);
+ } else if (RHSTy->isVoidType()) {
+ ResTy = RHSTy;
+ Diag(RHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void)
+ << RHS.get()->getSourceRange();
+ } else {
+ ResTy = LHSTy;
+ Diag(LHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void)
+ << LHS.get()->getSourceRange();
+ }
+ LHS = ImpCastExprToType(LHS.get(), ResTy, CK_ToVoid);
+ RHS = ImpCastExprToType(RHS.get(), ResTy, CK_ToVoid);
+ return ResTy;
}
+ // C2x 6.5.15p7:
+ // ... if both the second and third operands have nullptr_t type, the
+ // result also has that type.
+ if (LHSTy->isNullPtrType() && Context.hasSameType(LHSTy, RHSTy))
+ return ResTy;
+
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
// the type of the other operand."
if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy;
@@ -8763,7 +9009,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// Allow ?: operations in which both operands have the same
// built-in sizeless type.
if (LHSTy->isSizelessBuiltinType() && Context.hasSameType(LHSTy, RHSTy))
- return LHSTy;
+ return Context.getCommonSugaredType(LHSTy, RHSTy);
// Emit a better diagnostic if one of the expressions is a null pointer
// constant and the other is not a pointer type. In this case, the user most
@@ -9061,8 +9307,8 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin,
if (!ResTy->isAnyPointerType())
return ResTy;
- auto GetNullability = [&Ctx](QualType Ty) {
- Optional<NullabilityKind> Kind = Ty->getNullability(Ctx);
+ auto GetNullability = [](QualType Ty) {
+ std::optional<NullabilityKind> Kind = Ty->getNullability();
if (Kind) {
// For our purposes, treat _Nullable_result as _Nullable.
if (*Kind == NullabilityKind::NullableResult)
@@ -9099,7 +9345,7 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin,
return ResTy;
// Strip all nullability from ResTy.
- while (ResTy->getNullability(Ctx))
+ while (ResTy->getNullability())
ResTy = ResTy.getSingleStepDesugaredType(Ctx);
// Create a new AttributedType with the new nullability kind.
@@ -9236,7 +9482,8 @@ static bool IsInvalidCmseNSCallConversion(Sema &S, QualType FromType,
// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
// FIXME: add a couple examples in this comment.
static Sema::AssignConvertType
-checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
+checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
+ SourceLocation Loc) {
assert(LHSType.isCanonical() && "LHS not canonicalized!");
assert(RHSType.isCanonical() && "RHS not canonicalized!");
@@ -9305,6 +9552,13 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
return Sema::FunctionVoidPointer;
}
+ if (!S.Diags.isIgnored(
+ diag::warn_typecheck_convert_incompatible_function_pointer_strict,
+ Loc) &&
+ RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType() &&
+ !S.IsFunctionConversion(RHSType, LHSType, RHSType))
+ return Sema::IncompatibleFunctionPointerStrict;
+
// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
// unqualified versions of compatible types, ...
QualType ltrans = QualType(lhptee, 0), rtrans = QualType(rhptee, 0);
@@ -9656,7 +9910,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
Kind = CK_NoOp;
else
Kind = CK_BitCast;
- return checkPointerTypesForAssignment(*this, LHSType, RHSType);
+ return checkPointerTypesForAssignment(*this, LHSType, RHSType,
+ RHS.get()->getBeginLoc());
}
// int -> T*
@@ -9984,6 +10239,24 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
return Incompatible;
}
+ // This check seems unnatural, however it is necessary to ensure the proper
+ // conversion of functions/arrays. If the conversion were done for all
+ // DeclExpr's (created by ActOnIdExpression), it would mess up the unary
+ // expressions that suppress this implicit conversion (&, sizeof). This needs
+ // to happen before we check for null pointer conversions because C does not
+ // undergo the same implicit conversions as C++ does above (by the calls to
+ // TryImplicitConversion() and PerformImplicitConversion()) which insert the
+ // lvalue to rvalue cast before checking for null pointer constraints. This
+ // addresses code like: nullptr_t val; int *ptr; ptr = val;
+ //
+ // Suppress this for references: C++ 8.5.3p5.
+ if (!LHSType->isReferenceType()) {
+ // FIXME: We potentially allocate here even if ConvertRHS is false.
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose);
+ if (RHS.isInvalid())
+ return Incompatible;
+ }
+
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
if ((LHSType->isPointerType() || LHSType->isObjCObjectPointerType() ||
@@ -10008,18 +10281,6 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
return Compatible;
}
- // This check seems unnatural, however it is necessary to ensure the proper
- // conversion of functions/arrays. If the conversion were done for all
- // DeclExpr's (created by ActOnIdExpression), it would mess up the unary
- // expressions that suppress this implicit conversion (&, sizeof).
- //
- // Suppress this for references: C++ 8.5.3p5.
- if (!LHSType->isReferenceType()) {
- // FIXME: We potentially allocate here even if ConvertRHS is false.
- RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose);
- if (RHS.isInvalid())
- return Incompatible;
- }
CastKind Kind;
Sema::AssignConvertType result =
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
@@ -10434,7 +10695,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
// If the vector types are identical, return.
if (Context.hasSameType(LHSType, RHSType))
- return LHSType;
+ return Context.getCommonSugaredType(LHSType, RHSType);
// If we have compatible AltiVec and GCC vector types, use the AltiVec type.
if (LHSVecType && RHSVecType &&
@@ -11249,7 +11510,7 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS,
QualType LHSTy = Context.isPromotableBitField(LHS.get());
if (LHSTy.isNull()) {
LHSTy = LHS.get()->getType();
- if (LHSTy->isPromotableIntegerType())
+ if (Context.isPromotableIntegerType(LHSTy))
LHSTy = Context.getPromotedIntegerType(LHSTy);
}
*CompLHSTy = LHSTy;
@@ -12268,7 +12529,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
// We can't use `CK_IntegralCast` when the underlying type is 'bool', so we
// promote the boolean type, and all other promotable integer types, to
// avoid this.
- if (IntType->isPromotableIntegerType())
+ if (S.Context.isPromotableIntegerType(IntType))
IntType = S.Context.getPromotedIntegerType(IntType);
LHS = S.ImpCastExprToType(LHS.get(), IntType, CK_IntegralCast);
@@ -12285,7 +12546,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
if (Type.isNull())
return S.InvalidOperands(Loc, LHS, RHS);
- Optional<ComparisonCategoryType> CCT =
+ std::optional<ComparisonCategoryType> CCT =
getComparisonCategoryForBuiltinCmp(Type);
if (!CCT)
return S.InvalidOperands(Loc, LHS, RHS);
@@ -12429,7 +12690,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
QualType CompositeTy = LHS.get()->getType();
assert(!CompositeTy->isReferenceType());
- Optional<ComparisonCategoryType> CCT =
+ std::optional<ComparisonCategoryType> CCT =
getComparisonCategoryForBuiltinCmp(CompositeTy);
if (!CCT)
return InvalidOperands(Loc, LHS, RHS);
@@ -12574,34 +12835,54 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
return computeResultTy();
}
- if (getLangOpts().CPlusPlus) {
- // C++ [expr.eq]p4:
- // Two operands of type std::nullptr_t or one operand of type
- // std::nullptr_t and the other a null pointer constant compare equal.
- if (!IsOrdered && LHSIsNull && RHSIsNull) {
- if (LHSType->isNullPtrType()) {
- RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
- return computeResultTy();
- }
- if (RHSType->isNullPtrType()) {
- LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
- return computeResultTy();
- }
- }
- // Comparison of Objective-C pointers and block pointers against nullptr_t.
- // These aren't covered by the composite pointer type rules.
- if (!IsOrdered && RHSType->isNullPtrType() &&
- (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
+ // C++ [expr.eq]p4:
+ // Two operands of type std::nullptr_t or one operand of type
+ // std::nullptr_t and the other a null pointer constant compare
+ // equal.
+ // C2x 6.5.9p5:
+ // If both operands have type nullptr_t or one operand has type nullptr_t
+ // and the other is a null pointer constant, they compare equal.
+ if (!IsOrdered && LHSIsNull && RHSIsNull) {
+ if (LHSType->isNullPtrType()) {
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
return computeResultTy();
}
- if (!IsOrdered && LHSType->isNullPtrType() &&
- (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
+ if (RHSType->isNullPtrType()) {
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
return computeResultTy();
}
+ }
+
+ if (!getLangOpts().CPlusPlus && !IsOrdered && (LHSIsNull || RHSIsNull)) {
+ // C2x 6.5.9p6:
+ // Otherwise, at least one operand is a pointer. If one is a pointer and
+ // the other is a null pointer constant, the null pointer constant is
+ // converted to the type of the pointer.
+ if (LHSIsNull && RHSType->isPointerType()) {
+ LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
+ return computeResultTy();
+ }
+ if (RHSIsNull && LHSType->isPointerType()) {
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
+ return computeResultTy();
+ }
+ }
+
+ // Comparison of Objective-C pointers and block pointers against nullptr_t.
+ // These aren't covered by the composite pointer type rules.
+ if (!IsOrdered && RHSType->isNullPtrType() &&
+ (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) {
+ RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
+ return computeResultTy();
+ }
+ if (!IsOrdered && LHSType->isNullPtrType() &&
+ (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) {
+ LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer);
+ return computeResultTy();
+ }
+ if (getLangOpts().CPlusPlus) {
if (IsRelational &&
((LHSType->isNullPtrType() && RHSType->isPointerType()) ||
(RHSType->isNullPtrType() && LHSType->isPointerType()))) {
@@ -13152,7 +13433,7 @@ QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix");
if (Context.hasSameType(LHSType, RHSType))
- return LHSType;
+ return Context.getCommonSugaredType(LHSType, RHSType);
// Type conversion may change LHS/RHS. Keep copies to the original results, in
// case we have to return InvalidOperands.
@@ -13196,13 +13477,19 @@ QualType Sema::CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS,
if (LHSMatType->getNumColumns() != RHSMatType->getNumRows())
return InvalidOperands(Loc, LHS, RHS);
- if (!Context.hasSameType(LHSMatType->getElementType(),
- RHSMatType->getElementType()))
+ if (Context.hasSameType(LHSMatType, RHSMatType))
+ return Context.getCommonSugaredType(
+ LHS.get()->getType().getUnqualifiedType(),
+ RHS.get()->getType().getUnqualifiedType());
+
+ QualType LHSELTy = LHSMatType->getElementType(),
+ RHSELTy = RHSMatType->getElementType();
+ if (!Context.hasSameType(LHSELTy, RHSELTy))
return InvalidOperands(Loc, LHS, RHS);
- return Context.getConstantMatrixType(LHSMatType->getElementType(),
- LHSMatType->getNumRows(),
- RHSMatType->getNumColumns());
+ return Context.getConstantMatrixType(
+ Context.getCommonSugaredType(LHSELTy, RHSELTy),
+ LHSMatType->getNumRows(), RHSMatType->getNumColumns());
}
return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign);
}
@@ -13937,19 +14224,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// type is deprecated unless the assignment is either a discarded-value
// expression or an unevaluated operand
ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
- } else {
- // C++20 [expr.ass]p6:
- // [Compound-assignment] expressions are deprecated if E1 has
- // volatile-qualified type and op is not one of the bitwise
- // operators |, &, ˆ.
- switch (Opc) {
- case BO_OrAssign:
- case BO_AndAssign:
- case BO_XorAssign:
- break;
- default:
- Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
- }
}
}
@@ -13964,8 +14238,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
return getLangOpts().CPlusPlus ? LHSType : LHSType.getAtomicUnqualifiedType();
}
-// Only ignore explicit casts to void.
-static bool IgnoreCommaOperand(const Expr *E) {
+// Scenarios to ignore if expression E is:
+// 1. an explicit cast expression into void
+// 2. a function call expression that returns void
+static bool IgnoreCommaOperand(const Expr *E, const ASTContext &Context) {
E = E->IgnoreParens();
if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
@@ -13980,6 +14256,8 @@ static bool IgnoreCommaOperand(const Expr *E) {
}
}
+ if (const auto *CE = dyn_cast<CallExpr>(E))
+ return CE->getCallReturnType(Context)->isVoidType();
return false;
}
@@ -14021,7 +14299,7 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) {
}
// Only allow some expressions on LHS to not warn.
- if (IgnoreCommaOperand(LHS))
+ if (IgnoreCommaOperand(LHS, Context))
return;
Diag(Loc, diag::warn_comma_operator);
@@ -14486,7 +14764,8 @@ static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) {
/// CheckIndirectionOperand - Type check unary indirection (prefix '*').
static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
- SourceLocation OpLoc) {
+ SourceLocation OpLoc,
+ bool IsAfterAmp = false) {
if (Op->isTypeDependent())
return S.Context.DependentTy;
@@ -14523,18 +14802,18 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
return QualType();
}
- // Note that per both C89 and C99, indirection is always legal, even if Result
- // is an incomplete type or void. It would be possible to warn about
- // dereferencing a void pointer, but it's completely well-defined, and such a
- // warning is unlikely to catch any mistakes. In C++, indirection is not valid
- // for pointers to 'void' but is fine for any other pointer type:
- //
- // C++ [expr.unary.op]p1:
- // [...] the expression to which [the unary * operator] is applied shall
- // be a pointer to an object type, or a pointer to a function type
- if (S.getLangOpts().CPlusPlus && Result->isVoidType())
- S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer)
- << OpTy << Op->getSourceRange();
+ if (Result->isVoidType()) {
+ // C++ [expr.unary.op]p1:
+ // [...] the expression to which [the unary * operator] is applied shall
+ // be a pointer to an object type, or a pointer to a function type
+ LangOptions LO = S.getLangOpts();
+ if (LO.CPlusPlus)
+ S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer_cpp)
+ << OpTy << Op->getSourceRange();
+ else if (!(LO.C99 && IsAfterAmp) && !S.isUnevaluatedContext())
+ S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer)
+ << OpTy << Op->getSourceRange();
+ }
// Dereferences are usually l-values...
VK = VK_LValue;
@@ -14968,7 +15247,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
break;
case BO_And:
checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case BO_Xor:
case BO_Or:
ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
@@ -15020,7 +15299,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
case BO_AndAssign:
case BO_OrAssign: // fallthrough
DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case BO_XorAssign:
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
CompLHSTy = CompResultTy;
@@ -15163,38 +15442,21 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc,
Bop->getSourceRange());
}
-/// Returns true if the given expression can be evaluated as a constant
-/// 'true'.
-static bool EvaluatesAsTrue(Sema &S, Expr *E) {
- bool Res;
- return !E->isValueDependent() &&
- E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res;
-}
-
-/// Returns true if the given expression can be evaluated as a constant
-/// 'false'.
-static bool EvaluatesAsFalse(Sema &S, Expr *E) {
- bool Res;
- return !E->isValueDependent() &&
- E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res;
-}
-
/// Look for '&&' in the left hand of a '||' expr.
static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc,
Expr *LHSExpr, Expr *RHSExpr) {
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(LHSExpr)) {
if (Bop->getOpcode() == BO_LAnd) {
- // If it's "a && b || 0" don't warn since the precedence doesn't matter.
- if (EvaluatesAsFalse(S, RHSExpr))
- return;
- // If it's "1 && a || b" don't warn since the precedence doesn't matter.
- if (!EvaluatesAsTrue(S, Bop->getLHS()))
+ // If it's "string_literal && a || b" don't warn since the precedence
+ // doesn't matter.
+ if (!isa<StringLiteral>(Bop->getLHS()->IgnoreParenImpCasts()))
return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop);
} else if (Bop->getOpcode() == BO_LOr) {
if (BinaryOperator *RBop = dyn_cast<BinaryOperator>(Bop->getRHS())) {
- // If it's "a || b && 1 || c" we didn't warn earlier for
- // "a || b && 1", but warn now.
- if (RBop->getOpcode() == BO_LAnd && EvaluatesAsTrue(S, RBop->getRHS()))
+ // If it's "a || b && string_literal || c" we didn't warn earlier for
+ // "a || b && string_literal", but warn now.
+ if (RBop->getOpcode() == BO_LAnd &&
+ isa<StringLiteral>(RBop->getRHS()->IgnoreParenImpCasts()))
return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, RBop);
}
}
@@ -15206,11 +15468,9 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc,
Expr *LHSExpr, Expr *RHSExpr) {
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) {
if (Bop->getOpcode() == BO_LAnd) {
- // If it's "0 || a && b" don't warn since the precedence doesn't matter.
- if (EvaluatesAsFalse(S, LHSExpr))
- return;
- // If it's "a || b && 1" don't warn since the precedence doesn't matter.
- if (!EvaluatesAsTrue(S, Bop->getRHS()))
+ // If it's "a || b && string_literal" don't warn since the precedence
+ // doesn't matter.
+ if (!isa<StringLiteral>(Bop->getRHS()->IgnoreParenImpCasts()))
return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop);
}
}
@@ -15516,15 +15776,15 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {
if (T.isNull() || T->isDependentType())
return false;
- if (!T->isPromotableIntegerType())
+ if (!Ctx.isPromotableIntegerType(T))
return true;
return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy);
}
ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
- UnaryOperatorKind Opc,
- Expr *InputExpr) {
+ UnaryOperatorKind Opc, Expr *InputExpr,
+ bool IsAfterAmp) {
ExprResult Input = InputExpr;
ExprValueKind VK = VK_PRValue;
ExprObjectKind OK = OK_Ordinary;
@@ -15546,7 +15806,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
}
}
- if (getLangOpts().HLSL) {
+ if (getLangOpts().HLSL && OpLoc.isValid()) {
if (Opc == UO_AddrOf)
return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 0);
if (Opc == UO_Deref)
@@ -15574,7 +15834,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Deref: {
Input = DefaultFunctionArrayLvalueConversion(Input.get());
if (Input.isInvalid()) return ExprError();
- resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc);
+ resultType =
+ CheckIndirectionOperand(*this, Input.get(), VK, OpLoc, IsAfterAmp);
break;
}
case UO_Plus:
@@ -15603,6 +15864,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType->castAs<VectorType>()->getVectorKind() !=
VectorType::AltiVecBool))
break;
+ else if (resultType->isVLSTBuiltinType()) // SVE vectors allow + and -
+ break;
else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
Opc == UO_Plus &&
resultType->isPointerType())
@@ -15792,7 +16055,8 @@ bool Sema::isQualifiedMemberAccess(Expr *E) {
}
ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
- UnaryOperatorKind Opc, Expr *Input) {
+ UnaryOperatorKind Opc, Expr *Input,
+ bool IsAfterAmp) {
// First things first: handle placeholders so that the
// overloaded-operator check considers the right type.
if (const BuiltinType *pty = Input->getType()->getAsPlaceholderType()) {
@@ -15831,13 +16095,14 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc,
return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, Input);
}
- return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
+ return CreateBuiltinUnaryOp(OpLoc, Opc, Input, IsAfterAmp);
}
// Unary Operators. 'Tok' is the token for the operator.
-ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
- tok::TokenKind Op, Expr *Input) {
- return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input);
+ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op,
+ Expr *Input, bool IsAfterAmp) {
+ return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input,
+ IsAfterAmp);
}
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
@@ -15845,8 +16110,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
LabelDecl *TheDecl) {
TheDecl->markUsed(Context);
// Create the AST node. The address of a label always has type 'void*'.
- return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
- Context.getPointerType(Context.VoidTy));
+ auto *Res = new (Context) AddrLabelExpr(
+ OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy));
+
+ if (getCurFunction())
+ getCurFunction()->AddrLabels.push_back(Res);
+
+ return Res;
}
void Sema::ActOnStartStmtExpr() {
@@ -16203,7 +16473,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = false;
EPI.TypeQuals.addConst();
- T = Context.getFunctionType(Context.DependentTy, None, EPI);
+ T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI);
Sig = Context.getTrivialTypeSourceInfo(T);
}
@@ -16290,7 +16560,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
// Put the parameter variables in scope.
- for (auto AI : CurBlock->TheDecl->parameters()) {
+ for (auto *AI : CurBlock->TheDecl->parameters()) {
AI->setOwningFunction(CurBlock->TheDecl);
// If this has an identifier, add it to the scope stack.
@@ -16353,10 +16623,10 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (isa<FunctionNoProtoType>(FTy)) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy, None, EPI);
+ BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI);
- // Otherwise, if we don't need to change anything about the function type,
- // preserve its sugar structure.
+ // Otherwise, if we don't need to change anything about the function type,
+ // preserve its sugar structure.
} else if (FTy->getReturnType() == RetTy &&
(!NoReturn || FTy->getNoReturnAttr())) {
BlockTy = BSI->FunctionType;
@@ -16374,7 +16644,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
} else {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
- BlockTy = Context.getFunctionType(RetTy, None, EPI);
+ BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI);
}
DiagnoseUnusedParameters(BD->parameters());
@@ -16409,8 +16679,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
for (Capture &Cap : BSI->Captures) {
if (Cap.isInvalid() || Cap.isThisCapture())
continue;
-
- VarDecl *Var = Cap.getVariable();
+ // Cap.getVariable() is always a VarDecl because
+ // blocks cannot capture structured bindings or other ValueDecl kinds.
+ auto *Var = cast<VarDecl>(Cap.getVariable());
Expr *CopyExpr = nullptr;
if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) {
if (const RecordType *Record =
@@ -16603,7 +16874,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
// Check for va_arg where arguments of the given type will be promoted
// (i.e. this va_arg is guaranteed to have undefined behavior).
QualType PromoteType;
- if (TInfo->getType()->isPromotableIntegerType()) {
+ if (Context.isPromotableIntegerType(TInfo->getType())) {
PromoteType = Context.getPromotedIntegerType(TInfo->getType());
// [cstdarg.syn]p1 defers the C++ behavior to what the C standard says,
// and C2x 7.16.1.1p2 says, in part:
@@ -16664,7 +16935,7 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
// The type of __null will be int or long, depending on the size of
// pointers on the target.
QualType Ty;
- unsigned pw = Context.getTargetInfo().getPointerWidth(0);
+ unsigned pw = Context.getTargetInfo().getPointerWidth(LangAS::Default);
if (pw == Context.getTargetInfo().getIntWidth())
Ty = Context.IntTy;
else if (pw == Context.getTargetInfo().getLongWidth())
@@ -16902,6 +17173,12 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
MayHaveConvFixit = true;
break;
+ case IncompatibleFunctionPointerStrict:
+ DiagKind =
+ diag::warn_typecheck_convert_incompatible_function_pointer_strict;
+ ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
+ MayHaveConvFixit = true;
+ break;
case IncompatibleFunctionPointer:
if (getLangOpts().CPlusPlus) {
DiagKind = diag::err_typecheck_convert_incompatible_function_pointer;
@@ -17492,6 +17769,7 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) {
ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
if (isUnevaluatedContext() || !E.isUsable() || !Decl ||
!Decl->isConsteval() || isConstantEvaluated() ||
+ isCheckingDefaultArgumentOrInitializer() ||
RebuildingImmediateInvocation || isImmediateFunctionContext())
return E;
@@ -17537,8 +17815,14 @@ static void EvaluateAndDiagnoseImmediateInvocation(
FD = Call->getConstructor();
else
llvm_unreachable("unhandled decl kind");
- assert(FD->isConsteval());
+ assert(FD && FD->isConsteval());
SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD;
+ if (auto Context =
+ SemaRef.InnermostDeclarationWithDelayedImmediateInvocations()) {
+ SemaRef.Diag(Context->Loc, diag::note_invalid_consteval_initializer)
+ << Context->Decl;
+ SemaRef.Diag(Context->Decl->getBeginLoc(), diag::note_declared_at);
+ }
for (auto &Note : Notes)
SemaRef.Diag(Note.first, Note.second);
return;
@@ -17598,6 +17882,11 @@ static void RemoveNestedImmediateInvocation(
DRSet.erase(E);
return E;
}
+ ExprResult TransformLambdaExpr(LambdaExpr *E) {
+ // Do not rebuild lambdas to avoid creating a new type.
+ // Lambdas have already been processed inside their eval context.
+ return E;
+ }
bool AlwaysRebuild() { return false; }
bool ReplacingOriginal() { return true; }
bool AllowSkippingCXXConstructExpr() {
@@ -17619,9 +17908,13 @@ static void RemoveNestedImmediateInvocation(
Transformer.AllowSkippingFirstCXXConstructExpr = false;
ExprResult Res = Transformer.TransformExpr(It->getPointer()->getSubExpr());
- assert(Res.isUsable());
- Res = SemaRef.MaybeCreateExprWithCleanups(Res);
- It->getPointer()->setSubExpr(Res.get());
+ // The result may not be usable in case of previous compilation errors.
+ // In this case evaluation of the expression may result in crash so just
+ // don't do anything further with the result.
+ if (Res.isUsable()) {
+ Res = SemaRef.MaybeCreateExprWithCleanups(Res);
+ It->getPointer()->setSubExpr(Res.get());
+ }
}
static void
@@ -17639,7 +17932,7 @@ HandleImmediateInvocations(Sema &SemaRef,
/// Prevent sema calls during the tree transform from adding pointers that
/// are already in the sets.
- llvm::SaveAndRestore<bool> DisableIITracking(
+ llvm::SaveAndRestore DisableIITracking(
SemaRef.RebuildingImmediateInvocation, true);
/// Prevent diagnostic during tree transfrom as they are duplicates
@@ -17665,7 +17958,7 @@ HandleImmediateInvocations(Sema &SemaRef,
for (auto CE : Rec.ImmediateInvocationCandidates)
if (!CE.getInt())
EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
- for (auto DR : Rec.ReferenceToConsteval) {
+ for (auto *DR : Rec.ReferenceToConsteval) {
auto *FD = cast<FunctionDecl>(DR->getDecl());
SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
<< FD;
@@ -18106,7 +18399,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
}
} else {
// Walk redefinitions, as some of them may be instantiable.
- for (auto i : Func->redecls()) {
+ for (auto *i : Func->redecls()) {
if (!i->isUsed(false) && i->isImplicitlyInstantiable())
MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
@@ -18114,6 +18407,16 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
});
}
+ // If a constructor was defined in the context of a default parameter
+ // or of another default member initializer (ie a PotentiallyEvaluatedIfUsed
+ // context), its initializers may not be referenced yet.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
+ for (CXXCtorInitializer *Init : Constructor->inits()) {
+ if (Init->isInClassMemberInitializer())
+ MarkDeclarationsReferencedInExpr(Init->getInit());
+ }
+ }
+
// C++14 [except.spec]p17:
// An exception-specification is considered to be needed when:
// - the function is odr-used or, if it appears in an unevaluated operand,
@@ -18173,10 +18476,13 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
/// - else capture it in the DeclContext that maps to the
/// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack.
static void
-MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
+MarkVarDeclODRUsed(ValueDecl *V, SourceLocation Loc, Sema &SemaRef,
const unsigned *const FunctionScopeIndexToStopAt = nullptr) {
// Keep track of used but undefined variables.
// FIXME: We shouldn't suppress this warning for static data members.
+ VarDecl *Var = V->getPotentiallyDecomposedVarDecl();
+ assert(Var && "expected a capturable variable");
+
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
(!Var->isExternallyVisible() || Var->isInline() ||
SemaRef.isExternalWithNoLinkageType(Var)) &&
@@ -18187,12 +18493,11 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
}
QualType CaptureType, DeclRefType;
if (SemaRef.LangOpts.OpenMP)
- SemaRef.tryCaptureOpenMPLambdas(Var);
- SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit,
- /*EllipsisLoc*/ SourceLocation(),
- /*BuildAndDiagnose*/ true,
- CaptureType, DeclRefType,
- FunctionScopeIndexToStopAt);
+ SemaRef.tryCaptureOpenMPLambdas(V);
+ SemaRef.tryCaptureVariable(V, Loc, Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ true, CaptureType,
+ DeclRefType, FunctionScopeIndexToStopAt);
if (SemaRef.LangOpts.CUDA && Var->hasGlobalStorage()) {
auto *FD = dyn_cast_or_null<FunctionDecl>(SemaRef.CurContext);
@@ -18232,17 +18537,17 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef,
}
}
- Var->markUsed(SemaRef.Context);
+ V->markUsed(SemaRef.Context);
}
-void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture,
+void Sema::MarkCaptureUsedInEnclosingContext(ValueDecl *Capture,
SourceLocation Loc,
unsigned CapturingScopeIndex) {
MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex);
}
-static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
- ValueDecl *var) {
+void diagnoseUncapturableValueReferenceOrBinding(Sema &S, SourceLocation loc,
+ ValueDecl *var) {
DeclContext *VarDC = var->getDeclContext();
// If the parameter still belongs to the translation unit, then
@@ -18282,12 +18587,12 @@ static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc,
// capture.
}
-
-static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var,
- bool &SubCapturesAreNested,
- QualType &CaptureType,
- QualType &DeclRefType) {
- // Check whether we've already captured it.
+static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI,
+ ValueDecl *Var,
+ bool &SubCapturesAreNested,
+ QualType &CaptureType,
+ QualType &DeclRefType) {
+ // Check whether we've already captured it.
if (CSI->CaptureMap.count(Var)) {
// If we found a capture, any subcaptures are nested.
SubCapturesAreNested = true;
@@ -18314,14 +18619,18 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec
// Only block literals, captured statements, and lambda expressions can
// capture; other scopes don't work.
-static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var,
- SourceLocation Loc,
- const bool Diagnose, Sema &S) {
+static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC,
+ ValueDecl *Var,
+ SourceLocation Loc,
+ const bool Diagnose,
+ Sema &S) {
if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC))
return getLambdaAwareParentOfDeclContext(DC);
- else if (Var->hasLocalStorage()) {
- if (Diagnose)
- diagnoseUncapturableValueReference(S, Loc, Var);
+
+ VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl();
+ if (Underlying) {
+ if (Underlying->hasLocalStorage() && Diagnose)
+ diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var);
}
return nullptr;
}
@@ -18329,9 +18638,12 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *
// Certain capturing entities (lambdas, blocks etc.) are not allowed to capture
// certain types of variables (unnamed, variably modified types etc.)
// so check for eligibility.
-static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
- SourceLocation Loc,
- const bool Diagnose, Sema &S) {
+static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var,
+ SourceLocation Loc, const bool Diagnose,
+ Sema &S) {
+
+ assert((isa<VarDecl, BindingDecl>(Var)) &&
+ "Only variables and structured bindings can be captured");
bool IsBlock = isa<BlockScopeInfo>(CSI);
bool IsLambda = isa<LambdaScopeInfo>(CSI);
@@ -18388,17 +18700,28 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
return false;
}
+ if (isa<BindingDecl>(Var)) {
+ if (!IsLambda || !S.getLangOpts().CPlusPlus) {
+ if (Diagnose)
+ diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var);
+ return false;
+ } else if (Diagnose && S.getLangOpts().CPlusPlus) {
+ S.Diag(Loc, S.LangOpts.CPlusPlus20
+ ? diag::warn_cxx17_compat_capture_binding
+ : diag::ext_capture_binding)
+ << Var;
+ S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
+ }
+ }
+
return true;
}
// Returns true if the capture by block was successful.
-static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
- SourceLocation Loc,
- const bool BuildAndDiagnose,
- QualType &CaptureType,
- QualType &DeclRefType,
- const bool Nested,
- Sema &S, bool Invalid) {
+static bool captureInBlock(BlockScopeInfo *BSI, ValueDecl *Var,
+ SourceLocation Loc, const bool BuildAndDiagnose,
+ QualType &CaptureType, QualType &DeclRefType,
+ const bool Nested, Sema &S, bool Invalid) {
bool ByRef = false;
// Blocks are not allowed to capture arrays, excepting OpenCL.
@@ -18462,10 +18785,9 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
return !Invalid;
}
-
/// Capture the given variable in the captured region.
static bool captureInCapturedRegion(
- CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc,
+ CapturedRegionScopeInfo *RSI, ValueDecl *Var, SourceLocation Loc,
const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType,
const bool RefersToCapturedVariable, Sema::TryCaptureKind Kind,
bool IsTopScope, Sema &S, bool Invalid) {
@@ -18504,16 +18826,12 @@ static bool captureInCapturedRegion(
}
/// Capture the given variable in the lambda.
-static bool captureInLambda(LambdaScopeInfo *LSI,
- VarDecl *Var,
- SourceLocation Loc,
- const bool BuildAndDiagnose,
- QualType &CaptureType,
- QualType &DeclRefType,
+static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var,
+ SourceLocation Loc, const bool BuildAndDiagnose,
+ QualType &CaptureType, QualType &DeclRefType,
const bool RefersToCapturedVariable,
const Sema::TryCaptureKind Kind,
- SourceLocation EllipsisLoc,
- const bool IsTopScope,
+ SourceLocation EllipsisLoc, const bool IsTopScope,
Sema &S, bool Invalid) {
// Determine whether we are capturing by reference or by value.
bool ByRef = false;
@@ -18523,6 +18841,16 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref);
}
+ BindingDecl *BD = dyn_cast<BindingDecl>(Var);
+ // FIXME: We should support capturing structured bindings in OpenMP.
+ if (!Invalid && BD && S.LangOpts.OpenMP) {
+ if (BuildAndDiagnose) {
+ S.Diag(Loc, diag::err_capture_binding_openmp) << Var;
+ S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var;
+ }
+ Invalid = true;
+ }
+
// Compute the type of the field that will capture this variable.
if (ByRef) {
// C++11 [expr.prim.lambda]p15:
@@ -18603,7 +18931,8 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
return !Invalid;
}
-static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) {
+static bool canCaptureVariableByCopy(ValueDecl *Var,
+ const ASTContext &Context) {
// Offer a Copy fix even if the type is dependent.
if (Var->getType()->isDependentType())
return true;
@@ -18629,7 +18958,7 @@ static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) {
/// standard, for example we can't emit a default copy capture fix-it if we
/// already explicitly copy capture capture another variable.
static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
- VarDecl *Var) {
+ ValueDecl *Var) {
assert(LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None);
// Don't offer Capture by copy of default capture by copy fixes if Var is
// known not to be copy constructible.
@@ -18705,14 +19034,20 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI,
}
bool Sema::tryCaptureVariable(
- VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
+ ValueDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind,
SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType,
QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) {
// An init-capture is notionally from the context surrounding its
// declaration, but its parent DC is the lambda class.
DeclContext *VarDC = Var->getDeclContext();
- if (Var->isInitCapture())
- VarDC = VarDC->getParent();
+ const auto *VD = dyn_cast<VarDecl>(Var);
+ if (VD) {
+ if (VD->isInitCapture())
+ VarDC = VarDC->getParent();
+ } else {
+ VD = Var->getPotentiallyDecomposedVarDecl();
+ }
+ assert(VD && "Cannot capture a null variable");
DeclContext *DC = CurContext;
const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt
@@ -18734,12 +19069,14 @@ bool Sema::tryCaptureVariable(
// Capture global variables if it is required to use private copy of this
// variable.
- bool IsGlobal = !Var->hasLocalStorage();
+ bool IsGlobal = !VD->hasLocalStorage();
if (IsGlobal &&
!(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true,
MaxFunctionScopesIndex)))
return true;
- Var = Var->getCanonicalDecl();
+
+ if (isa<VarDecl>(Var))
+ Var = cast<VarDecl>(Var->getCanonicalDecl());
// Walk up the stack to determine whether we can capture the variable,
// performing the "simple" checks that don't depend on type. We stop when
@@ -18795,7 +19132,7 @@ bool Sema::tryCaptureVariable(
Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl);
buildLambdaCaptureFixit(*this, LSI, Var);
} else
- diagnoseUncapturableValueReference(*this, ExprLoc, Var);
+ diagnoseUncapturableValueReferenceOrBinding(*this, ExprLoc, Var);
}
return true;
}
@@ -18943,7 +19280,7 @@ bool Sema::tryCaptureVariable(
return Invalid;
}
-bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
+bool Sema::tryCaptureVariable(ValueDecl *Var, SourceLocation Loc,
TryCaptureKind Kind, SourceLocation EllipsisLoc) {
QualType CaptureType;
QualType DeclRefType;
@@ -18952,7 +19289,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
DeclRefType, nullptr);
}
-bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
+bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) {
QualType CaptureType;
QualType DeclRefType;
return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(),
@@ -18960,7 +19297,7 @@ bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) {
DeclRefType, nullptr);
}
-QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
+QualType Sema::getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc) {
QualType CaptureType;
QualType DeclRefType;
@@ -19382,6 +19719,38 @@ void Sema::CleanupVarDeclMarking() {
"MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?");
}
+static void DoMarkPotentialCapture(Sema &SemaRef, SourceLocation Loc,
+ ValueDecl *Var, Expr *E) {
+ VarDecl *VD = Var->getPotentiallyDecomposedVarDecl();
+ if (!VD)
+ return;
+
+ const bool RefersToEnclosingScope =
+ (SemaRef.CurContext != VD->getDeclContext() &&
+ VD->getDeclContext()->isFunctionOrMethod() && VD->hasLocalStorage());
+ if (RefersToEnclosingScope) {
+ LambdaScopeInfo *const LSI =
+ SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true);
+ if (LSI && (!LSI->CallOperator ||
+ !LSI->CallOperator->Encloses(Var->getDeclContext()))) {
+ // If a variable could potentially be odr-used, defer marking it so
+ // until we finish analyzing the full expression for any
+ // lvalue-to-rvalue
+ // or discarded value conversions that would obviate odr-use.
+ // Add it to the list of potential captures that will be analyzed
+ // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
+ // unless the variable is a reference that was initialized by a constant
+ // expression (this will never need to be captured or odr-used).
+ //
+ // FIXME: We can simplify this a lot after implementing P0588R1.
+ assert(E && "Capture variable should be used in an expression.");
+ if (!Var->getType()->isReferenceType() ||
+ !VD->isUsableInConstantExpressions(SemaRef.Context))
+ LSI->addPotentialCapture(E->IgnoreParens());
+ }
+ }
+}
+
static void DoMarkVarDeclReferenced(
Sema &SemaRef, SourceLocation Loc, VarDecl *Var, Expr *E,
llvm::DenseMap<const VarDecl *, int> &RefsMinusAssignments) {
@@ -19505,7 +19874,10 @@ static void DoMarkVarDeclReferenced(
switch (OdrUse) {
case OdrUseContext::None:
- assert((!E || isa<FunctionParmPackExpr>(E)) &&
+ // In some cases, a variable may not have been marked unevaluated, if it
+ // appears in a defaukt initializer.
+ assert((!E || isa<FunctionParmPackExpr>(E) ||
+ SemaRef.isUnevaluatedContext()) &&
"missing non-odr-use marking for unevaluated decl ref");
break;
@@ -19528,34 +19900,31 @@ static void DoMarkVarDeclReferenced(
// odr-used, but we may still need to track them for lambda capture.
// FIXME: Do we also need to do this inside dependent typeid expressions
// (which are modeled as unevaluated at this point)?
- const bool RefersToEnclosingScope =
- (SemaRef.CurContext != Var->getDeclContext() &&
- Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
- if (RefersToEnclosingScope) {
- LambdaScopeInfo *const LSI =
- SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true);
- if (LSI && (!LSI->CallOperator ||
- !LSI->CallOperator->Encloses(Var->getDeclContext()))) {
- // If a variable could potentially be odr-used, defer marking it so
- // until we finish analyzing the full expression for any
- // lvalue-to-rvalue
- // or discarded value conversions that would obviate odr-use.
- // Add it to the list of potential captures that will be analyzed
- // later (ActOnFinishFullExpr) for eventual capture and odr-use marking
- // unless the variable is a reference that was initialized by a constant
- // expression (this will never need to be captured or odr-used).
- //
- // FIXME: We can simplify this a lot after implementing P0588R1.
- assert(E && "Capture variable should be used in an expression.");
- if (!Var->getType()->isReferenceType() ||
- !Var->isUsableInConstantExpressions(SemaRef.Context))
- LSI->addPotentialCapture(E->IgnoreParens());
- }
- }
+ DoMarkPotentialCapture(SemaRef, Loc, Var, E);
break;
}
}
+static void DoMarkBindingDeclReferenced(Sema &SemaRef, SourceLocation Loc,
+ BindingDecl *BD, Expr *E) {
+ BD->setReferenced();
+
+ if (BD->isInvalidDecl())
+ return;
+
+ OdrUseContext OdrUse = isOdrUseContext(SemaRef);
+ if (OdrUse == OdrUseContext::Used) {
+ QualType CaptureType, DeclRefType;
+ SemaRef.tryCaptureVariable(BD, Loc, Sema::TryCapture_Implicit,
+ /*EllipsisLoc*/ SourceLocation(),
+ /*BuildAndDiagnose*/ true, CaptureType,
+ DeclRefType,
+ /*FunctionScopeIndexToStopAt*/ nullptr);
+ } else if (OdrUse == OdrUseContext::Dependent) {
+ DoMarkPotentialCapture(SemaRef, Loc, BD, E);
+ }
+}
+
/// Mark a variable referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be
/// used directly for normal expressions referring to VarDecl.
@@ -19575,6 +19944,11 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E,
return;
}
+ if (BindingDecl *Decl = dyn_cast<BindingDecl>(D)) {
+ DoMarkBindingDeclReferenced(SemaRef, Loc, Decl, E);
+ return;
+ }
+
SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse);
// If this is a call to a method via a cast, also mark the method in the
@@ -19615,7 +19989,9 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) {
if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl()))
if (!isUnevaluatedContext() && !isConstantEvaluated() &&
- FD->isConsteval() && !RebuildingImmediateInvocation)
+ !isImmediateFunctionContext() &&
+ !isCheckingDefaultArgumentOrInitializer() && FD->isConsteval() &&
+ !RebuildingImmediateInvocation && !FD->isDependentContext())
ExprEvalContexts.back().ReferenceToConsteval.insert(E);
MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse,
RefsMinusAssignments);
@@ -19849,7 +20225,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts,
bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
const PartialDiagnostic &PD) {
return DiagRuntimeBehavior(
- Loc, Statement ? llvm::makeArrayRef(Statement) : llvm::None, PD);
+ Loc, Statement ? llvm::ArrayRef(Statement) : std::nullopt, PD);
}
bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
@@ -20761,7 +21137,8 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
llvm::ArrayRef<AvailabilitySpec> AvailSpecs, SourceLocation AtLoc,
SourceLocation RParen) {
- auto FindSpecVersion = [&](StringRef Platform) -> Optional<VersionTuple> {
+ auto FindSpecVersion =
+ [&](StringRef Platform) -> std::optional<VersionTuple> {
auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) {
return Spec.getPlatform() == Platform;
});
@@ -20773,7 +21150,7 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
});
}
if (Spec == AvailSpecs.end())
- return None;
+ return std::nullopt;
return Spec->getVersion();
};
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 5331193de863..e3eef9323b2f 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -21,11 +21,13 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/AlignedAllocation.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TokenKinds.h"
#include "clang/Basic/TypeTraits.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
@@ -42,6 +44,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TypeSize.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -241,7 +244,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
if (IsAcceptableResult(Type)) {
QualType T = Context.getTypeDeclType(Type);
MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false);
- return CreateParsedType(T,
+ return CreateParsedType(Context.getElaboratedType(ETK_None, nullptr, T),
Context.getTrivialTypeSourceInfo(T, NameLoc));
}
}
@@ -1388,6 +1391,13 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
bool IsImplicit) {
+ if (getLangOpts().HLSL && Type.getTypePtr()->isPointerType()) {
+ auto *This = new (Context)
+ CXXThisExpr(Loc, Type.getTypePtr()->getPointeeType(), IsImplicit);
+ This->setValueKind(ExprValueKind::VK_LValue);
+ MarkThisReferenced(This);
+ return This;
+ }
auto *This = new (Context) CXXThisExpr(Loc, Type, IsImplicit);
MarkThisReferenced(This);
return This;
@@ -1450,9 +1460,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
QualType Ty = TInfo->getType();
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
- assert((!ListInitialization ||
- (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) &&
- "List initialization must have initializer list as expression.");
+ assert((!ListInitialization || Exprs.size() == 1) &&
+ "List initialization must have exactly one expression.");
SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc);
InitializedEntity Entity =
@@ -1506,12 +1515,17 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
<< ListInitialization << Ty << FullRange);
QualType DeducedType;
- if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed)
+ TemplateDeductionInfo Info(Deduce->getExprLoc());
+ TemplateDeductionResult Result =
+ DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info);
+ if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure)
<< Ty << Deduce->getType() << FullRange
<< Deduce->getSourceRange());
- if (DeducedType.isNull())
+ if (DeducedType.isNull()) {
+ assert(Result == TDK_AlreadyDiagnosed);
return ExprError();
+ }
Ty = DeducedType;
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
@@ -1832,7 +1846,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
SourceLocation PlacementRParen, SourceRange TypeIdParens,
Declarator &D, Expr *Initializer) {
- Optional<Expr *> ArraySize;
+ std::optional<Expr *> ArraySize;
// If the specified type is an array, unwrap it and save the expression.
if (D.getNumTypeObjects() > 0 &&
D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
@@ -1924,7 +1938,7 @@ Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const {
return false;
if (FD.isDefined())
return false;
- Optional<unsigned> AlignmentParam;
+ std::optional<unsigned> AlignmentParam;
if (FD.isReplaceableGlobalAllocationFunction(&AlignmentParam) &&
AlignmentParam)
return true;
@@ -1950,17 +1964,14 @@ void Sema::diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
}
}
-ExprResult
-Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
- SourceLocation PlacementLParen,
- MultiExprArg PlacementArgs,
- SourceLocation PlacementRParen,
- SourceRange TypeIdParens,
- QualType AllocType,
- TypeSourceInfo *AllocTypeInfo,
- Optional<Expr *> ArraySize,
- SourceRange DirectInitRange,
- Expr *Initializer) {
+ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
+ SourceLocation PlacementLParen,
+ MultiExprArg PlacementArgs,
+ SourceLocation PlacementRParen,
+ SourceRange TypeIdParens, QualType AllocType,
+ TypeSourceInfo *AllocTypeInfo,
+ std::optional<Expr *> ArraySize,
+ SourceRange DirectInitRange, Expr *Initializer) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
SourceLocation StartLoc = Range.getBegin();
@@ -2045,12 +2056,17 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
<< Braced << AllocType << TypeRange);
QualType DeducedType;
- if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
+ TemplateDeductionInfo Info(Deduce->getExprLoc());
+ TemplateDeductionResult Result =
+ DeduceAutoType(AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info);
+ if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
- << AllocType << Deduce->getType()
- << TypeRange << Deduce->getSourceRange());
- if (DeducedType.isNull())
+ << AllocType << Deduce->getType() << TypeRange
+ << Deduce->getSourceRange());
+ if (DeducedType.isNull()) {
+ assert(Result == TDK_AlreadyDiagnosed);
return ExprError();
+ }
AllocType = DeducedType;
}
@@ -2069,6 +2085,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
+ if (ArraySize && !checkArrayElementAlignment(AllocType, TypeRange.getBegin()))
+ return ExprError();
+
// In ARC, infer 'retaining' for the allocated
if (getLangOpts().ObjCAutoRefCount &&
AllocType.getObjCLifetime() == Qualifiers::OCL_None &&
@@ -2092,7 +2111,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// conversion function to integral or unscoped enumeration type exists.
// C++1y [expr.new]p6: The expression [...] is implicitly converted to
// std::size_t.
- llvm::Optional<uint64_t> KnownArraySize;
+ std::optional<uint64_t> KnownArraySize;
if (ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent()) {
ExprResult ConvertedSize;
if (getLangOpts().CPlusPlus14) {
@@ -2186,7 +2205,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// FIXME: Per CWG1464, we are required to check the value prior to
// converting to size_t. This will never find a negative array size in
// C++14 onwards, because Value is always unsigned here!
- if (Optional<llvm::APSInt> Value =
+ if (std::optional<llvm::APSInt> Value =
(*ArraySize)->getIntegerConstantExpr(Context)) {
if (Value->isSigned() && Value->isNegative()) {
return ExprError(Diag((*ArraySize)->getBeginLoc(),
@@ -2273,7 +2292,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
SizeTyWidth, Context.getTypeSizeInChars(AllocType).getQuantity());
// How many bytes do we want to allocate here?
- llvm::Optional<llvm::APInt> AllocationSize;
+ std::optional<llvm::APInt> AllocationSize;
if (!ArraySize && !AllocType->isDependentType()) {
// For non-array operator new, we only want to allocate one element.
AllocationSize = SingleEltSize;
@@ -2632,7 +2651,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// tree? Or should the consumer just recalculate the value?
// FIXME: Using a dummy value will interact poorly with attribute enable_if.
IntegerLiteral Size(
- Context, llvm::APInt::getZero(Context.getTargetInfo().getPointerWidth(0)),
+ Context,
+ llvm::APInt::getZero(
+ Context.getTargetInfo().getPointerWidth(LangAS::Default)),
Context.getSizeType(), SourceLocation());
AllocArgs.push_back(&Size);
@@ -2950,6 +2971,14 @@ void Sema::DeclareGlobalNewDelete() {
if (getLangOpts().OpenCLCPlusPlus)
return;
+ // C++ [basic.stc.dynamic.general]p2:
+ // The library provides default definitions for the global allocation
+ // and deallocation functions. Some global allocation and deallocation
+ // functions are replaceable ([new.delete]); these are attached to the
+ // global module ([module.unit]).
+ if (getLangOpts().CPlusPlusModules && getCurrentModule())
+ PushGlobalModuleFragment(SourceLocation(), /*IsImplicit=*/true);
+
// C++ [basic.std.dynamic]p2:
// [...] The following allocation and deallocation functions (18.4) are
// implicitly declared in global scope in each translation unit of a
@@ -2989,6 +3018,14 @@ void Sema::DeclareGlobalNewDelete() {
&PP.getIdentifierTable().get("bad_alloc"),
nullptr);
getStdBadAlloc()->setImplicit(true);
+
+ // The implicitly declared "std::bad_alloc" should live in global module
+ // fragment.
+ if (GlobalModuleFragment) {
+ getStdBadAlloc()->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::ReachableWhenImported);
+ getStdBadAlloc()->setLocalOwningModule(GlobalModuleFragment);
+ }
}
if (!StdAlignValT && getLangOpts().AlignedAllocation) {
// The "std::align_val_t" enum class has not yet been declared, so build it
@@ -2996,9 +3033,19 @@ void Sema::DeclareGlobalNewDelete() {
auto *AlignValT = EnumDecl::Create(
Context, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(),
&PP.getIdentifierTable().get("align_val_t"), nullptr, true, true, true);
+
+ // The implicitly declared "std::align_val_t" should live in global module
+ // fragment.
+ if (GlobalModuleFragment) {
+ AlignValT->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::ReachableWhenImported);
+ AlignValT->setLocalOwningModule(GlobalModuleFragment);
+ }
+
AlignValT->setIntegerType(Context.getSizeType());
AlignValT->setPromotionType(Context.getSizeType());
AlignValT->setImplicit(true);
+
StdAlignValT = AlignValT;
}
@@ -3040,6 +3087,9 @@ void Sema::DeclareGlobalNewDelete() {
DeclareGlobalAllocationFunctions(OO_Array_New, VoidPtr, SizeT);
DeclareGlobalAllocationFunctions(OO_Delete, Context.VoidTy, VoidPtr);
DeclareGlobalAllocationFunctions(OO_Array_Delete, Context.VoidTy, VoidPtr);
+
+ if (getLangOpts().CPlusPlusModules && getCurrentModule())
+ PopGlobalModuleFragment();
}
/// DeclareGlobalAllocationFunction - Declares a single implicit global
@@ -3061,7 +3111,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
for (auto *P : Func->parameters())
FuncParams.push_back(
Context.getCanonicalType(P->getType().getUnqualifiedType()));
- if (llvm::makeArrayRef(FuncParams) == Params) {
+ if (llvm::ArrayRef(FuncParams) == Params) {
// Make the function visible to name lookup, even if we found it in
// an unimported module. It either is an implicitly-declared global
// allocation function, or is suppressing that function.
@@ -3084,7 +3134,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
assert(StdBadAlloc && "Must have std::bad_alloc declared");
EPI.ExceptionSpec.Type = EST_Dynamic;
- EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType);
+ EPI.ExceptionSpec.Exceptions = llvm::ArrayRef(BadAllocType);
}
if (getLangOpts().NewInfallible) {
EPI.ExceptionSpec.Type = EST_DynamicNone;
@@ -3108,6 +3158,22 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Alloc->addAttr(
ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation()));
+ // C++ [basic.stc.dynamic.general]p2:
+ // The library provides default definitions for the global allocation
+ // and deallocation functions. Some global allocation and deallocation
+ // functions are replaceable ([new.delete]); these are attached to the
+ // global module ([module.unit]).
+ //
+ // In the language wording, these functions are attched to the global
+ // module all the time. But in the implementation, the global module
+ // is only meaningful when we're in a module unit. So here we attach
+ // these allocation functions to global module conditionally.
+ if (GlobalModuleFragment) {
+ Alloc->setModuleOwnershipKind(
+ Decl::ModuleOwnershipKind::ReachableWhenImported);
+ Alloc->setLocalOwningModule(GlobalModuleFragment);
+ }
+
Alloc->addAttr(VisibilityAttr::CreateImplicit(
Context, LangOpts.GlobalAllocationFunctionVisibilityHidden
? VisibilityAttr::Hidden
@@ -3176,7 +3242,8 @@ FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc,
bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
DeclarationName Name,
- FunctionDecl *&Operator, bool Diagnose) {
+ FunctionDecl *&Operator, bool Diagnose,
+ bool WantSize, bool WantAligned) {
LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName);
// Try to find operator delete/operator delete[] in class scope.
LookupQualifiedName(Found, RD);
@@ -3186,13 +3253,14 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Found.suppressDiagnostics();
- bool Overaligned = hasNewExtendedAlignment(*this, Context.getRecordType(RD));
+ bool Overaligned =
+ WantAligned || hasNewExtendedAlignment(*this, Context.getRecordType(RD));
// C++17 [expr.delete]p10:
// If the deallocation functions have class scope, the one without a
// parameter of type std::size_t is selected.
llvm::SmallVector<UsualDeallocFnInfo, 4> Matches;
- resolveDeallocationOverload(*this, Found, /*WantSize*/ false,
+ resolveDeallocationOverload(*this, Found, /*WantSize*/ WantSize,
/*WantAlign*/ Overaligned, &Matches);
// If we could find an overload, use it.
@@ -4170,7 +4238,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
- llvm_unreachable("Cannot perform an ellipsis conversion");
+ case ImplicitConversionSequence::StaticObjectArgumentConversion:
+ llvm_unreachable("bad conversion");
case ImplicitConversionSequence::BadConversion:
Sema::AssignConvertType ConvTy =
@@ -4740,12 +4809,16 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsIntegral:
case UTT_IsFloatingPoint:
case UTT_IsArray:
+ case UTT_IsBoundedArray:
case UTT_IsPointer:
+ case UTT_IsNullPointer:
+ case UTT_IsReferenceable:
case UTT_IsLvalueReference:
case UTT_IsRvalueReference:
case UTT_IsMemberFunctionPointer:
case UTT_IsMemberObjectPointer:
case UTT_IsEnum:
+ case UTT_IsScopedEnum:
case UTT_IsUnion:
case UTT_IsClass:
case UTT_IsFunction:
@@ -4766,6 +4839,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsConst:
case UTT_IsVolatile:
case UTT_IsSigned:
+ case UTT_IsUnboundedArray:
case UTT_IsUnsigned:
// This type trait always returns false, checking the type is moot.
@@ -4792,9 +4866,16 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
return true;
+ // LWG3823: T shall be an array type, a complete type, or cv void.
+ case UTT_IsAggregate:
+ if (ArgTy->isArrayType() || ArgTy->isVoidType())
+ return true;
+
+ return !S.RequireCompleteType(
+ Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr);
+
// C++1z [meta.unary.prop]:
// remove_all_extents_t<T> shall be a complete type or cv void.
- case UTT_IsAggregate:
case UTT_IsTrivial:
case UTT_IsTriviallyCopyable:
case UTT_IsStandardLayout:
@@ -4817,7 +4898,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// C++1z [meta.unary.prop]:
// T shall be a complete type, cv void, or an array of unknown bound.
@@ -4885,8 +4966,26 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return T->isFloatingType();
case UTT_IsArray:
return T->isArrayType();
+ case UTT_IsBoundedArray:
+ if (!T->isVariableArrayType()) {
+ return T->isArrayType() && !T->isIncompleteArrayType();
+ }
+
+ Self.Diag(KeyLoc, diag::err_vla_unsupported)
+ << 1 << tok::kw___is_bounded_array;
+ return false;
+ case UTT_IsUnboundedArray:
+ if (!T->isVariableArrayType()) {
+ return T->isIncompleteArrayType();
+ }
+
+ Self.Diag(KeyLoc, diag::err_vla_unsupported)
+ << 1 << tok::kw___is_unbounded_array;
+ return false;
case UTT_IsPointer:
return T->isAnyPointerType();
+ case UTT_IsNullPointer:
+ return T->isNullPtrType();
case UTT_IsLvalueReference:
return T->isLValueReferenceType();
case UTT_IsRvalueReference:
@@ -4897,6 +4996,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return T->isMemberDataPointerType();
case UTT_IsEnum:
return T->isEnumeralType();
+ case UTT_IsScopedEnum:
+ return T->isScopedEnumeralType();
case UTT_IsUnion:
return T->isUnionType();
case UTT_IsClass:
@@ -5268,6 +5369,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return C.hasUniqueObjectRepresentations(T);
case UTT_IsTriviallyRelocatable:
return T.isTriviallyRelocatableType(C);
+ case UTT_IsReferenceable:
+ return T.isReferenceable();
}
}
@@ -5412,6 +5515,8 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
Replacement = BTT_IsTriviallyAssignable;
break;
case UTT_HasTrivialCopy:
+ Replacement = UTT_IsTriviallyCopyable;
+ break;
case UTT_HasTrivialDefaultConstructor:
case UTT_HasTrivialMoveConstructor:
Replacement = TT_IsTriviallyConstructible;
@@ -5427,9 +5532,26 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind,
}
}
+bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) {
+ if (Arity && N != Arity) {
+ Diag(Loc, diag::err_type_trait_arity)
+ << Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc);
+ return false;
+ }
+
+ if (!Arity && N == 0) {
+ Diag(Loc, diag::err_type_trait_arity)
+ << 1 << 1 << 1 << (int)N << SourceRange(Loc);
+ return false;
+ }
+ return true;
+}
+
ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ArrayRef<TypeSourceInfo *> Args,
SourceLocation RParenLoc) {
+ if (!CheckTypeTraitArity(getTypeTraitArity(Kind), KWLoc, Args.size()))
+ return ExprError();
QualType ResultType = Context.getLogicalOperationType();
if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness(
@@ -6186,7 +6308,7 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
<< LHSType << RHSType;
return {};
}
- ResultType = LHSType;
+ ResultType = Context.getCommonSugaredType(LHSType, RHSType);
} else if (LHSVT || RHSVT) {
ResultType = CheckVectorOperands(
LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true,
@@ -6197,15 +6319,13 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
return {};
} else {
// Both are scalar.
- QualType ResultElementTy;
- LHSType = LHSType.getCanonicalType().getUnqualifiedType();
- RHSType = RHSType.getCanonicalType().getUnqualifiedType();
-
- if (Context.hasSameType(LHSType, RHSType))
- ResultElementTy = LHSType;
- else
- ResultElementTy =
- UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
+ LHSType = LHSType.getUnqualifiedType();
+ RHSType = RHSType.getUnqualifiedType();
+ QualType ResultElementTy =
+ Context.hasSameType(LHSType, RHSType)
+ ? Context.getCommonSugaredType(LHSType, RHSType)
+ : UsualArithmeticConversions(LHS, RHS, QuestionLoc,
+ ACK_Conditional);
if (ResultElementTy->isEnumeralType()) {
Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
@@ -6425,7 +6545,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// -- Both the second and third operands have type void; the result is of
// type void and is a prvalue.
if (LVoid && RVoid)
- return Context.VoidTy;
+ return Context.getCommonSugaredType(LTy, RTy);
// Neither holds, error.
Diag(QuestionLoc, diag::err_conditional_void_nonvoid)
@@ -6531,21 +6651,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (LHS.get()->getObjectKind() == OK_BitField ||
RHS.get()->getObjectKind() == OK_BitField)
OK = OK_BitField;
-
- // If we have function pointer types, unify them anyway to unify their
- // exception specifications, if any.
- if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) {
- Qualifiers Qs = LTy.getQualifiers();
- LTy = FindCompositePointerType(QuestionLoc, LHS, RHS,
- /*ConvertArgs*/false);
- LTy = Context.getQualifiedType(LTy, Qs);
-
- assert(!LTy.isNull() && "failed to find composite pointer type for "
- "canonically equivalent function ptr types");
- assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type");
- }
-
- return LTy;
+ return Context.getCommonSugaredType(LTy, RTy);
}
// C++11 [expr.cond]p5
@@ -6575,36 +6681,23 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// is a prvalue temporary of the result type, which is
// copy-initialized from either the second operand or the third
// operand depending on the value of the first operand.
- if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) {
+ if (Context.hasSameType(LTy, RTy)) {
if (LTy->isRecordType()) {
// The operands have class type. Make a temporary copy.
- InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy);
-
- ExprResult LHSCopy = PerformCopyInitialization(Entity,
- SourceLocation(),
- LHS);
+ ExprResult LHSCopy = PerformCopyInitialization(
+ InitializedEntity::InitializeTemporary(LTy), SourceLocation(), LHS);
if (LHSCopy.isInvalid())
return QualType();
- ExprResult RHSCopy = PerformCopyInitialization(Entity,
- SourceLocation(),
- RHS);
+ ExprResult RHSCopy = PerformCopyInitialization(
+ InitializedEntity::InitializeTemporary(RTy), SourceLocation(), RHS);
if (RHSCopy.isInvalid())
return QualType();
LHS = LHSCopy;
RHS = RHSCopy;
}
-
- // If we have function pointer types, unify them anyway to unify their
- // exception specifications, if any.
- if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) {
- LTy = FindCompositePointerType(QuestionLoc, LHS, RHS);
- assert(!LTy.isNull() && "failed to find composite pointer type for "
- "canonically equivalent function ptr types");
- }
-
- return LTy;
+ return Context.getCommonSugaredType(LTy, RTy);
}
// Extension: conditional operator involving vector types.
@@ -6669,79 +6762,6 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
return QualType();
}
-static FunctionProtoType::ExceptionSpecInfo
-mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1,
- FunctionProtoType::ExceptionSpecInfo ESI2,
- SmallVectorImpl<QualType> &ExceptionTypeStorage) {
- ExceptionSpecificationType EST1 = ESI1.Type;
- ExceptionSpecificationType EST2 = ESI2.Type;
-
- // If either of them can throw anything, that is the result.
- if (EST1 == EST_None) return ESI1;
- if (EST2 == EST_None) return ESI2;
- if (EST1 == EST_MSAny) return ESI1;
- if (EST2 == EST_MSAny) return ESI2;
- if (EST1 == EST_NoexceptFalse) return ESI1;
- if (EST2 == EST_NoexceptFalse) return ESI2;
-
- // If either of them is non-throwing, the result is the other.
- if (EST1 == EST_NoThrow) return ESI2;
- if (EST2 == EST_NoThrow) return ESI1;
- if (EST1 == EST_DynamicNone) return ESI2;
- if (EST2 == EST_DynamicNone) return ESI1;
- if (EST1 == EST_BasicNoexcept) return ESI2;
- if (EST2 == EST_BasicNoexcept) return ESI1;
- if (EST1 == EST_NoexceptTrue) return ESI2;
- if (EST2 == EST_NoexceptTrue) return ESI1;
-
- // If we're left with value-dependent computed noexcept expressions, we're
- // stuck. Before C++17, we can just drop the exception specification entirely,
- // since it's not actually part of the canonical type. And this should never
- // happen in C++17, because it would mean we were computing the composite
- // pointer type of dependent types, which should never happen.
- if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) {
- assert(!S.getLangOpts().CPlusPlus17 &&
- "computing composite pointer type of dependent types");
- return FunctionProtoType::ExceptionSpecInfo();
- }
-
- // Switch over the possibilities so that people adding new values know to
- // update this function.
- switch (EST1) {
- case EST_None:
- case EST_DynamicNone:
- case EST_MSAny:
- case EST_BasicNoexcept:
- case EST_DependentNoexcept:
- case EST_NoexceptFalse:
- case EST_NoexceptTrue:
- case EST_NoThrow:
- llvm_unreachable("handled above");
-
- case EST_Dynamic: {
- // This is the fun case: both exception specifications are dynamic. Form
- // the union of the two lists.
- assert(EST2 == EST_Dynamic && "other cases should already be handled");
- llvm::SmallPtrSet<QualType, 8> Found;
- for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions})
- for (QualType E : Exceptions)
- if (Found.insert(S.Context.getCanonicalType(E)).second)
- ExceptionTypeStorage.push_back(E);
-
- FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic);
- Result.Exceptions = ExceptionTypeStorage;
- return Result;
- }
-
- case EST_Unevaluated:
- case EST_Uninstantiated:
- case EST_Unparsed:
- llvm_unreachable("shouldn't see unresolved exception specifications here");
- }
-
- llvm_unreachable("invalid ExceptionSpecificationType");
-}
-
/// Find a merged pointer type and convert the two expressions to it.
///
/// This finds the composite pointer type for \p E1 and \p E2 according to
@@ -7045,9 +7065,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
// The result is nothrow if both operands are.
SmallVector<QualType, 8> ExceptionTypeStorage;
- EPI1.ExceptionSpec = EPI2.ExceptionSpec =
- mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec,
- ExceptionTypeStorage);
+ EPI1.ExceptionSpec = EPI2.ExceptionSpec = Context.mergeExceptionSpecs(
+ EPI1.ExceptionSpec, EPI2.ExceptionSpec, ExceptionTypeStorage,
+ getLangOpts().CPlusPlus17);
Composite1 = Context.getFunctionType(FPT1->getReturnType(),
FPT1->getParamTypes(), EPI1);
@@ -7091,7 +7111,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc,
Steps[I].Quals.addConst();
// Rebuild the composite type.
- QualType Composite = Composite1;
+ QualType Composite = Context.getCommonSugaredType(Composite1, Composite2);
for (auto &S : llvm::reverse(Steps))
Composite = S.rebuild(Context, Composite);
@@ -7308,8 +7328,8 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
if (!Cleanup.exprNeedsCleanups())
return SubExpr;
- auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
- ExprCleanupObjects.size() - FirstCleanup);
+ auto Cleanups = llvm::ArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
+ ExprCleanupObjects.size() - FirstCleanup);
auto *E = ExprWithCleanups::Create(
Context, SubExpr, Cleanup.cleanupsHaveSideEffects(), Cleanups);
@@ -7381,7 +7401,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
return BinaryOperator::Create(Context, BO->getLHS(), RHS.get(), BO_Comma,
BO->getType(), BO->getValueKind(),
BO->getObjectKind(), BO->getOperatorLoc(),
- BO->getFPFeatures(getLangOpts()));
+ BO->getFPFeatures());
}
}
@@ -7713,8 +7733,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
// designated by the pseudo-destructor-name shall be the same type.
if (DestructedTypeInfo) {
QualType DestructedType = DestructedTypeInfo->getType();
- SourceLocation DestructedTypeStart
- = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ SourceLocation DestructedTypeStart =
+ DestructedTypeInfo->getTypeLoc().getBeginLoc();
if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) {
if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
// Detect dot pseudo destructor calls on pointer objects, e.g.:
@@ -7739,7 +7759,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
} else {
Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
<< ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+ << DestructedTypeInfo->getTypeLoc().getSourceRange();
// Recover by setting the destructed type to the object type.
DestructedType = ObjectType;
@@ -7755,8 +7775,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
// type.
} else {
Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals)
- << ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getSourceRange();
}
// Recover by setting the destructed type to the object type.
@@ -7780,10 +7800,10 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
if (!ScopeType->isDependentType() && !ObjectType->isDependentType() &&
!Context.hasSameUnqualifiedType(ScopeType, ObjectType)) {
- Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(),
+ Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(),
diag::err_pseudo_dtor_type_mismatch)
- << ObjectType << ScopeType << Base->getSourceRange()
- << ScopeTypeInfo->getTypeLoc().getLocalSourceRange();
+ << ObjectType << ScopeType << Base->getSourceRange()
+ << ScopeTypeInfo->getTypeLoc().getSourceRange();
ScopeType = QualType();
ScopeTypeInfo = nullptr;
@@ -8254,7 +8274,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
// All the potentially captureable variables in the current nested
// lambda (within a generic outer lambda), must be captured by an
// outer lambda that is enclosed within a non-dependent context.
- CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) {
+ CurrentLSI->visitPotentialCaptures([&](ValueDecl *Var, Expr *VarExpr) {
// If the variable is clearly identified as non-odr-used and the full
// expression is not instantiation dependent, only then do we not
// need to check enclosing lambda's for speculative captures.
@@ -8270,14 +8290,18 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
!IsFullExprInstantiationDependent)
return;
+ VarDecl *UnderlyingVar = Var->getPotentiallyDecomposedVarDecl();
+ if (!UnderlyingVar)
+ return;
+
// If we have a capture-capable lambda for the variable, go ahead and
// capture the variable in that lambda (and all its enclosing lambdas).
- if (const Optional<unsigned> Index =
+ if (const std::optional<unsigned> Index =
getStackIndexOfNearestEnclosingCaptureCapableLambda(
S.FunctionScopes, Var, S))
S.MarkCaptureUsedInEnclosingContext(Var, VarExpr->getExprLoc(), *Index);
const bool IsVarNeverAConstantExpression =
- VariableCanNeverBeAConstantExpression(Var, S.Context);
+ VariableCanNeverBeAConstantExpression(UnderlyingVar, S.Context);
if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) {
// This full expression is not instantiation dependent or the variable
// can not be used in a constant expression - which means
@@ -8305,7 +8329,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
if (CurrentLSI->hasPotentialThisCapture()) {
// If we have a capture-capable lambda for 'this', go ahead and capture
// 'this' in that lambda (and all its enclosing lambdas).
- if (const Optional<unsigned> Index =
+ if (const std::optional<unsigned> Index =
getStackIndexOfNearestEnclosingCaptureCapableLambda(
S.FunctionScopes, /*0 is 'this'*/ nullptr, S)) {
const unsigned FunctionScopeIndexOfCapturableLambda = *Index;
@@ -8448,7 +8472,7 @@ class TransformTypos : public TreeTransform<TransformTypos> {
///
/// Returns true if there are any untried correction combinations.
bool CheckAndAdvanceTypoExprCorrectionStreams() {
- for (auto TE : TypoExprs) {
+ for (auto *TE : TypoExprs) {
auto &State = SemaRef.getTypoExprState(TE);
TransformCache.erase(TE);
if (!State.Consumer->hasMadeAnyCorrectionProgress())
@@ -8470,7 +8494,7 @@ class TransformTypos : public TreeTransform<TransformTypos> {
return DRE->getFoundDecl();
if (auto *ME = dyn_cast<MemberExpr>(E))
return ME->getFoundDecl();
- // FIXME: Add any other expr types that could be be seen by the delayed typo
+ // FIXME: Add any other expr types that could be seen by the delayed typo
// correction TreeTransform for which the corresponding TypoCorrection could
// contain multiple decls.
return nullptr;
@@ -8515,7 +8539,7 @@ class TransformTypos : public TreeTransform<TransformTypos> {
// 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) {
+ for (auto *TE : TypoExprs) {
TransformCache.erase(TE);
SemaRef.clearDelayedTypo(TE);
@@ -8744,14 +8768,14 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl,
}
ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
- bool DiscardedValue,
- bool IsConstexpr) {
+ bool DiscardedValue, bool IsConstexpr,
+ bool IsTemplateArgument) {
ExprResult FullExpr = FE;
if (!FullExpr.get())
return ExprError();
- if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
+ if (!IsTemplateArgument && DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
if (DiscardedValue) {
@@ -8998,13 +9022,14 @@ Sema::BuildExprRequirement(
Context.getReferenceQualifiedType(E).getCanonicalType();
llvm::SmallVector<TemplateArgument, 1> Args;
Args.push_back(TemplateArgument(MatchedType));
+
+ auto *Param = cast<TemplateTypeParmDecl>(TPL->getParam(0));
+
TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args);
- MultiLevelTemplateArgumentList MLTAL(TAL);
- for (unsigned I = 0; I < TPL->getDepth(); ++I)
- MLTAL.addOuterRetainedLevel();
- Expr *IDC =
- cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint()
- ->getImmediatelyDeclaredConstraint();
+ MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray(),
+ /*Final=*/false);
+ MLTAL.addOuterRetainedLevels(TPL->getDepth());
+ Expr *IDC = Param->getTypeConstraint()->getImmediatelyDeclaredConstraint();
ExprResult Constraint = SubstExpr(IDC, MLTAL);
if (Constraint.isInvalid()) {
Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure;
@@ -9057,9 +9082,11 @@ Sema::BuildNestedRequirement(Expr *Constraint) {
}
concepts::NestedRequirement *
-Sema::BuildNestedRequirement(
- concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
- return new (Context) concepts::NestedRequirement(SubstDiag);
+Sema::BuildNestedRequirement(StringRef InvalidConstraintEntity,
+ const ASTConstraintSatisfaction &Satisfaction) {
+ return new (Context) concepts::NestedRequirement(
+ InvalidConstraintEntity,
+ ASTConstraintSatisfaction::Rebuild(Context, Satisfaction));
}
RequiresExprBodyDecl *
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index c9d9ef31f3ee..a3420ac6fdd2 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -249,7 +249,7 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(
case IMA_Field_Uneval_Context:
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
<< R.getLookupNameInfo().getName();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case IMA_Static:
case IMA_Abstract:
case IMA_Mixed_StaticContext:
@@ -1161,10 +1161,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (!Var->getTemplateSpecializationKind())
Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc);
- return BuildMemberExpr(
- BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
- /*HadMultipleCandidates=*/false, MemberNameInfo,
- Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary);
+ return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var,
+ FoundDecl, /*HadMultipleCandidates=*/false,
+ MemberNameInfo, Var->getType().getNonReferenceType(),
+ VK_LValue, OK_Ordinary, TemplateArgs);
}
// We found something that we didn't expect. Complain.
@@ -1621,16 +1621,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
if (BaseType->isExtVectorType()) {
// FIXME: this expr should store IsArrow.
IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
- ExprValueKind VK;
- if (IsArrow)
- VK = VK_LValue;
- else {
- if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(BaseExpr.get()))
- VK = POE->getSyntacticForm()->getValueKind();
- else
- VK = BaseExpr.get()->getValueKind();
- }
-
+ ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind());
QualType ret = CheckExtVectorComponent(S, BaseType, VK, OpLoc,
Member, MemberLoc);
if (ret.isNull())
@@ -1903,6 +1894,14 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
baseExpr = BuildCXXThisExpr(loc, ThisTy, /*IsImplicit=*/true);
+ if (getLangOpts().HLSL && ThisTy.getTypePtr()->isPointerType()) {
+ ThisTy = ThisTy.getTypePtr()->getPointeeType();
+ return BuildMemberReferenceExpr(baseExpr, ThisTy,
+ /*OpLoc*/ SourceLocation(),
+ /*IsArrow*/ false, SS, TemplateKWLoc,
+ /*FirstQualifierInScope*/ nullptr, R,
+ TemplateArgs, S);
+ }
}
return BuildMemberReferenceExpr(baseExpr, ThisTy,
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index a6c92d1a338d..a4372349fff7 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -27,10 +27,11 @@
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ConvertUTF.h"
+#include <optional>
using namespace clang;
using namespace sema;
-using llvm::makeArrayRef;
+using llvm::ArrayRef;
ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
ArrayRef<Expr *> Strings) {
@@ -243,7 +244,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
QualType NumberType,
bool isLiteral = false,
SourceRange R = SourceRange()) {
- Optional<NSAPI::NSNumberLiteralMethodKind> Kind =
+ std::optional<NSAPI::NSNumberLiteralMethodKind> Kind =
S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
if (!Kind) {
@@ -298,7 +299,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
&CX.Idents.get("value"),
NumberType, /*TInfo=*/nullptr,
SC_None, nullptr);
- Method->setMethodParams(S.Context, value, None);
+ Method->setMethodParams(S.Context, value, std::nullopt);
}
if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method))
@@ -577,7 +578,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
Context.getPointerType(ConstCharType),
/*TInfo=*/nullptr,
SC_None, nullptr);
- M->setMethodParams(Context, value, None);
+ M->setMethodParams(Context, value, std::nullopt);
BoxingMethod = M;
}
@@ -591,8 +592,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
BoxingMethod = StringWithUTF8StringMethod;
BoxedType = NSStringPointer;
// Transfer the nullability from method's return type.
- Optional<NullabilityKind> Nullability =
- BoxingMethod->getReturnType()->getNullability(Context);
+ std::optional<NullabilityKind> Nullability =
+ BoxingMethod->getReturnType()->getNullability();
if (Nullability)
BoxedType = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability), BoxedType,
@@ -705,7 +706,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
SC_None, nullptr);
Params.push_back(type);
- M->setMethodParams(Context, Params, None);
+ M->setMethodParams(Context, Params, std::nullopt);
BoxingMethod = M;
}
@@ -833,7 +834,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
/*TInfo=*/nullptr, SC_None,
nullptr);
Params.push_back(cnt);
- Method->setMethodParams(Context, Params, None);
+ Method->setMethodParams(Context, Params, std::nullopt);
}
if (!validateBoxingMethod(*this, Loc, NSArrayDecl, Sel, Method))
@@ -1003,7 +1004,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
/*TInfo=*/nullptr, SC_None,
nullptr);
Params.push_back(cnt);
- Method->setMethodParams(Context, Params, None);
+ Method->setMethodParams(Context, Params, std::nullopt);
}
if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel,
@@ -1037,12 +1038,9 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
if (ObjCProtocolDecl *NSCopyingPDecl =
LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) {
ObjCProtocolDecl *PQ[] = {NSCopyingPDecl};
- QIDNSCopying =
- Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { },
- llvm::makeArrayRef(
- (ObjCProtocolDecl**) PQ,
- 1),
- false);
+ QIDNSCopying = Context.getObjCObjectType(
+ Context.ObjCBuiltinIdTy, {},
+ llvm::ArrayRef((ObjCProtocolDecl **)PQ, 1), false);
QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying);
}
}
@@ -1466,8 +1464,8 @@ static QualType getBaseMessageSendResultType(Sema &S,
// result type to the returned result.
auto transferNullability = [&](QualType type) -> QualType {
// If the method's result type has nullability, extract it.
- if (auto nullability = Method->getSendResultType(ReceiverType)
- ->getNullability(Context)){
+ if (auto nullability =
+ Method->getSendResultType(ReceiverType)->getNullability()) {
// Strip off any outer nullability sugar from the provided type.
(void)AttributedType::stripOuterNullability(type);
@@ -1546,7 +1544,7 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver,
assert(MD->isClassMethod() && "expected a class method");
QualType NewResultType = Context.getObjCObjectPointerType(
Context.getObjCInterfaceType(MD->getClassInterface()));
- if (auto Nullability = resultType->getNullability(Context))
+ if (auto Nullability = resultType->getNullability())
NewResultType = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability),
NewResultType, NewResultType);
@@ -1563,16 +1561,16 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver,
// Map the nullability of the result into a table index.
unsigned receiverNullabilityIdx = 0;
- if (Optional<NullabilityKind> nullability =
- ReceiverType->getNullability(Context)) {
+ if (std::optional<NullabilityKind> nullability =
+ ReceiverType->getNullability()) {
if (*nullability == NullabilityKind::NullableResult)
nullability = NullabilityKind::Nullable;
receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
}
unsigned resultNullabilityIdx = 0;
- if (Optional<NullabilityKind> nullability =
- resultType->getNullability(Context)) {
+ if (std::optional<NullabilityKind> nullability =
+ resultType->getNullability()) {
if (*nullability == NullabilityKind::NullableResult)
nullability = NullabilityKind::Nullable;
resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
@@ -1605,7 +1603,7 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver,
} else {
resultType = resultType.getDesugaredType(Context);
}
- } while (resultType->getNullability(Context));
+ } while (resultType->getNullability());
// Add nullability back if needed.
if (newResultNullabilityIdx > 0) {
@@ -1808,8 +1806,8 @@ bool Sema::CheckMessageArgumentTypes(
// Compute the set of type arguments to be substituted into each parameter
// type.
- Optional<ArrayRef<QualType>> typeArgs
- = ReceiverType->getObjCSubstitutions(Method->getDeclContext());
+ std::optional<ArrayRef<QualType>> typeArgs =
+ ReceiverType->getObjCSubstitutions(Method->getDeclContext());
bool IsError = false;
for (unsigned i = 0; i < NumNamedArgs; i++) {
// We can't do any type-checking on a type-dependent argument.
@@ -1909,8 +1907,8 @@ bool Sema::CheckMessageArgumentTypes(
DiagnoseSentinelCalls(Method, SelLoc, Args);
// Do additional checkings on method.
- IsError |= CheckObjCMethodCall(
- Method, SelLoc, makeArrayRef(Args.data(), Args.size()));
+ IsError |=
+ CheckObjCMethodCall(Method, SelLoc, ArrayRef(Args.data(), Args.size()));
return IsError;
}
@@ -2633,10 +2631,10 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
unsigned NumArgs = ArgsIn.size();
Expr **Args = ArgsIn.data();
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
- return ObjCMessageExpr::Create(
- Context, ReceiverType, VK_PRValue, LBracLoc, ReceiverTypeInfo, Sel,
- SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs), RBracLoc,
- isImplicit);
+ return ObjCMessageExpr::Create(Context, ReceiverType, VK_PRValue, LBracLoc,
+ ReceiverTypeInfo, Sel, SelectorLocs,
+ /*Method=*/nullptr, ArrayRef(Args, NumArgs),
+ RBracLoc, isImplicit);
}
// Find the class to which we are sending this message.
@@ -2735,21 +2733,19 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
// Construct the appropriate ObjCMessageExpr.
ObjCMessageExpr *Result;
if (SuperLoc.isValid())
- Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- SuperLoc, /*IsInstanceSuper=*/false,
- ReceiverType, Sel, SelectorLocs,
- Method, makeArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
+ Result = ObjCMessageExpr::Create(
+ Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false,
+ ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs),
+ RBracLoc, isImplicit);
else {
- Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- ReceiverTypeInfo, Sel, SelectorLocs,
- Method, makeArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
+ Result = ObjCMessageExpr::Create(
+ Context, ReturnType, VK, LBracLoc, ReceiverTypeInfo, Sel, SelectorLocs,
+ Method, ArrayRef(Args, NumArgs), RBracLoc, isImplicit);
if (!isImplicit)
checkCocoaAPI(*this, Result);
}
if (Method)
- checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs),
+ checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs),
ReceiverType, /*IsClassObjectCall=*/true);
return MaybeBindToTemporary(Result);
}
@@ -2888,8 +2884,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
assert(SuperLoc.isInvalid() && "Message to super with dependent type");
return ObjCMessageExpr::Create(
Context, Context.DependentTy, VK_PRValue, LBracLoc, Receiver, Sel,
- SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs),
- RBracLoc, isImplicit);
+ SelectorLocs, /*Method=*/nullptr, ArrayRef(Args, NumArgs), RBracLoc,
+ isImplicit);
}
// If necessary, apply function/array conversion to the receiver.
@@ -3326,16 +3322,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// Construct the appropriate ObjCMessageExpr instance.
ObjCMessageExpr *Result;
if (SuperLoc.isValid())
- Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- SuperLoc, /*IsInstanceSuper=*/true,
- ReceiverType, Sel, SelectorLocs, Method,
- makeArrayRef(Args, NumArgs), RBracLoc,
- isImplicit);
+ Result = ObjCMessageExpr::Create(
+ Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true,
+ ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs),
+ RBracLoc, isImplicit);
else {
- Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc,
- Receiver, Sel, SelectorLocs, Method,
- makeArrayRef(Args, NumArgs), RBracLoc,
- isImplicit);
+ Result = ObjCMessageExpr::Create(
+ Context, ReturnType, VK, LBracLoc, Receiver, Sel, SelectorLocs, Method,
+ ArrayRef(Args, NumArgs), RBracLoc, isImplicit);
if (!isImplicit)
checkCocoaAPI(*this, Result);
}
@@ -3356,7 +3350,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
}
}
- checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs),
+ checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs),
ReceiverType, IsClassObjectCall);
}
@@ -3860,7 +3854,7 @@ static inline T *getObjCBridgeAttr(const TypedefType *TD) {
static ObjCBridgeRelatedAttr *ObjCBridgeRelatedAttrFromType(QualType T,
TypedefNameDecl *&TDNDecl) {
- while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ while (const auto *TD = T->getAs<TypedefType>()) {
TDNDecl = TD->getDecl();
if (ObjCBridgeRelatedAttr *ObjCBAttr =
getObjCBridgeAttr<ObjCBridgeRelatedAttr>(TD))
@@ -4007,7 +4001,7 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr,
bool &HadTheAttribute, bool warn) {
QualType T = castExpr->getType();
HadTheAttribute = false;
- while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ while (const auto *TD = T->getAs<TypedefType>()) {
TypedefNameDecl *TDNDecl = TD->getDecl();
if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
@@ -4070,7 +4064,7 @@ static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr,
bool &HadTheAttribute, bool warn) {
QualType T = castType;
HadTheAttribute = false;
- while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
+ while (const auto *TD = T->getAs<TypedefType>()) {
TypedefNameDecl *TDNDecl = TD->getDecl();
if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) {
if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) {
@@ -4377,11 +4371,9 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
Diag(RelatedClass->getBeginLoc(), diag::note_declared_at);
Diag(TDNDecl->getBeginLoc(), diag::note_declared_at);
- ExprResult msg =
- BuildInstanceMessageImplicit(SrcExpr, SrcType,
- InstanceMethod->getLocation(),
- InstanceMethod->getSelector(),
- InstanceMethod, None);
+ ExprResult msg = BuildInstanceMessageImplicit(
+ SrcExpr, SrcType, InstanceMethod->getLocation(),
+ InstanceMethod->getSelector(), InstanceMethod, std::nullopt);
SrcExpr = msg.get();
}
return true;
diff --git a/clang/lib/Sema/SemaFixItUtils.cpp b/clang/lib/Sema/SemaFixItUtils.cpp
index 2910a56f866b..2c85a5319430 100644
--- a/clang/lib/Sema/SemaFixItUtils.cpp
+++ b/clang/lib/Sema/SemaFixItUtils.cpp
@@ -124,7 +124,7 @@ bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
// Check if the pointer to the argument needs to be passed:
// (type -> type *) or (type & -> type *).
- if (isa<PointerType>(ToQTy)) {
+ if (const auto *ToPtrTy = dyn_cast<PointerType>(ToQTy)) {
bool CanConvert = false;
OverloadFixItKind FixKind = OFIK_TakeAddress;
@@ -132,6 +132,10 @@ bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr,
if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary)
return false;
+ // Do no take address of const pointer to get void*
+ if (isa<PointerType>(FromQTy) && ToPtrTy->isVoidPointerType())
+ return false;
+
CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, S,
Begin, VK_PRValue);
if (CanConvert) {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
new file mode 100644
index 000000000000..cf82cc9bccdf
--- /dev/null
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -0,0 +1,34 @@
+//===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===//
+//
+// 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 implements Semantic Analysis for HLSL constructs.
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/Sema.h"
+
+using namespace clang;
+
+Decl *Sema::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *Ident,
+ SourceLocation IdentLoc,
+ SourceLocation LBrace) {
+ // For anonymous namespace, take the location of the left brace.
+ DeclContext *LexicalParent = getCurLexicalContext();
+ HLSLBufferDecl *Result = HLSLBufferDecl::Create(
+ Context, LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
+
+ PushOnScopeChains(Result, BufferScope);
+ PushDeclContext(BufferScope, Result);
+
+ return Result;
+}
+
+void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) {
+ auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
+ BufDecl->setRBraceLoc(RBrace);
+ PopDeclContext();
+}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index d3b454843234..ddb2b5cf5cd1 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -81,12 +81,22 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT,
const QualType ElemTy =
Context.getCanonicalType(AT->getElementType()).getUnqualifiedType();
+ auto IsCharOrUnsignedChar = [](const QualType &T) {
+ const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr());
+ return BT && BT->isCharType() && BT->getKind() != BuiltinType::SChar;
+ };
+
switch (SL->getKind()) {
case StringLiteral::UTF8:
// char8_t array can be initialized with a UTF-8 string.
- if (ElemTy->isChar8Type())
+ // - C++20 [dcl.init.string] (DR)
+ // Additionally, an array of char or unsigned char may be initialized
+ // by a UTF-8 string literal.
+ if (ElemTy->isChar8Type() ||
+ (Context.getLangOpts().Char8 &&
+ IsCharOrUnsignedChar(ElemTy.getCanonicalType())))
return SIF_None;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case StringLiteral::Ordinary:
// char array can be initialized with a narrow string.
// Only allow char x[] = "foo"; not char x[] = L"foo";
@@ -229,6 +239,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
if (StrLength > CAT->getSize().getZExtValue())
S.Diag(Str->getBeginLoc(),
diag::err_initializer_string_for_char_array_too_long)
+ << CAT->getSize().getZExtValue() << StrLength
<< Str->getSourceRange();
} else {
// C99 6.7.8p14.
@@ -493,7 +504,7 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc,
true);
MultiExprArg SubInit;
Expr *InitExpr;
- InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc);
+ InitListExpr DummyInitList(SemaRef.Context, Loc, std::nullopt, Loc);
// C++ [dcl.init.aggr]p7:
// If there are fewer initializer-clauses in the list than there are
@@ -512,8 +523,10 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc,
//
// Only do this if we're initializing a class type, to avoid filling in
// the initializer list where possible.
- InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context)
- InitListExpr(SemaRef.Context, Loc, None, Loc);
+ InitExpr = VerifyOnly
+ ? &DummyInitList
+ : new (SemaRef.Context)
+ InitListExpr(SemaRef.Context, Loc, std::nullopt, Loc);
InitExpr->setType(SemaRef.Context.VoidTy);
SubInit = InitExpr;
Kind = InitializationKind::CreateCopy(Loc, Loc);
@@ -695,10 +708,10 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
// 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);
+ << Field->getType()
+ << (ILE->isSyntacticForm() ? ILE : ILE->getSyntacticForm())
+ ->getSourceRange();
+ SemaRef.Diag(Field->getLocation(), diag::note_uninit_reference_member);
}
hadError = true;
return;
@@ -1518,8 +1531,8 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
// As an extension, clang supports complex initializers, which initialize
// a complex number component-wise. When an explicit initializer list for
- // a complex number contains two two initializers, this extension kicks in:
- // it exepcts the initializer list to contain two elements convertible to
+ // a complex number contains two initializers, this extension kicks in:
+ // it expects the initializer list to contain two elements convertible to
// the element type of the complex type. The first element initializes
// the real part, and the second element intitializes the imaginary part.
@@ -2934,7 +2947,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Compute the type of the integer literals.
QualType PromotedCharTy = CharTy;
- if (CharTy->isPromotableIntegerType())
+ if (Context.isPromotableIntegerType(CharTy))
PromotedCharTy = Context.getPromotedIntegerType(CharTy);
unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy);
@@ -3110,10 +3123,8 @@ InitListExpr *
InitListChecker::createInitListExpr(QualType CurrentObjectType,
SourceRange InitRange,
unsigned ExpectedNumInits) {
- InitListExpr *Result
- = new (SemaRef.Context) InitListExpr(SemaRef.Context,
- InitRange.getBegin(), None,
- InitRange.getEnd());
+ InitListExpr *Result = new (SemaRef.Context) InitListExpr(
+ SemaRef.Context, InitRange.getBegin(), std::nullopt, InitRange.getEnd());
QualType ResultType = CurrentObjectType;
if (!ResultType->isArrayType())
@@ -3519,6 +3530,7 @@ void InitializationSequence::Step::Destroy() {
case SK_StdInitializerListConstructorCall:
case SK_OCLSamplerInit:
case SK_OCLZeroOpaqueType:
+ case SK_ParenthesizedListInit:
break;
case SK_ConversionSequence:
@@ -3578,6 +3590,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_PlaceholderType:
case FK_ExplicitConstructor:
case FK_AddressOfUnaddressableFunction:
+ case FK_ParenthesizedListInitFailed:
return false;
case FK_ReferenceInitOverloadFailed:
@@ -3813,6 +3826,13 @@ void InitializationSequence::AddOCLZeroOpaqueTypeStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddParenthesizedListInitStep(QualType T) {
+ Step S;
+ S.Kind = SK_ParenthesizedListInit;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::RewrapReferenceInitList(QualType T,
InitListExpr *Syntactic) {
assert(Syntactic->getNumInits() == 1 &&
@@ -5227,7 +5247,7 @@ static void TryDefaultInitialization(Sema &S,
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) {
- TryConstructorInitialization(S, Entity, Kind, None, DestType,
+ TryConstructorInitialization(S, Entity, Kind, std::nullopt, DestType,
Entity.getType(), Sequence);
return;
}
@@ -5250,6 +5270,208 @@ static void TryDefaultInitialization(Sema &S,
}
}
+static void TryOrBuildParenListInitialization(
+ Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
+ ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly,
+ ExprResult *Result = nullptr) {
+ unsigned ArgIndexToProcess = 0;
+ SmallVector<Expr *, 4> InitExprs;
+ QualType ResultType;
+ Expr *ArrayFiller = nullptr;
+ FieldDecl *InitializedFieldInUnion = nullptr;
+
+ // Process entities (i.e. array members, base classes, or class fields) by
+ // adding an initialization expression to InitExprs for each entity to
+ // initialize.
+ auto ProcessEntities = [&](auto Range) -> bool {
+ bool IsUnionType = Entity.getType()->isUnionType();
+ for (InitializedEntity SubEntity : Range) {
+ // Unions should only have one initializer expression.
+ // If there are more initializers than it will be caught when we check
+ // whether Index equals Args.size().
+ if (ArgIndexToProcess == 1 && IsUnionType)
+ return true;
+
+ bool IsMember = SubEntity.getKind() == InitializedEntity::EK_Member;
+
+ // Unnamed bitfields should not be initialized at all, either with an arg
+ // or by default.
+ if (IsMember && cast<FieldDecl>(SubEntity.getDecl())->isUnnamedBitfield())
+ continue;
+
+ if (ArgIndexToProcess < Args.size()) {
+ // There are still expressions in Args that haven't been processed.
+ // Let's match them to the current entity to initialize.
+ Expr *E = Args[ArgIndexToProcess++];
+
+ // Incomplete array types indicate flexible array members. Do not allow
+ // paren list initializations of structs with these members, as GCC
+ // doesn't either.
+ if (IsMember) {
+ auto *FD = cast<FieldDecl>(SubEntity.getDecl());
+ if (FD->getType()->isIncompleteArrayType()) {
+ if (!VerifyOnly) {
+ S.Diag(E->getBeginLoc(), diag::err_flexible_array_init)
+ << SourceRange(E->getBeginLoc(), E->getEndLoc());
+ S.Diag(FD->getLocation(), diag::note_flexible_array_member) << FD;
+ }
+ Sequence.SetFailed(
+ InitializationSequence::FK_ParenthesizedListInitFailed);
+ return false;
+ }
+ }
+
+ InitializationKind SubKind = InitializationKind::CreateForInit(
+ E->getExprLoc(), /*isDirectInit=*/false, E);
+ InitializationSequence SubSeq(S, SubEntity, SubKind, E);
+
+ if (SubSeq.Failed()) {
+ if (!VerifyOnly)
+ SubSeq.Diagnose(S, SubEntity, SubKind, E);
+ else
+ Sequence.SetFailed(
+ InitializationSequence::FK_ParenthesizedListInitFailed);
+
+ return false;
+ }
+ if (!VerifyOnly) {
+ ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, E);
+ InitExprs.push_back(ER.get());
+ if (IsMember && IsUnionType)
+ InitializedFieldInUnion = cast<FieldDecl>(SubEntity.getDecl());
+ }
+ } else {
+ // We've processed all of the args, but there are still entities that
+ // have to be initialized.
+ if (IsMember) {
+ // C++ [dcl.init]p17.6.2.2
+ // The remaining elements are initialized with their default member
+ // initializers, if any
+ auto *FD = cast<FieldDecl>(SubEntity.getDecl());
+ if (Expr *ICE = FD->getInClassInitializer(); ICE && !VerifyOnly) {
+ ExprResult DIE = S.BuildCXXDefaultInitExpr(FD->getLocation(), FD);
+ if (DIE.isInvalid())
+ return false;
+ S.checkInitializerLifetime(SubEntity, DIE.get());
+ InitExprs.push_back(DIE.get());
+ continue;
+ };
+ }
+ // Remaining class elements without default member initializers and
+ // array elements are value initialized:
+ //
+ // C++ [dcl.init]p17.6.2.2
+ // The remaining elements...otherwise are value initialzed
+ //
+ // C++ [dcl.init]p17.5
+ // if the destination type is an array, the object is initialized as
+ // . follows. Let x1, . . . , xk be the elements of the expression-list
+ // ...Let n denote the array size...the ith array element is...value-
+ // initialized for each k < i <= n.
+ InitializationKind SubKind = InitializationKind::CreateValue(
+ Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true);
+ InitializationSequence SubSeq(S, SubEntity, SubKind, std::nullopt);
+ if (SubSeq.Failed()) {
+ if (!VerifyOnly)
+ SubSeq.Diagnose(S, SubEntity, SubKind, std::nullopt);
+ return false;
+ }
+ if (!VerifyOnly) {
+ ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, std::nullopt);
+ if (SubEntity.getKind() == InitializedEntity::EK_ArrayElement) {
+ ArrayFiller = ER.get();
+ return true;
+ }
+ InitExprs.push_back(ER.get());
+ }
+ }
+ }
+ return true;
+ };
+
+ if (const ArrayType *AT =
+ S.getASTContext().getAsArrayType(Entity.getType())) {
+
+ SmallVector<InitializedEntity, 4> ElementEntities;
+ uint64_t ArrayLength;
+ // C++ [dcl.init]p17.5
+ // if the destination type is an array, the object is initialized as
+ // follows. Let x1, . . . , xk be the elements of the expression-list. If
+ // the destination type is an array of unknown bound, it is define as
+ // having k elements.
+ if (const ConstantArrayType *CAT =
+ S.getASTContext().getAsConstantArrayType(Entity.getType()))
+ ArrayLength = CAT->getSize().getZExtValue();
+ else
+ ArrayLength = Args.size();
+
+ if (ArrayLength >= Args.size()) {
+ for (uint64_t I = 0; I < ArrayLength; ++I)
+ ElementEntities.push_back(
+ InitializedEntity::InitializeElement(S.getASTContext(), I, Entity));
+
+ if (!ProcessEntities(ElementEntities))
+ return;
+
+ ResultType = S.Context.getConstantArrayType(
+ AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength),
+ nullptr, ArrayType::Normal, 0);
+ }
+ } else if (auto *RT = Entity.getType()->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ auto BaseRange = map_range(RD->bases(), [&S](auto &base) {
+ return InitializedEntity::InitializeBase(S.getASTContext(), &base, false);
+ });
+ auto FieldRange = map_range(RD->fields(), [](auto *field) {
+ return InitializedEntity::InitializeMember(field);
+ });
+
+ if (!ProcessEntities(BaseRange))
+ return;
+
+ if (!ProcessEntities(FieldRange))
+ return;
+
+ ResultType = Entity.getType();
+ }
+
+ // Not all of the args have been processed, so there must've been more args
+ // then were required to initialize the element.
+ if (ArgIndexToProcess < Args.size()) {
+ Sequence.SetFailed(InitializationSequence::FK_ParenthesizedListInitFailed);
+ if (!VerifyOnly) {
+ QualType T = Entity.getType();
+ int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 3 : 4;
+ SourceRange ExcessInitSR(Args[ArgIndexToProcess]->getBeginLoc(),
+ Args.back()->getEndLoc());
+ S.Diag(Kind.getLocation(), diag::err_excess_initializers)
+ << InitKind << ExcessInitSR;
+ }
+ return;
+ }
+
+ if (VerifyOnly) {
+ Sequence.setSequenceKind(InitializationSequence::NormalSequence);
+ Sequence.AddParenthesizedListInitStep(Entity.getType());
+ } else if (Result) {
+ SourceRange SR = Kind.getParenOrBraceRange();
+ auto *CPLIE = CXXParenListInitExpr::Create(
+ S.getASTContext(), InitExprs, ResultType, Args.size(),
+ Kind.getLocation(), SR.getBegin(), SR.getEnd());
+ if (ArrayFiller)
+ CPLIE->setArrayFiller(ArrayFiller);
+ if (InitializedFieldInUnion)
+ CPLIE->setInitializedFieldInUnion(InitializedFieldInUnion);
+ *Result = CPLIE;
+ S.Diag(Kind.getLocation(),
+ diag::warn_cxx17_compat_aggregate_init_paren_list)
+ << Kind.getLocation() << SR << ResultType;
+ }
+
+ return;
+}
+
/// Attempt a user-defined conversion between two types (C++ [dcl.init]),
/// which enumerates all conversion functions and performs overload resolution
/// to select the best.
@@ -5905,7 +6127,11 @@ void InitializationSequence::InitializeFrom(Sema &S,
TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer),
*this, TreatUnavailableAsInvalid);
AddParenthesizedArrayInitStep(DestType);
- } else if (DestAT->getElementType()->isCharType())
+ } else if (S.getLangOpts().CPlusPlus20 && !TopLevelOfInitList &&
+ Kind.getKind() == InitializationKind::IK_Direct)
+ TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+ /*VerifyOnly=*/true);
+ else if (DestAT->getElementType()->isCharType())
SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
else if (IsWideCharCompatible(DestAT->getElementType(), Context))
SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral);
@@ -5952,18 +6178,53 @@ void InitializationSequence::InitializeFrom(Sema &S,
if (Kind.getKind() == InitializationKind::IK_Direct ||
(Kind.getKind() == InitializationKind::IK_Copy &&
(Context.hasSameUnqualifiedType(SourceType, DestType) ||
- S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType))))
- TryConstructorInitialization(S, Entity, Kind, Args,
- DestType, DestType, *this);
- // - Otherwise (i.e., for the remaining copy-initialization cases),
- // user-defined conversion sequences that can convert from the source
- // type to the destination type or (when a conversion function is
- // used) to a derived class thereof are enumerated as described in
- // 13.3.1.4, and the best one is chosen through overload resolution
- // (13.3).
- else
+ S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType)))) {
+ TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType,
+ *this);
+
+ // We fall back to the "no matching constructor" path if the
+ // failed candidate set has functions other than the three default
+ // constructors. For example, conversion function.
+ if (const auto *RD =
+ dyn_cast<CXXRecordDecl>(DestType->getAs<RecordType>()->getDecl());
+ // In general, we should call isCompleteType for RD to check its
+ // completeness, we don't call it here as it was already called in the
+ // above TryConstructorInitialization.
+ S.getLangOpts().CPlusPlus20 && RD && RD->hasDefinition() &&
+ RD->isAggregate() && Failed() &&
+ getFailureKind() == FK_ConstructorOverloadFailed) {
+ // Do not attempt paren list initialization if overload resolution
+ // resolves to a deleted function .
+ //
+ // We may reach this condition if we have a union wrapping a class with
+ // a non-trivial copy or move constructor and we call one of those two
+ // constructors. The union is an aggregate, but the matched constructor
+ // is implicitly deleted, so we need to prevent aggregate initialization
+ // (otherwise, it'll attempt aggregate initialization by initializing
+ // the first element with a reference to the union).
+ OverloadCandidateSet::iterator Best;
+ OverloadingResult OR = getFailedCandidateSet().BestViableFunction(
+ S, Kind.getLocation(), Best);
+ if (OR != OverloadingResult::OR_Deleted) {
+ // C++20 [dcl.init] 17.6.2.2:
+ // - Otherwise, if no constructor is viable, the destination type is
+ // an
+ // aggregate class, and the initializer is a parenthesized
+ // expression-list.
+ TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+ /*VerifyOnly=*/true);
+ }
+ }
+ } else {
+ // - Otherwise (i.e., for the remaining copy-initialization cases),
+ // user-defined conversion sequences that can convert from the
+ // source type to the destination type or (when a conversion
+ // function is used) to a derived class thereof are enumerated as
+ // described in 13.3.1.4, and the best one is chosen through
+ // overload resolution (13.3).
TryUserDefinedConversion(S, DestType, Kind, Initializer, *this,
TopLevelOfInitList);
+ }
return;
}
@@ -5977,7 +6238,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
llvm::SmallVector<Expr *> InitArgs;
- for (auto Arg : Args) {
+ for (auto *Arg : Args) {
if (Arg->getType()->isExtVectorType()) {
const auto *VTy = Arg->getType()->castAs<ExtVectorType>();
unsigned Elm = VTy->getNumElements();
@@ -7085,11 +7346,11 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
if (auto *CE = dyn_cast<CallExpr>(Call)) {
Callee = CE->getDirectCallee();
- Args = llvm::makeArrayRef(CE->getArgs(), CE->getNumArgs());
+ Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());
} else {
auto *CCE = cast<CXXConstructExpr>(Call);
Callee = CCE->getConstructor();
- Args = llvm::makeArrayRef(CCE->getArgs(), CCE->getNumArgs());
+ Args = llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs());
}
if (!Callee)
return;
@@ -7572,7 +7833,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
case IndirectLocalPathEntry::VarInit:
if (cast<VarDecl>(Path[I].D)->isImplicit())
return SourceRange();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case IndirectLocalPathEntry::DefaultInit:
return Path[I].E->getSourceRange();
@@ -7586,15 +7847,15 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
}
static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
- for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
- if (It->Kind == IndirectLocalPathEntry::VarInit)
+ for (const auto &It : llvm::reverse(Path)) {
+ if (It.Kind == IndirectLocalPathEntry::VarInit)
continue;
- if (It->Kind == IndirectLocalPathEntry::AddressOf)
+ if (It.Kind == IndirectLocalPathEntry::AddressOf)
continue;
- if (It->Kind == IndirectLocalPathEntry::LifetimeBoundCall)
+ if (It.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
continue;
- return It->Kind == IndirectLocalPathEntry::GslPointerInit ||
- It->Kind == IndirectLocalPathEntry::GslReferenceInit;
+ return It.Kind == IndirectLocalPathEntry::GslPointerInit ||
+ It.Kind == IndirectLocalPathEntry::GslReferenceInit;
}
return false;
}
@@ -7846,7 +8107,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
break;
// FIXME: We can't easily tell apart an init-capture from a nested
// capture of an init-capture.
- const VarDecl *VD = Elem.Capture->getCapturedVar();
+ const ValueDecl *VD = Elem.Capture->getCapturedVar();
Diag(Elem.Capture->getLocation(), diag::note_lambda_capture_initializer)
<< VD << VD->isInitCapture() << Elem.Capture->isExplicit()
<< (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD
@@ -8053,19 +8314,29 @@ ExprResult InitializationSequence::Perform(Sema &S,
return ExprError();
}
if (!ZeroInitializationFixit.empty()) {
- unsigned DiagID = diag::err_default_init_const;
- if (Decl *D = Entity.getDecl())
- if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>())
- DiagID = diag::ext_default_init_const;
+ const Decl *D = Entity.getDecl();
+ const auto *VD = dyn_cast_or_null<VarDecl>(D);
+ QualType DestType = Entity.getType();
// The initialization would have succeeded with this fixit. Since the fixit
// is on the error, we need to build a valid AST in this case, so this isn't
// handled in the Failed() branch above.
- QualType DestType = Entity.getType();
- S.Diag(Kind.getLocation(), DiagID)
- << DestType << (bool)DestType->getAs<RecordType>()
- << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
- ZeroInitializationFixit);
+ if (!DestType->isRecordType() && VD && VD->isConstexpr()) {
+ // Use a more useful diagnostic for constexpr variables.
+ S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init)
+ << VD
+ << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
+ ZeroInitializationFixit);
+ } else {
+ unsigned DiagID = diag::err_default_init_const;
+ if (S.getLangOpts().MSVCCompat && D && D->hasAttr<SelectAnyAttr>())
+ DiagID = diag::ext_default_init_const;
+
+ S.Diag(Kind.getLocation(), DiagID)
+ << DestType << (bool)DestType->getAs<RecordType>()
+ << FixItHint::CreateInsertion(ZeroInitializationFixitLoc,
+ ZeroInitializationFixit);
+ }
}
if (getKind() == DependentSequence) {
@@ -8213,6 +8484,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
case SK_ConstructorInitializationFromList:
case SK_StdInitializerListConstructorCall:
case SK_ZeroInitialization:
+ case SK_ParenthesizedListInit:
break;
}
@@ -8739,7 +9011,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
<< Step->Type << CurInit.get()->getType()
<< CurInit.get()->getSourceRange();
updateGNUCompoundLiteralRValue(CurInit.get());
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SK_ArrayInit:
// If the destination type is an incomplete array type, update the
// type accordingly.
@@ -8902,6 +9174,14 @@ ExprResult InitializationSequence::Perform(Sema &S,
CurInit.get()->getValueKind());
break;
}
+ case SK_ParenthesizedListInit: {
+ CurInit = nullptr;
+ TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+ /*VerifyOnly=*/false, &CurInit);
+ if (CurInit.get() && ResultType)
+ *ResultType = CurInit.get()->getType();
+ break;
+ }
}
}
@@ -9104,9 +9384,8 @@ bool InitializationSequence::Diagnose(Sema &S,
<< FixItHint::CreateInsertion(Args.front()->getBeginLoc(), "u8");
break;
case FK_UTF8StringIntoPlainChar:
- S.Diag(Kind.getLocation(),
- diag::err_array_init_utf8_string_into_char)
- << S.getLangOpts().CPlusPlus20;
+ S.Diag(Kind.getLocation(), diag::err_array_init_utf8_string_into_char)
+ << DestType->isSignedIntegerType() << S.getLangOpts().CPlusPlus20;
break;
case FK_ArrayTypeMismatch:
case FK_NonConstantArrayInit:
@@ -9201,7 +9480,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case FK_NonConstLValueReferenceBindingToUnrelated:
S.Diag(Kind.getLocation(),
@@ -9464,6 +9743,10 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Entity.getName();
S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl)
<< Entity.getName();
+ } else if (const auto *VD = dyn_cast_if_present<VarDecl>(Entity.getDecl());
+ VD && VD->isConstexpr()) {
+ S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init)
+ << VD;
} else {
S.Diag(Kind.getLocation(), diag::err_default_init_const)
<< DestType << (bool)DestType->getAs<RecordType>();
@@ -9500,6 +9783,11 @@ bool InitializationSequence::Diagnose(Sema &S,
diag::note_explicit_ctor_deduction_guide_here) << false;
break;
}
+
+ case FK_ParenthesizedListInitFailed:
+ TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this,
+ /*VerifyOnly=*/false);
+ break;
}
PrintInitLocationNote(S, Entity);
@@ -9666,6 +9954,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case FK_ExplicitConstructor:
OS << "list copy initialization chose explicit constructor";
break;
+
+ case FK_ParenthesizedListInitFailed:
+ OS << "parenthesized list initialization failed";
+ break;
}
OS << '\n';
return;
@@ -9837,6 +10129,9 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case SK_OCLZeroOpaqueType:
OS << "OpenCL opaque type from zero";
break;
+ case SK_ParenthesizedListInit:
+ OS << "initialization from a parenthesized list of values";
+ break;
}
OS << " [" << S->Type << ']';
@@ -9868,6 +10163,7 @@ static void DiagnoseNarrowingInInitList(Sema &S,
SCS = &ICS.UserDefined.After;
break;
case ImplicitConversionSequence::AmbiguousConversion:
+ case ImplicitConversionSequence::StaticObjectArgumentConversion:
case ImplicitConversionSequence::EllipsisConversion:
case ImplicitConversionSequence::BadConversion:
return;
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index afc2f3ef4d76..00ab6ba580bf 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -21,6 +21,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -54,17 +55,17 @@ using namespace sema;
/// is at the top of the stack and has the highest index.
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
///
-/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
-/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
-/// which is capture-ready. If the return value evaluates to 'false' then
-/// no lambda is capture-ready for \p VarToCapture.
+/// \returns An std::optional<unsigned> Index that if evaluates to 'true'
+/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost
+/// lambda which is capture-ready. If the return value evaluates to 'false'
+/// then no lambda is capture-ready for \p VarToCapture.
-static inline Optional<unsigned>
+static inline std::optional<unsigned>
getStackIndexOfNearestEnclosingCaptureReadyLambda(
ArrayRef<const clang::sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture) {
+ ValueDecl *VarToCapture) {
// Label failure to capture.
- const Optional<unsigned> NoLambdaIsCaptureReady;
+ const std::optional<unsigned> NoLambdaIsCaptureReady;
// Ignore all inner captured regions.
unsigned CurScopeIndex = FunctionScopes.size() - 1;
@@ -165,18 +166,19 @@ getStackIndexOfNearestEnclosingCaptureReadyLambda(
/// \param VarToCapture - the variable to capture. If NULL, capture 'this'.
///
///
-/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains
-/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda
-/// which is capture-capable. If the return value evaluates to 'false' then
-/// no lambda is capture-capable for \p VarToCapture.
+/// \returns An std::optional<unsigned> Index that if evaluates to 'true'
+/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost
+/// lambda which is capture-capable. If the return value evaluates to 'false'
+/// then no lambda is capture-capable for \p VarToCapture.
-Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
+std::optional<unsigned>
+clang::getStackIndexOfNearestEnclosingCaptureCapableLambda(
ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes,
- VarDecl *VarToCapture, Sema &S) {
+ ValueDecl *VarToCapture, Sema &S) {
- const Optional<unsigned> NoLambdaIsCaptureCapable;
+ const std::optional<unsigned> NoLambdaIsCaptureCapable;
- const Optional<unsigned> OptionalStackIndex =
+ const std::optional<unsigned> OptionalStackIndex =
getStackIndexOfNearestEnclosingCaptureReadyLambda(FunctionScopes,
VarToCapture);
if (!OptionalStackIndex)
@@ -282,7 +284,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
DataMember,
StaticDataMember,
InlineVariable,
- VariableTemplate
+ VariableTemplate,
+ Concept
} Kind = Normal;
// Default arguments of member function parameters that appear in a class
@@ -307,6 +310,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
}
} else if (isa<FieldDecl>(ManglingContextDecl)) {
Kind = DataMember;
+ } else if (isa<ImplicitConceptSpecializationDecl>(ManglingContextDecl)) {
+ Kind = Concept;
}
}
@@ -330,12 +335,17 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
return std::make_tuple(nullptr, nullptr);
}
+ case Concept:
+ // Concept definitions aren't code generated and thus aren't mangled,
+ // however the ManglingContextDecl is important for the purposes of
+ // re-forming the template argument list of the lambda for constraint
+ // evaluation.
case StaticDataMember:
// -- the initializers of nonspecialized static members of template classes
if (!IsInNonspecializedTemplate)
return std::make_tuple(nullptr, ManglingContextDecl);
// Fall through to get the current context.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DataMember:
// -- the in-class initializers of class members
@@ -354,13 +364,11 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
llvm_unreachable("unexpected context");
}
-CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- TypeSourceInfo *MethodTypeInfo,
- SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params,
- ConstexprSpecKind ConstexprKind,
- Expr *TrailingRequiresClause) {
+CXXMethodDecl *Sema::startLambdaDefinition(
+ CXXRecordDecl *Class, SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind,
+ StorageClass SC, Expr *TrailingRequiresClause) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -390,7 +398,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
Context, Class, EndLoc,
DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
MethodNameLoc),
- MethodType, MethodTypeInfo, SC_None, getCurFPFeatures().isFPConstrained(),
+ MethodType, MethodTypeInfo, SC, getCurFPFeatures().isFPConstrained(),
/*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause);
Method->setAccess(AS_public);
if (!TemplateParams)
@@ -418,7 +426,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
CheckParmsForFunctionDef(Params,
/*CheckParameterNames=*/false);
- for (auto P : Method->parameters())
+ for (auto *P : Method->parameters())
P->setOwningFunction(Method);
}
@@ -427,7 +435,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
void Sema::handleLambdaNumbering(
CXXRecordDecl *Class, CXXMethodDecl *Method,
- Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
+ std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
if (Mangling) {
bool HasKnownInternalLinkage;
unsigned ManglingNumber, DeviceManglingNumber;
@@ -769,8 +777,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
if (Context.getCanonicalFunctionResultType(ReturnType) ==
Context.getCanonicalFunctionResultType(CSI.ReturnType)) {
// Use the return type with the strictest possible nullability annotation.
- auto RetTyNullability = ReturnType->getNullability(Ctx);
- auto BlockNullability = CSI.ReturnType->getNullability(Ctx);
+ auto RetTyNullability = ReturnType->getNullability();
+ auto BlockNullability = CSI.ReturnType->getNullability();
if (BlockNullability &&
(!RetTyNullability ||
hasWeakerNullability(*RetTyNullability, *BlockNullability)))
@@ -789,8 +797,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
QualType Sema::buildLambdaInitCaptureInitialization(
SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool IsDirectInit,
- Expr *&Init) {
+ std::optional<unsigned> NumExpansions, IdentifierInfo *Id,
+ bool IsDirectInit, Expr *&Init) {
// Create an 'auto' or 'auto&' TypeSourceInfo that we can use to
// deduce against.
QualType DeductType = Context.getAutoDeductType();
@@ -881,11 +889,12 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
return NewVD;
}
-void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var) {
+void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var,
+ bool isReferenceType) {
assert(Var->isInitCapture() && "init capture flag should be set");
- LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(),
- /*isNested*/false, Var->getLocation(), SourceLocation(),
- Var->getType(), /*Invalid*/false);
+ LSI->addCapture(Var, /*isBlock*/ false, isReferenceType,
+ /*isNested*/ false, Var->getLocation(), SourceLocation(),
+ Var->getType(), /*Invalid*/ false);
}
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
@@ -917,6 +926,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
SmallVector<ParmVarDecl *, 8> Params;
+
+ assert(
+ (ParamInfo.getDeclSpec().getStorageClassSpec() ==
+ DeclSpec::SCS_unspecified ||
+ ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) &&
+ "Unexpected storage specifier");
+ bool IsLambdaStatic =
+ ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static;
+
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
@@ -938,8 +956,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
QualType DefaultTypeForNoTrailingReturn =
getLangOpts().CPlusPlus14 ? Context.getAutoDeductType()
: Context.DependentTy;
- QualType MethodTy =
- Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
+ QualType MethodTy = Context.getFunctionType(DefaultTypeForNoTrailingReturn,
+ std::nullopt, EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false;
ExplicitResultType = false;
@@ -953,7 +971,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// This function call operator is declared const (9.3.1) if and only if
// the lambda-expression's parameter-declaration-clause is not followed
// by mutable. It is neither virtual nor declared volatile. [...]
- if (!FTI.hasMutableQualifier()) {
+ if (!FTI.hasMutableQualifier() && !IsLambdaStatic) {
FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const,
SourceLocation());
}
@@ -964,6 +982,18 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ExplicitResultType = FTI.hasTrailingReturnType();
+ if (ExplicitResultType && getLangOpts().HLSL) {
+ QualType RetTy = FTI.getTrailingReturnType().get();
+ if (!RetTy.isNull()) {
+ // HLSL does not support specifying an address space on a lambda return
+ // type.
+ LangAS AddressSpace = RetTy.getAddressSpace();
+ if (AddressSpace != LangAS::Default)
+ Diag(FTI.getTrailingReturnTypeLoc(),
+ diag::err_return_value_with_address_space);
+ }
+ }
+
if (FTIHasNonVoidParameters(FTI)) {
Params.reserve(FTI.NumParams);
for (unsigned i = 0, e = FTI.NumParams; i != e; ++i)
@@ -981,6 +1011,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier(),
+ IsLambdaStatic ? SC_Static : SC_None,
ParamInfo.getTrailingRequiresClause());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -1088,7 +1119,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->Init.isInvalid())
continue;
- VarDecl *Var = nullptr;
+ ValueDecl *Var = nullptr;
if (C->Init.isUsable()) {
Diag(C->Loc, getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_init_capture
@@ -1166,7 +1197,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
- Var = R.getAsSingle<VarDecl>();
+ if (auto *BD = R.getAsSingle<BindingDecl>())
+ Var = BD;
+ else
+ Var = R.getAsSingle<VarDecl>();
if (Var && DiagnoseUseOfDecl(Var, C->Loc))
continue;
}
@@ -1200,7 +1234,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (Var->isInvalidDecl())
continue;
- if (!Var->hasLocalStorage()) {
+ VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl();
+
+ if (!Underlying->hasLocalStorage()) {
Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id;
Diag(Var->getLocation(), diag::note_previous_decl) << C->Id;
continue;
@@ -1224,7 +1260,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
if (C->Init.isUsable()) {
- addInitCapture(LSI, Var);
+ addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef);
} else {
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
TryCapture_ExplicitByVal;
@@ -1374,7 +1410,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
ConvExtInfo.TypeQuals.addConst();
ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept;
QualType ConvTy =
- S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
+ S.Context.getFunctionType(PtrToFunctionTy, std::nullopt, ConvExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName ConversionName
@@ -1470,45 +1506,50 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange,
Class->addDecl(ConversionTemplate);
} else
Class->addDecl(Conversion);
- // Add a non-static member function that will be the result of
- // the conversion with a certain unique ID.
- DeclarationName InvokerName = &S.Context.Idents.get(
- getLambdaStaticInvokerName());
- // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
- // we should get a prebuilt TrivialTypeSourceInfo from Context
- // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
- // then rewire the parameters accordingly, by hoisting up the InvokeParams
- // loop below and then use its Params to set Invoke->setParams(...) below.
- // This would avoid the 'const' qualifier of the calloperator from
- // contaminating the type of the invoker, which is currently adjusted
- // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
- // trailing return type of the invoker would require a visitor to rebuild
- // the trailing return type and adjusting all back DeclRefExpr's to refer
- // to the new static invoker parameters - not the call operator's.
- CXXMethodDecl *Invoke = CXXMethodDecl::Create(
- S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
- InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
- S.getCurFPFeatures().isFPConstrained(),
- /*isInline=*/true, ConstexprSpecKind::Unspecified,
- CallOperator->getBody()->getEndLoc());
- for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
- InvokerParams[I]->setOwningFunction(Invoke);
- Invoke->setParams(InvokerParams);
- Invoke->setAccess(AS_private);
- Invoke->setImplicit(true);
- if (Class->isGenericLambda()) {
- FunctionTemplateDecl *TemplateCallOperator =
- CallOperator->getDescribedFunctionTemplate();
- FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
- S.Context, Class, Loc, InvokerName,
- TemplateCallOperator->getTemplateParameters(),
- Invoke);
- StaticInvokerTemplate->setAccess(AS_private);
- StaticInvokerTemplate->setImplicit(true);
- Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
- Class->addDecl(StaticInvokerTemplate);
- } else
- Class->addDecl(Invoke);
+
+ // If the lambda is not static, we need to add a static member
+ // function that will be the result of the conversion with a
+ // certain unique ID.
+ // When it is static we just return the static call operator instead.
+ if (CallOperator->isInstance()) {
+ DeclarationName InvokerName =
+ &S.Context.Idents.get(getLambdaStaticInvokerName());
+ // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
+ // we should get a prebuilt TrivialTypeSourceInfo from Context
+ // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
+ // then rewire the parameters accordingly, by hoisting up the InvokeParams
+ // loop below and then use its Params to set Invoke->setParams(...) below.
+ // This would avoid the 'const' qualifier of the calloperator from
+ // contaminating the type of the invoker, which is currently adjusted
+ // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
+ // trailing return type of the invoker would require a visitor to rebuild
+ // the trailing return type and adjusting all back DeclRefExpr's to refer
+ // to the new static invoker parameters - not the call operator's.
+ CXXMethodDecl *Invoke = CXXMethodDecl::Create(
+ S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
+ InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
+ S.getCurFPFeatures().isFPConstrained(),
+ /*isInline=*/true, ConstexprSpecKind::Unspecified,
+ CallOperator->getBody()->getEndLoc());
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
+ InvokerParams[I]->setOwningFunction(Invoke);
+ Invoke->setParams(InvokerParams);
+ Invoke->setAccess(AS_private);
+ Invoke->setImplicit(true);
+ if (Class->isGenericLambda()) {
+ FunctionTemplateDecl *TemplateCallOperator =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *StaticInvokerTemplate =
+ FunctionTemplateDecl::Create(
+ S.Context, Class, Loc, InvokerName,
+ TemplateCallOperator->getTemplateParameters(), Invoke);
+ StaticInvokerTemplate->setAccess(AS_private);
+ StaticInvokerTemplate->setImplicit(true);
+ Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate);
+ Class->addDecl(StaticInvokerTemplate);
+ } else
+ Class->addDecl(Invoke);
+ }
}
/// Add a lambda's conversion to function pointers, as described in
@@ -1546,7 +1587,8 @@ static void addBlockPointerConversion(Sema &S,
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
ConversionEPI.TypeQuals = Qualifiers();
ConversionEPI.TypeQuals.addConst();
- QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ConversionEPI);
+ QualType ConvTy =
+ S.Context.getFunctionType(BlockPtrTy, std::nullopt, ConversionEPI);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -1574,7 +1616,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
// An init-capture is initialized directly from its stored initializer.
if (Cap.isInitCapture())
- return Cap.getVariable()->getInit();
+ return cast<VarDecl>(Cap.getVariable())->getInit();
// For anything else, build an initialization expression. For an implicit
// capture, the capture notionally happens at the capture-default, so use
@@ -1605,7 +1647,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap,
Init = This;
} else {
assert(Cap.isVariableCapture() && "unknown kind of capture");
- VarDecl *Var = Cap.getVariable();
+ ValueDecl *Var = Cap.getVariable();
Name = Var->getIdentifier();
Init = BuildDeclarationNameExpr(
CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var);
@@ -1654,7 +1696,7 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) {
bool Sema::CaptureHasSideEffects(const Capture &From) {
if (From.isInitCapture()) {
- Expr *Init = From.getVariable()->getInit();
+ Expr *Init = cast<VarDecl>(From.getVariable())->getInit();
if (Init && Init->HasSideEffects(Context))
return true;
}
@@ -1704,9 +1746,9 @@ FieldDecl *Sema::BuildCaptureField(RecordDecl *RD,
TypeSourceInfo *TSI = nullptr;
if (Capture.isVariableCapture()) {
- auto *Var = Capture.getVariable();
- if (Var->isInitCapture())
- TSI = Capture.getVariable()->getTypeSourceInfo();
+ const auto *Var = dyn_cast_or_null<VarDecl>(Capture.getVariable());
+ if (Var && Var->isInitCapture())
+ TSI = Var->getTypeSourceInfo();
}
// FIXME: Should we really be doing this? A null TypeSourceInfo seems more
@@ -1854,7 +1896,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType);
} else {
assert(From.isVariableCapture() && "unknown kind of capture");
- VarDecl *Var = From.getVariable();
+ ValueDecl *Var = From.getVariable();
LambdaCaptureKind Kind =
From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef;
return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var,
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 68158ec977cf..b2e943699c5f 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -40,10 +40,12 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/edit_distance.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <iterator>
#include <list>
+#include <optional>
#include <set>
#include <utility>
#include <vector>
@@ -156,7 +158,7 @@ namespace {
void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) {
SmallVector<DeclContext*, 4> queue;
while (true) {
- for (auto UD : DC->using_directives()) {
+ for (auto *UD : DC->using_directives()) {
DeclContext *NS = UD->getNominatedNamespace();
if (SemaRef.isVisible(UD) && visited.insert(NS).second) {
addUsingDirective(UD, EffectiveDC);
@@ -519,12 +521,13 @@ void LookupResult::resolveKind() {
D = cast<NamedDecl>(D->getCanonicalDecl());
// Ignore an invalid declaration unless it's the only one left.
- if (D->isInvalidDecl() && !(I == 0 && N == 1)) {
+ // Also ignore HLSLBufferDecl which not have name conflict with other Decls.
+ if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) && !(I == 0 && N == 1)) {
Decls[I] = Decls[--N];
continue;
}
- llvm::Optional<unsigned> ExistingI;
+ std::optional<unsigned> ExistingI;
// Redeclarations of types via typedef can occur both within a scope
// and, through using declarations and directives, across scopes. There is
@@ -939,11 +942,9 @@ bool Sema::LookupBuiltin(LookupResult &R) {
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {
- // In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any
- // predefined library functions like 'malloc'. Instead, we'll just
- // error.
- if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL ||
- getLangOpts().C2x) &&
+ // 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 ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) &&
Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
@@ -1179,9 +1180,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C);
EPI.ExceptionSpec = EST_None;
- QualType ExpectedType
- = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
- None, EPI);
+ QualType ExpectedType = R.getSema().Context.getFunctionType(
+ R.getLookupName().getCXXNameType(), std::nullopt, EPI);
// Perform template argument deduction against the type that we would
// expect the function to have.
@@ -1624,10 +1624,8 @@ hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D,
if (!D->hasDefaultArgument())
return false;
- llvm::SmallDenseSet<const ParmDecl *, 4> Visited;
- while (D && !Visited.count(D)) {
- Visited.insert(D);
-
+ llvm::SmallPtrSet<const ParmDecl *, 4> Visited;
+ while (D && Visited.insert(D).second) {
auto &DefaultArg = D->getDefaultArgStorage();
if (!DefaultArg.isInherited() && S.isAcceptable(D, Kind))
return true;
@@ -1920,12 +1918,7 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) {
// If D comes from a module and SemaRef doesn't own a module, it implies D
// comes from another TU. In case SemaRef owns a module, we could judge if D
// comes from another TU by comparing the module unit.
- //
- // FIXME: It would look better if we have direct method to judge whether D is
- // in another TU.
- if (SemaRef.getCurrentModule() &&
- SemaRef.getCurrentModule()->getTopLevelModule() ==
- DeclModule->getTopLevelModule())
+ if (SemaRef.isModuleUnitOfCurrentTU(DeclModule))
return true;
// [module.reach]/p3:
@@ -2023,7 +2016,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D,
unsigned IDNS) {
assert(!LookupResult::isAvailableForLookup(SemaRef, D) && "not in slow case");
- for (auto RD : D->redecls()) {
+ for (auto *RD : D->redecls()) {
// Don't bother with extra checks if we already know this one isn't visible.
if (RD == D)
continue;
@@ -2107,6 +2100,22 @@ bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) {
if (auto *DeductionGuide = ND->getDeclName().getCXXDeductionGuideTemplate())
return SemaRef.hasReachableDefinition(DeductionGuide);
+ // FIXME: The lookup for allocation function is a standalone process.
+ // (We can find the logics in Sema::FindAllocationFunctions)
+ //
+ // Such structure makes it a problem when we instantiate a template
+ // declaration using placement allocation function if the placement
+ // allocation function is invisible.
+ // (See https://github.com/llvm/llvm-project/issues/59601)
+ //
+ // Here we workaround it by making the placement allocation functions
+ // always acceptable. The downside is that we can't diagnose the direct
+ // use of the invisible placement allocation functions. (Although such uses
+ // should be rare).
+ if (auto *FD = dyn_cast<FunctionDecl>(ND);
+ FD && FD->isReservedGlobalPlacementOperator())
+ return true;
+
auto *DC = ND->getDeclContext();
// If ND is not visible and it is at namespace scope, it shouldn't be found
// by name lookup.
@@ -2367,7 +2376,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
continue;
}
- for (auto I : ND->using_directives()) {
+ for (auto *I : ND->using_directives()) {
NamespaceDecl *Nom = I->getNominatedNamespace();
if (S.isVisible(I) && Visited.insert(Nom).second)
Queue.push_back(Nom);
@@ -3147,7 +3156,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
for (const auto &Arg : Proto->param_types())
Queue.push_back(Arg.getTypePtr());
// fallthrough
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case Type::FunctionNoProto: {
const FunctionType *FnType = cast<FunctionType>(T);
@@ -3477,27 +3486,27 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
- llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ llvm::ArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
- llvm::makeArrayRef(&Arg, NumArgs), OCS,
+ llvm::ArrayRef(&Arg, NumArgs), OCS,
/*SuppressUserConversions*/ true);
else
- AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
+ AddOverloadCandidate(M, Cand, llvm::ArrayRef(&Arg, NumArgs), OCS,
/*SuppressUserConversions*/ true);
} else if (FunctionTemplateDecl *Tmpl =
dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
- AddMethodTemplateCandidate(
- Tmpl, Cand, RD, nullptr, ThisTy, Classification,
- llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ AddMethodTemplateCandidate(Tmpl, Cand, RD, nullptr, ThisTy,
+ Classification,
+ llvm::ArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
- AddTemplateOverloadCandidate(
- CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
- llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ AddTemplateOverloadCandidate(CtorInfo.ConstructorTmpl,
+ CtorInfo.FoundDecl, nullptr,
+ llvm::ArrayRef(&Arg, NumArgs), OCS, true);
else
- AddTemplateOverloadCandidate(
- Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ AddTemplateOverloadCandidate(Tmpl, Cand, nullptr,
+ llvm::ArrayRef(&Arg, NumArgs), OCS, true);
} else {
assert(isa<UsingDecl>(Cand.getDecl()) &&
"illegal Kind of operator = Decl");
@@ -3620,9 +3629,10 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class,
///
/// \returns The destructor for this class.
CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) {
- return cast<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor,
- false, false, false,
- false, false).getMethod());
+ return cast_or_null<CXXDestructorDecl>(
+ LookupSpecialMember(Class, CXXDestructor, false, false, false, false,
+ false)
+ .getMethod());
}
/// LookupLiteralOperator - Determine which literal operator should be used for
@@ -3696,11 +3706,11 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
// is a well-formed template argument for the template parameter.
if (StringLit) {
SFINAETrap Trap(*this);
- SmallVector<TemplateArgument, 1> Checked;
+ SmallVector<TemplateArgument, 1> SugaredChecked, CanonicalChecked;
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
- if (CheckTemplateArgument(Params->getParam(0), Arg, FD,
- R.getNameLoc(), R.getNameLoc(), 0,
- Checked) ||
+ if (CheckTemplateArgument(
+ Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
+ 0, SugaredChecked, CanonicalChecked, CTAK_Specified) ||
Trap.hasErrorOccurred())
IsTemplate = false;
}
@@ -4166,7 +4176,7 @@ private:
// Traverse using directives for qualified name lookup.
if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
- for (auto I : Ctx->using_directives()) {
+ for (auto *I : Ctx->using_directives()) {
if (!Result.getSema().isVisible(I))
continue;
lookupInDeclContext(I->getNominatedNamespace(), Result,
@@ -4939,9 +4949,9 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier(
if (NNS && !CurNameSpecifierIdentifiers.empty()) {
SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers;
getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers);
- NumSpecifiers = llvm::ComputeEditDistance(
- llvm::makeArrayRef(CurNameSpecifierIdentifiers),
- llvm::makeArrayRef(NewNameSpecifierIdentifiers));
+ NumSpecifiers =
+ llvm::ComputeEditDistance(llvm::ArrayRef(CurNameSpecifierIdentifiers),
+ llvm::ArrayRef(NewNameSpecifierIdentifiers));
}
SpecifierInfo SI = {Ctx, NNS, NumSpecifiers};
@@ -5028,9 +5038,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
"extern", "inline", "static", "typedef"
};
- const unsigned NumCTypeSpecs = llvm::array_lengthof(CTypeSpecs);
- for (unsigned I = 0; I != NumCTypeSpecs; ++I)
- Consumer.addKeywordResult(CTypeSpecs[I]);
+ for (const auto *CTS : CTypeSpecs)
+ Consumer.addKeywordResult(CTS);
if (SemaRef.getLangOpts().C99)
Consumer.addKeywordResult("restrict");
@@ -5082,9 +5091,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
static const char *const CXXExprs[] = {
"delete", "new", "operator", "throw", "typeid"
};
- const unsigned NumCXXExprs = llvm::array_lengthof(CXXExprs);
- for (unsigned I = 0; I != NumCXXExprs; ++I)
- Consumer.addKeywordResult(CXXExprs[I]);
+ for (const auto *CE : CXXExprs)
+ Consumer.addKeywordResult(CE);
if (isa<CXXMethodDecl>(SemaRef.CurContext) &&
cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance())
@@ -5108,9 +5116,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
// Statements.
static const char *const CStmts[] = {
"do", "else", "for", "goto", "if", "return", "switch", "while" };
- const unsigned NumCStmts = llvm::array_lengthof(CStmts);
- for (unsigned I = 0; I != NumCStmts; ++I)
- Consumer.addKeywordResult(CStmts[I]);
+ for (const auto *CS : CStmts)
+ Consumer.addKeywordResult(CS);
if (SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("catch");
@@ -5699,7 +5706,7 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
llvm::SmallVector<Module*, 8> UniqueModules;
llvm::SmallDenseSet<Module*, 8> UniqueModuleSet;
for (auto *M : Modules) {
- if (M->Kind == Module::GlobalModuleFragment)
+ if (M->isGlobalModule() || M->isPrivateModule())
continue;
if (UniqueModuleSet.insert(M).second)
UniqueModules.push_back(M);
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index f5c24bd10daa..f52c0247f01c 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -15,6 +15,7 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/SemaInternal.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -119,12 +120,12 @@ void Sema::HandleStartOfHeaderUnit() {
// TODO: Make the C++20 header lookup independent.
// When the input is pre-processed source, we need a file ref to the original
// file for the header map.
- auto F = SourceMgr.getFileManager().getFile(HUName);
+ auto F = SourceMgr.getFileManager().getOptionalFileRef(HUName);
// For the sake of error recovery (if someone has moved the original header
// after creating the pre-processed output) fall back to obtaining the file
// ref for the input file, which must be present.
if (!F)
- F = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+ F = SourceMgr.getFileEntryRefForID(SourceMgr.getMainFileID());
assert(F && "failed to find the header unit source?");
Module::Header H{HUName.str(), HUName.str(), *F};
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
@@ -144,6 +145,36 @@ void Sema::HandleStartOfHeaderUnit() {
TU->setLocalOwningModule(Mod);
}
+/// Tests whether the given identifier is reserved as a module name and
+/// diagnoses if it is. Returns true if a diagnostic is emitted and false
+/// otherwise.
+static bool DiagReservedModuleName(Sema &S, const IdentifierInfo *II,
+ SourceLocation Loc) {
+ enum {
+ Valid = -1,
+ Invalid = 0,
+ Reserved = 1,
+ } Reason = Valid;
+
+ if (II->isStr("module") || II->isStr("import"))
+ Reason = Invalid;
+ else if (II->isReserved(S.getLangOpts()) !=
+ ReservedIdentifierStatus::NotReserved)
+ Reason = Reserved;
+
+ // If the identifier is reserved (not invalid) but is in a system header,
+ // we do not diagnose (because we expect system headers to use reserved
+ // identifiers).
+ if (Reason == Reserved && S.getSourceManager().isInSystemHeader(Loc))
+ Reason = Valid;
+
+ if (Reason != Valid) {
+ S.Diag(Loc, diag::err_invalid_module_name) << II << (int)Reason;
+ return true;
+ }
+ return false;
+}
+
Sema::DeclGroupPtrTy
Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
ModuleDeclKind MDK, ModuleIdPath Path,
@@ -195,9 +226,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
Diag(ModuleLoc, diag::err_module_decl_in_module_map_module);
return nullptr;
- case LangOptions::CMK_HeaderModule:
case LangOptions::CMK_HeaderUnit:
- Diag(ModuleLoc, diag::err_module_decl_in_header_module);
+ Diag(ModuleLoc, diag::err_module_decl_in_header_unit);
return nullptr;
}
@@ -207,22 +237,15 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
// here, in order to support macro import.
// Only one module-declaration is permitted per source file.
- if (!ModuleScopes.empty() &&
- ModuleScopes.back().Module->isModulePurview()) {
+ if (isCurrentModulePurview()) {
Diag(ModuleLoc, diag::err_module_redeclaration);
Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module),
diag::note_prev_module_declaration);
return nullptr;
}
- // Find the global module fragment we're adopting into this module, if any.
- Module *GlobalModuleFragment = nullptr;
- if (!ModuleScopes.empty() &&
- ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment)
- GlobalModuleFragment = ModuleScopes.back().Module;
-
assert((!getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS ||
- SeenGMF == (bool)GlobalModuleFragment) &&
+ SeenGMF == (bool)this->GlobalModuleFragment) &&
"mismatched global module state");
// In C++20, the module-declaration must be the first declaration if there
@@ -239,6 +262,32 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
}
}
+ // C++2b [module.unit]p1: ... The identifiers module and import shall not
+ // appear as identifiers in a module-name or module-partition. All
+ // module-names either beginning with an identifier consisting of std
+ // followed by zero or more digits or containing a reserved identifier
+ // ([lex.name]) are reserved and shall not be specified in a
+ // module-declaration; no diagnostic is required.
+
+ // Test the first part of the path to see if it's std[0-9]+ but allow the
+ // name in a system header.
+ StringRef FirstComponentName = Path[0].first->getName();
+ if (!getSourceManager().isInSystemHeader(Path[0].second) &&
+ (FirstComponentName == "std" ||
+ (FirstComponentName.startswith("std") &&
+ llvm::all_of(FirstComponentName.drop_front(3), &llvm::isDigit)))) {
+ Diag(Path[0].second, diag::err_invalid_module_name)
+ << Path[0].first << /*reserved*/ 1;
+ return nullptr;
+ }
+
+ // Then test all of the components in the path to see if any of them are
+ // using another kind of reserved or invalid identifier.
+ for (auto Part : Path) {
+ if (DiagReservedModuleName(*this, Part.first, Part.second))
+ return nullptr;
+ }
+
// Flatten the dots in a module name. Unlike Clang's hierarchical module map
// modules, the dots here are just another character that can appear in a
// module name.
@@ -272,7 +321,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
Diag(Path[0].second, diag::err_module_redefinition) << ModuleName;
if (M->DefinitionLoc.isValid())
Diag(M->DefinitionLoc, diag::note_prev_module_definition);
- else if (Optional<FileEntryRef> FE = M->getASTFile())
+ else if (OptionalFileEntryRef FE = M->getASTFile())
Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file)
<< FE->getName();
Mod = M;
@@ -280,8 +329,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
}
// Create a Module for the module that we're defining.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- GlobalModuleFragment);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
if (MDK == ModuleDeclKind::PartitionInterface)
Mod->Kind = Module::ModulePartitionInterface;
assert(Mod && "module creation should not fail");
@@ -301,21 +349,19 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc,
if (!Mod) {
Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName;
// Create an empty module interface unit for error recovery.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- GlobalModuleFragment);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
}
} break;
case ModuleDeclKind::PartitionImplementation:
// Create an interface, but note that it is an implementation
// unit.
- Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName,
- GlobalModuleFragment);
+ Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName);
Mod->Kind = Module::ModulePartitionImplementation;
break;
}
- if (!GlobalModuleFragment) {
+ if (!this->GlobalModuleFragment) {
ModuleScopes.push_back({});
if (getLangOpts().ModulesLocalVisibility)
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
@@ -495,7 +541,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
// of the same top-level module. Until we do, make it an error rather than
// silently ignoring the import.
// FIXME: Should we warn on a redundant import of the current module?
- if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule &&
+ if (Mod->isForBuilding(getLangOpts()) &&
(getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) {
Diag(ImportLoc, getLangOpts().isCompilingModule()
? diag::err_module_self_import
@@ -545,9 +591,6 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
(ModuleScopes.back().ModuleInterface ||
(getLangOpts().CPlusPlusModules &&
ModuleScopes.back().Module->isGlobalModule()))) {
- assert((!ModuleScopes.back().Module->isGlobalModule() ||
- Mod->Kind == Module::ModuleKind::ModuleHeaderUnit) &&
- "should only be importing a header unit into the GMF");
// Re-export the module if the imported module is exported.
// Note that we don't need to add re-exported module to Imports field
// since `Exports` implies the module is imported already.
@@ -562,11 +605,6 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
Diag(ExportLoc, diag::err_export_not_in_module_interface)
<< (!ModuleScopes.empty() &&
!ModuleScopes.back().ImplicitGlobalModuleFragment);
- } else if (getLangOpts().isCompilingModule()) {
- Module *ThisModule = PP.getHeaderSearchInfo().lookupModule(
- getLangOpts().CurrentModule, ExportLoc, false, false);
- (void)ThisModule;
- assert(ThisModule && "was expecting a module if building one");
}
// In some cases we need to know if an entity was present in a directly-
@@ -717,7 +755,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
// An export-declaration shall appear only [...] in the purview of a module
// interface unit. An export-declaration shall not appear directly or
// indirectly within [...] a private-module-fragment.
- if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) {
+ if (!isCurrentModulePurview()) {
Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0;
D->setInvalidDecl();
return D;
@@ -786,7 +824,7 @@ enum class UnnamedDeclKind {
};
}
-static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) {
+static std::optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) {
if (isa<EmptyDecl>(D))
return UnnamedDeclKind::Empty;
if (isa<StaticAssertDecl>(D))
@@ -796,7 +834,7 @@ static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) {
if (isa<UsingDirectiveDecl>(D))
return UnnamedDeclKind::UsingDirective;
// Everything else either introduces one or more names or is ill-formed.
- return llvm::None;
+ return std::nullopt;
}
unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) {
@@ -911,6 +949,17 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) {
diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child,
BlockStart);
}
+ if (auto *FD = dyn_cast<FunctionDecl>(Child)) {
+ // [dcl.inline]/7
+ // If an inline function or variable that is attached to a named module
+ // is declared in a definition domain, it shall be defined in that
+ // domain.
+ // So, if the current declaration does not have a definition, we must
+ // check at the end of the TU (or when the PMF starts) to see that we
+ // have a definition at that point.
+ if (FD->isInlineSpecified() && !FD->isDefined())
+ PendingInlineFuncDecls.insert(FD);
+ }
}
}
diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp
index 118afb81dd72..584c4a31793c 100644
--- a/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/clang/lib/Sema/SemaObjCProperty.cpp
@@ -1028,7 +1028,7 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
// Find the corresponding property in the primary class definition.
auto OrigClass = Category->getClassInterface();
- for (auto Found : OrigClass->lookup(Prop->getDeclName())) {
+ for (auto *Found : OrigClass->lookup(Prop->getDeclName())) {
if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found))
return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
}
@@ -1822,9 +1822,8 @@ CollectImmediateProperties(ObjCContainerDecl *CDecl,
static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
ObjCInterfaceDecl::PropertyMap &PropMap) {
if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
- ObjCInterfaceDecl::PropertyDeclOrder PO;
while (SDecl) {
- SDecl->collectPropertiesToImplement(PropMap, PO);
+ SDecl->collectPropertiesToImplement(PropMap);
SDecl = SDecl->getSuperClass();
}
}
@@ -1889,15 +1888,14 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl,
ObjCInterfaceDecl *IDecl,
SourceLocation AtEnd) {
ObjCInterfaceDecl::PropertyMap PropMap;
- ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
- IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
+ IDecl->collectPropertiesToImplement(PropMap);
if (PropMap.empty())
return;
ObjCInterfaceDecl::PropertyMap SuperPropMap;
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) {
- ObjCPropertyDecl *Prop = PropertyOrder[i];
+ for (const auto &PropEntry : PropMap) {
+ ObjCPropertyDecl *Prop = PropEntry.second;
// Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->isClassProperty() ||
@@ -2046,8 +2044,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
// its primary class (and its super classes) if property is
// declared in one of those containers.
if ((IDecl = C->getClassInterface())) {
- ObjCInterfaceDecl::PropertyDeclOrder PO;
- IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
+ IDecl->collectPropertiesToImplement(NoNeedToImplPropMap);
}
}
if (IDecl)
@@ -2574,7 +2571,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
/*TInfo=*/nullptr,
SC_None,
nullptr);
- SetterMethod->setMethodParams(Context, Argument, None);
+ SetterMethod->setMethodParams(Context, Argument, std::nullopt);
AddPropertyAttrs(*this, SetterMethod, property);
@@ -2757,7 +2754,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
if (Attributes & ObjCPropertyAttribute::kind_weak) {
// 'weak' and 'nonnull' are mutually exclusive.
- if (auto nullability = PropertyTy->getNullability(Context)) {
+ if (auto nullability = PropertyTy->getNullability()) {
if (*nullability == NullabilityKind::NonNull)
Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
<< "nonnull" << "weak";
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index dc1470bf7a9d..c767341d922b 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -39,6 +39,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include <optional>
#include <set>
using namespace clang;
@@ -172,7 +173,8 @@ private:
/// First argument (Expr *) contains optional argument of the
/// 'ordered' clause, the second one is true if the regions has 'ordered'
/// clause, false otherwise.
- llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
+ std::optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
+ bool RegionHasOrderConcurrent = false;
unsigned AssociatedLoops = 1;
bool HasMutipleLoops = false;
const Decl *PossiblyLoopCounter = nullptr;
@@ -213,6 +215,7 @@ private:
llvm::SmallVector<ImplicitDefaultFDInfoTy, 8>
ImplicitDefaultFirstprivateFDs;
Expr *DeclareMapperVar = nullptr;
+ SmallVector<VarDecl *, 16> IteratorVarDecls;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -847,7 +850,7 @@ public:
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
if (const SharingMapTy *Top = getTopOfStackOrNull())
if (Top->OrderedRegion)
- return Top->OrderedRegion.value();
+ return *Top->OrderedRegion;
return std::make_pair(nullptr, nullptr);
}
/// Returns true, if parent region is ordered (has associated
@@ -862,9 +865,20 @@ public:
getParentOrderedRegionParam() const {
if (const SharingMapTy *Parent = getSecondOnStackOrNull())
if (Parent->OrderedRegion)
- return Parent->OrderedRegion.value();
+ return *Parent->OrderedRegion;
return std::make_pair(nullptr, nullptr);
}
+ /// Marks current region as having an 'order' clause.
+ void setRegionHasOrderConcurrent(bool HasOrderConcurrent) {
+ getTopOfStack().RegionHasOrderConcurrent = HasOrderConcurrent;
+ }
+ /// Returns true, if parent region is order (has associated
+ /// 'order' clause), false - otherwise.
+ bool isParentOrderConcurrent() const {
+ if (const SharingMapTy *Parent = getSecondOnStackOrNull())
+ return Parent->RegionHasOrderConcurrent;
+ return false;
+ }
/// Marks current region as nowait (it has a 'nowait' clause).
void setNowaitRegion(bool IsNowait = true) {
getTopOfStack().NowaitRegion = IsNowait;
@@ -1114,19 +1128,20 @@ public:
}
/// Checks if specified decl is used in uses allocator clause as the
/// allocator.
- Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(unsigned Level,
- const Decl *D) const {
+ std::optional<UsesAllocatorsDeclKind>
+ isUsesAllocatorsDecl(unsigned Level, const Decl *D) const {
const SharingMapTy &StackElem = getTopOfStack();
auto I = StackElem.UsesAllocatorsDecls.find(D);
if (I == StackElem.UsesAllocatorsDecls.end())
- return None;
+ return std::nullopt;
return I->getSecond();
}
- Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(const Decl *D) const {
+ std::optional<UsesAllocatorsDeclKind>
+ isUsesAllocatorsDecl(const Decl *D) const {
const SharingMapTy &StackElem = getTopOfStack();
auto I = StackElem.UsesAllocatorsDecls.find(D);
if (I == StackElem.UsesAllocatorsDecls.end())
- return None;
+ return std::nullopt;
return I->getSecond();
}
@@ -1138,6 +1153,22 @@ public:
const SharingMapTy *Top = getTopOfStackOrNull();
return Top ? Top->DeclareMapperVar : nullptr;
}
+
+ /// Add a new iterator variable.
+ void addIteratorVarDecl(VarDecl *VD) {
+ SharingMapTy &StackElem = getTopOfStack();
+ StackElem.IteratorVarDecls.push_back(VD->getCanonicalDecl());
+ }
+ /// Check if variable declaration is an iterator VarDecl.
+ bool isIteratorVarDecl(const VarDecl *VD) const {
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ if (!Top)
+ return false;
+
+ return llvm::any_of(Top->IteratorVarDecls, [VD](const VarDecl *IteratorVD) {
+ return IteratorVD == VD->getCanonicalDecl();
+ });
+ }
/// get captured field from ImplicitDefaultFirstprivateFDs
VarDecl *getImplicitFDCapExprDecl(const FieldDecl *FD) const {
const_iterator I = begin();
@@ -2093,7 +2124,7 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
//
// =========================================================================
// | type | defaultmap | pvt | first | is_device_ptr | map | res. |
- // | |(tofrom:scalar)| | pvt | | | |
+ // | |(tofrom:scalar)| | pvt | |has_dv_adr| |
// =========================================================================
// | scl | | | | - | | bycopy|
// | scl | | - | x | - | - | bycopy|
@@ -2154,10 +2185,11 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
D](OMPClauseMappableExprCommon::MappableExprComponentListRef
MapExprComponents,
OpenMPClauseKind WhereFoundClauseKind) {
- // Only the map clause information influences how a variable is
- // captured. E.g. is_device_ptr does not require changing the default
- // behavior.
- if (WhereFoundClauseKind != OMPC_map)
+ // Both map and has_device_addr clauses information influences how a
+ // variable is captured. E.g. is_device_ptr does not require changing
+ // the default behavior.
+ if (WhereFoundClauseKind != OMPC_map &&
+ WhereFoundClauseKind != OMPC_has_device_addr)
return false;
auto EI = MapExprComponents.rbegin();
@@ -2270,6 +2302,9 @@ bool Sema::isInOpenMPTargetExecutionDirective() const {
}
bool Sema::isOpenMPRebuildMemberExpr(ValueDecl *D) {
+ // Only rebuild for Field.
+ if (!dyn_cast<FieldDecl>(D))
+ return false;
DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
D,
[](OpenMPClauseKind C, bool AppliedToPointee,
@@ -2661,7 +2696,7 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller,
const FunctionDecl *Callee,
SourceLocation Loc) {
assert(LangOpts.OpenMP && "Expected OpenMP compilation mode.");
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl());
// Ignore host functions during device analyzis.
if (LangOpts.OpenMPIsDevice &&
@@ -2686,6 +2721,24 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller,
}
if (!LangOpts.OpenMPIsDevice && !LangOpts.OpenMPOffloadMandatory && DevTy &&
*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
+ // In OpenMP 5.2 or later, if the function has a host variant then allow
+ // that to be called instead
+ auto &&HasHostAttr = [](const FunctionDecl *Callee) {
+ for (OMPDeclareVariantAttr *A :
+ Callee->specific_attrs<OMPDeclareVariantAttr>()) {
+ auto *DeclRefVariant = cast<DeclRefExpr>(A->getVariantFuncRef());
+ auto *VariantFD = cast<FunctionDecl>(DeclRefVariant->getDecl());
+ std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(
+ VariantFD->getMostRecentDecl());
+ if (!DevTy || *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ return true;
+ }
+ return false;
+ };
+ if (getLangOpts().OpenMP >= 52 &&
+ Callee->hasAttr<OMPDeclareVariantAttr>() && HasHostAttr(Callee))
+ return;
// Diagnose nohost function called during host codegen.
StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
@@ -2715,7 +2768,8 @@ void Sema::EndOpenMPClause() {
static std::pair<ValueDecl *, bool>
getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
- SourceRange &ERange, bool AllowArraySection = false);
+ SourceRange &ERange, bool AllowArraySection = false,
+ StringRef DiagType = "");
/// Check consistency of the reduction clauses.
static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
@@ -3226,13 +3280,15 @@ getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) {
Allocator->containsUnexpandedParameterPack())
return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
+ llvm::FoldingSetNodeID AEId;
const Expr *AE = Allocator->IgnoreParenImpCasts();
+ AE->IgnoreImpCasts()->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
const Expr *DefAllocator = Stack->getAllocator(AllocatorKind);
- llvm::FoldingSetNodeID AEId, DAEId;
- AE->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
- DefAllocator->Profile(DAEId, S.getASTContext(), /*Canonical=*/true);
+ llvm::FoldingSetNodeID DAEId;
+ DefAllocator->IgnoreImpCasts()->Profile(DAEId, S.getASTContext(),
+ /*Canonical=*/true);
if (AEId == DAEId) {
AllocatorKindRes = AllocatorKind;
break;
@@ -3694,7 +3750,7 @@ public:
return;
// Skip internally declared static variables.
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) &&
(Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
@@ -3764,9 +3820,8 @@ public:
bool IsModifierPresent = Stack->getDefaultmapModifier(ClauseKind) ==
OMPC_DEFAULTMAP_MODIFIER_present;
if (IsModifierPresent) {
- if (llvm::find(ImplicitMapModifier[ClauseKind],
- OMPC_MAP_MODIFIER_present) ==
- std::end(ImplicitMapModifier[ClauseKind])) {
+ if (!llvm::is_contained(ImplicitMapModifier[ClauseKind],
+ OMPC_MAP_MODIFIER_present)) {
ImplicitMapModifier[ClauseKind].push_back(
OMPC_MAP_MODIFIER_present);
}
@@ -3785,9 +3840,8 @@ public:
// Variable is used if it has been marked as an array, array
// section, array shaping or the variable iself.
return StackComponents.size() == 1 ||
- std::all_of(
- std::next(StackComponents.rbegin()),
- StackComponents.rend(),
+ llvm::all_of(
+ llvm::drop_begin(llvm::reverse(StackComponents)),
[](const OMPClauseMappableExprCommon::
MappableComponent &MC) {
return MC.getAssociatedDeclaration() ==
@@ -4032,9 +4086,13 @@ public:
Visit(C);
}
}
- if (Expr *Callee = S->getCallee())
- if (auto *CE = dyn_cast<MemberExpr>(Callee->IgnoreParenImpCasts()))
+ if (Expr *Callee = S->getCallee()) {
+ auto *CI = Callee->IgnoreParenImpCasts();
+ if (auto *CE = dyn_cast<MemberExpr>(CI))
Visit(CE->getBase());
+ else if (auto *CE = dyn_cast<DeclRefExpr>(CI))
+ Visit(CE);
+ }
}
void VisitStmt(Stmt *S) {
for (Stmt *C : S->children()) {
@@ -4529,6 +4587,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -4674,12 +4733,12 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) {
DSAStack->setForceCaptureByReferenceInTargetExecutable(
/*V=*/true);
if (RD->isLambda()) {
- llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures;
FieldDecl *ThisCapture;
RD->getCaptureFields(Captures, ThisCapture);
for (const LambdaCapture &LC : RD->captures()) {
if (LC.getCaptureKind() == LCK_ByRef) {
- VarDecl *VD = LC.getCapturedVar();
+ VarDecl *VD = cast<VarDecl>(LC.getCapturedVar());
DeclContext *VDC = VD->getDeclContext();
if (!VDC->Encloses(CurContext))
continue;
@@ -4939,6 +4998,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ShouldBeInTeamsRegion,
ShouldBeInLoopSimdRegion,
} Recommend = NoRecommend;
+ if (SemaRef.LangOpts.OpenMP >= 51 && Stack->isParentOrderConcurrent() &&
+ CurrentRegion != OMPD_simd && CurrentRegion != OMPD_loop &&
+ CurrentRegion != OMPD_parallel &&
+ !isOpenMPCombinedParallelADirective(CurrentRegion)) {
+ SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_order)
+ << getOpenMPDirectiveName(CurrentRegion);
+ return true;
+ }
if (isOpenMPSimdDirective(ParentRegion) &&
((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) ||
(SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered &&
@@ -5277,7 +5344,8 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
SourceLocation &ELoc,
SourceRange &ERange,
- bool AllowArraySection) {
+ bool AllowArraySection,
+ StringRef DiagType) {
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
RefExpr->containsUnexpandedParameterPack())
return std::make_pair(nullptr, true);
@@ -5322,6 +5390,12 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
if (IsArrayExpr != NoArrayExpr) {
S.Diag(ELoc, diag::err_omp_expected_base_var_name)
<< IsArrayExpr << ERange;
+ } else if (!DiagType.empty()) {
+ unsigned DiagSelect = S.getLangOpts().CPlusPlus
+ ? (S.getCurrentThisType().isNull() ? 1 : 2)
+ : 0;
+ S.Diag(ELoc, diag::err_omp_expected_var_name_member_expr_with_type)
+ << DiagSelect << DiagType << ERange;
} else {
S.Diag(ELoc,
AllowArraySection
@@ -6021,7 +6095,7 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack,
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperId;
if (OMPClause *NewClause = S.ActOnOpenMPMapClause(
- C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(),
+ nullptr, C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(),
MapperIdScopeSpec, MapperId, C->getMapType(),
/*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
SubExprs, OMPVarListLocTy()))
@@ -6163,8 +6237,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperId;
if (OMPClause *Implicit = ActOnOpenMPMapClause(
- OMPC_MAP_MODIFIER_unknown, SourceLocation(), MapperIdScopeSpec,
- MapperId, OMPC_MAP_tofrom,
+ nullptr, OMPC_MAP_MODIFIER_unknown, SourceLocation(),
+ MapperIdScopeSpec, MapperId, OMPC_MAP_tofrom,
/*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
Exprs, OMPVarListLocTy(), /*NoDiagnose=*/true))
ClausesWithImplicit.emplace_back(Implicit);
@@ -6180,7 +6254,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
DeclarationNameInfo MapperId;
auto Kind = static_cast<OpenMPMapClauseKind>(ClauseKindCnt);
if (OMPClause *Implicit = ActOnOpenMPMapClause(
- ImplicitMapModifiers[I], ImplicitMapModifiersLoc[I],
+ nullptr, ImplicitMapModifiers[I], ImplicitMapModifiersLoc[I],
MapperIdScopeSpec, MapperId, Kind, /*IsMapTypeImplicit=*/true,
SourceLocation(), SourceLocation(), ImplicitMap,
OMPVarListLocTy())) {
@@ -6295,6 +6369,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
"No associated statement allowed for 'omp taskyield' directive");
Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc);
break;
+ case OMPD_error:
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp error' directive");
+ Res = ActOnOpenMPErrorDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ break;
case OMPD_barrier:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp barrier' directive");
@@ -6703,6 +6782,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_device_type:
case OMPC_match:
case OMPC_when:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
default:
llvm_unreachable("Unexpected clause");
}
@@ -7176,6 +7258,13 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
if (!CalleeFnDecl)
return Call;
+ if (LangOpts.OpenMP >= 51 && CalleeFnDecl->getIdentifier() &&
+ CalleeFnDecl->getName().startswith_insensitive("omp_")) {
+ // checking for any calls inside an Order region
+ if (Scope && Scope->isOpenMPOrderClauseScope())
+ Diag(LParenLoc, diag::err_omp_unexpected_call_to_omp_runtime_api);
+ }
+
if (!CalleeFnDecl->hasAttr<OMPDeclareVariantAttr>())
return Call;
@@ -7268,20 +7357,20 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
return PseudoObjectExpr::Create(Context, CE, {NewCall.get()}, 0);
}
-Optional<std::pair<FunctionDecl *, Expr *>>
+std::optional<std::pair<FunctionDecl *, Expr *>>
Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
Expr *VariantRef, OMPTraitInfo &TI,
unsigned NumAppendArgs,
SourceRange SR) {
if (!DG || DG.get().isNull())
- return None;
+ return std::nullopt;
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;
+ return std::nullopt;
}
Decl *ADecl = DG.get().getSingleDecl();
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
@@ -7292,7 +7381,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (!FD) {
Diag(ADecl->getLocation(), diag::err_omp_function_expected)
<< VariantId << SR;
- return None;
+ return std::nullopt;
}
auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) {
@@ -7304,7 +7393,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (HasMultiVersionAttributes(FD)) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes)
<< SR;
- return None;
+ return std::nullopt;
}
// Allow #pragma omp declare variant only if the function is not used.
@@ -7322,7 +7411,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
// The VariantRef must point to function.
if (!VariantRef) {
Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId;
- return None;
+ return std::nullopt;
}
auto ShouldDelayChecks = [](Expr *&E, bool) {
@@ -7357,7 +7446,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return true;
};
if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions))
- return None;
+ return std::nullopt;
QualType AdjustedFnType = FD->getType();
if (NumAppendArgs) {
@@ -7365,7 +7454,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (!PTy) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_prototype_required)
<< SR;
- return None;
+ return std::nullopt;
}
// Adjust the function type to account for an extra omp_interop_t for each
// specified in the append_args clause.
@@ -7378,12 +7467,12 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
}
if (!TD) {
Diag(SR.getBegin(), diag::err_omp_interop_type_not_found) << SR;
- return None;
+ return std::nullopt;
}
QualType InteropType = Context.getTypeDeclType(TD);
if (PTy->isVariadic()) {
Diag(FD->getLocation(), diag::err_omp_append_args_with_varargs) << SR;
- return None;
+ return std::nullopt;
}
llvm::SmallVector<QualType, 8> Params;
Params.append(PTy->param_type_begin(), PTy->param_type_end());
@@ -7413,7 +7502,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (!ER.isUsable()) {
Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
<< VariantId << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
VariantRef = ER.get();
} else {
@@ -7433,12 +7522,12 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
<< VariantRef->getType()
<< ((Method && !Method->isStatic()) ? FnPtrType : FD->getType())
<< (NumAppendArgs ? 1 : 0) << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
VariantRefCast = PerformImplicitConversion(
VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting);
if (!VariantRefCast.isUsable())
- return None;
+ return std::nullopt;
}
// Drop previously built artificial addr_of unary op for member functions.
if (Method && !Method->isStatic()) {
@@ -7454,7 +7543,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
!ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) {
Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
<< VariantId << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
// The VariantRef must point to function.
@@ -7462,20 +7551,20 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (!DRE) {
Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
<< VariantId << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
auto *NewFD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl());
if (!NewFD) {
Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
<< VariantId << VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
if (FD->getCanonicalDecl() == NewFD->getCanonicalDecl()) {
Diag(VariantRef->getExprLoc(),
diag::err_omp_declare_variant_same_base_function)
<< VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
// Check if function types are compatible in C.
@@ -7487,7 +7576,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
diag::err_omp_declare_variant_incompat_types)
<< NewFD->getType() << FD->getType() << (NumAppendArgs ? 1 : 0)
<< VariantRef->getSourceRange();
- return None;
+ return std::nullopt;
}
if (NewType->isFunctionProtoType()) {
if (FD->getType()->isFunctionNoProtoType())
@@ -7505,7 +7594,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
SourceRange SR =
NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange();
Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR;
- return None;
+ return std::nullopt;
}
enum DoesntSupport {
@@ -7521,38 +7610,38 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (CXXFD->isVirtual()) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< VirtFuncs;
- return None;
+ return std::nullopt;
}
if (isa<CXXConstructorDecl>(FD)) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< Constructors;
- return None;
+ return std::nullopt;
}
if (isa<CXXDestructorDecl>(FD)) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< Destructors;
- return None;
+ return std::nullopt;
}
}
if (FD->isDeleted()) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< DeletedFuncs;
- return None;
+ return std::nullopt;
}
if (FD->isDefaulted()) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< DefaultedFuncs;
- return None;
+ return std::nullopt;
}
if (FD->isConstexpr()) {
Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
<< (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
- return None;
+ return std::nullopt;
}
// Check general compatibility.
@@ -7568,7 +7657,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
<< FD->getLocation()),
/*TemplatesSupported=*/true, /*ConstexprSupported=*/false,
/*CLinkageMayDiffer=*/true))
- return None;
+ return std::nullopt;
return std::make_pair(FD, cast<Expr>(DRE));
}
@@ -7576,9 +7665,8 @@ void Sema::ActOnOpenMPDeclareVariantDirective(
FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI,
ArrayRef<Expr *> AdjustArgsNothing,
ArrayRef<Expr *> AdjustArgsNeedDevicePtr,
- ArrayRef<OMPDeclareVariantAttr::InteropType> AppendArgs,
- SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc,
- SourceRange SR) {
+ ArrayRef<OMPInteropInfo> AppendArgs, SourceLocation AdjustArgsLoc,
+ SourceLocation AppendArgsLoc, SourceRange SR) {
// OpenMP 5.1 [2.3.5, declare variant directive, Restrictions]
// An adjust_args clause or append_args clause can only be specified if the
@@ -7638,8 +7726,7 @@ void Sema::ActOnOpenMPDeclareVariantDirective(
AdjustArgsNothing.size(),
const_cast<Expr **>(AdjustArgsNeedDevicePtr.data()),
AdjustArgsNeedDevicePtr.size(),
- const_cast<OMPDeclareVariantAttr::InteropType *>(AppendArgs.data()),
- AppendArgs.size(), SR);
+ const_cast<OMPInteropInfo *>(AppendArgs.data()), AppendArgs.size(), SR);
FD->addAttr(NewAttr);
}
@@ -7750,7 +7837,7 @@ class OpenMPIterationSpaceChecker {
/// UB > Var
/// UB >= Var
/// This will have no value when the condition is !=
- llvm::Optional<bool> TestIsLessOp;
+ std::optional<bool> TestIsLessOp;
/// This flag is true when condition is strict ( < or > ).
bool TestIsStrictOp = false;
/// This flag is true when step is subtracted on each iteration.
@@ -7759,12 +7846,13 @@ class OpenMPIterationSpaceChecker {
const ValueDecl *DepDecl = nullptr;
/// Contains number of loop (starts from 1) on which loop counter init
/// expression of this loop depends on.
- Optional<unsigned> InitDependOnLC;
+ std::optional<unsigned> InitDependOnLC;
/// Contains number of loop (starts from 1) on which loop counter condition
/// expression of this loop depends on.
- Optional<unsigned> CondDependOnLC;
+ std::optional<unsigned> CondDependOnLC;
/// Checks if the provide statement depends on the loop counter.
- Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer);
+ std::optional<unsigned> doesDependOnLoopCounter(const Stmt *S,
+ bool IsInitializer);
/// Original condition required for checking of the exit condition for
/// non-rectangular loop.
Expr *Condition = nullptr;
@@ -7847,7 +7935,7 @@ private:
bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB,
bool EmitDiags);
/// Helper to set upper bound.
- bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp,
+ bool setUB(Expr *NewUB, std::optional<bool> LessOp, bool StrictOp,
SourceRange SR, SourceLocation SL);
/// Helper to set loop increment.
bool setStep(Expr *NewStep, bool Subtract);
@@ -7885,8 +7973,7 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
return false;
}
-bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB,
- llvm::Optional<bool> LessOp,
+bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, std::optional<bool> LessOp,
bool StrictOp, SourceRange SR,
SourceLocation SL) {
// State consistency checking to ensure correct usage.
@@ -7929,7 +8016,7 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
// loop. If test-expr is of form b relational-op var and relational-op is
// > or >= then incr-expr must cause var to increase on each iteration of
// the loop.
- Optional<llvm::APSInt> Result =
+ std::optional<llvm::APSInt> Result =
NewStep->getIntegerConstantExpr(SemaRef.Context);
bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation();
bool IsConstNeg =
@@ -7941,19 +8028,18 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
// != with increment is treated as <; != with decrement is treated as >
if (!TestIsLessOp)
TestIsLessOp = IsConstPos || (IsUnsigned && !Subtract);
- if (UB &&
- (IsConstZero ||
- (TestIsLessOp.value() ? (IsConstNeg || (IsUnsigned && Subtract))
- : (IsConstPos || (IsUnsigned && !Subtract))))) {
+ if (UB && (IsConstZero ||
+ (*TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract))
+ : (IsConstPos || (IsUnsigned && !Subtract))))) {
SemaRef.Diag(NewStep->getExprLoc(),
diag::err_omp_loop_incr_not_compatible)
- << LCDecl << TestIsLessOp.value() << NewStep->getSourceRange();
+ << LCDecl << *TestIsLessOp << NewStep->getSourceRange();
SemaRef.Diag(ConditionLoc,
diag::note_omp_loop_cond_requres_compatible_incr)
- << TestIsLessOp.value() << ConditionSrcRange;
+ << *TestIsLessOp << ConditionSrcRange;
return true;
}
- if (TestIsLessOp.value() == Subtract) {
+ if (*TestIsLessOp == Subtract) {
NewStep =
SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, NewStep)
.get();
@@ -8064,7 +8150,7 @@ public:
};
} // namespace
-Optional<unsigned>
+std::optional<unsigned>
OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S,
bool IsInitializer) {
// Check for the non-rectangular loops.
@@ -8074,7 +8160,7 @@ OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S,
DepDecl = LoopStmtChecker.getDepDecl();
return LoopStmtChecker.getBaseLoopId();
}
- return llvm::None;
+ return std::nullopt;
}
bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
@@ -8200,10 +8286,10 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
Condition = S;
S = getExprAsWritten(S);
SourceLocation CondLoc = S->getBeginLoc();
- auto &&CheckAndSetCond = [this, IneqCondIsCanonical](
- BinaryOperatorKind Opcode, const Expr *LHS,
- const Expr *RHS, SourceRange SR,
- SourceLocation OpLoc) -> llvm::Optional<bool> {
+ auto &&CheckAndSetCond =
+ [this, IneqCondIsCanonical](BinaryOperatorKind Opcode, const Expr *LHS,
+ const Expr *RHS, SourceRange SR,
+ SourceLocation OpLoc) -> std::optional<bool> {
if (BinaryOperator::isRelationalOp(Opcode)) {
if (getInitLCDecl(LHS) == LCDecl)
return setUB(const_cast<Expr *>(RHS),
@@ -8215,12 +8301,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
(Opcode == BO_LT || Opcode == BO_GT), SR, OpLoc);
} else if (IneqCondIsCanonical && Opcode == BO_NE) {
return setUB(const_cast<Expr *>(getInitLCDecl(LHS) == LCDecl ? RHS : LHS),
- /*LessOp=*/llvm::None,
+ /*LessOp=*/std::nullopt,
/*StrictOp=*/true, SR, OpLoc);
}
- return llvm::None;
+ return std::nullopt;
};
- llvm::Optional<bool> Res;
+ std::optional<bool> Res;
if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
CXXRewrittenBinaryOperator::DecomposedForm DF = RBO->getDecomposedForm();
Res = CheckAndSetCond(DF.Opcode, DF.LHS, DF.RHS, RBO->getSourceRange(),
@@ -8383,12 +8469,12 @@ calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc,
return nullptr;
llvm::APSInt LRes, SRes;
bool IsLowerConst = false, IsStepConst = false;
- if (Optional<llvm::APSInt> Res =
+ if (std::optional<llvm::APSInt> Res =
Lower->getIntegerConstantExpr(SemaRef.Context)) {
LRes = *Res;
IsLowerConst = true;
}
- if (Optional<llvm::APSInt> Res =
+ if (std::optional<llvm::APSInt> Res =
Step->getIntegerConstantExpr(SemaRef.Context)) {
SRes = *Res;
IsStepConst = true;
@@ -8427,7 +8513,7 @@ calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc,
}
llvm::APSInt URes;
bool IsUpperConst = false;
- if (Optional<llvm::APSInt> Res =
+ if (std::optional<llvm::APSInt> Res =
Upper->getIntegerConstantExpr(SemaRef.Context)) {
URes = *Res;
IsUpperConst = true;
@@ -8708,8 +8794,8 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
UBVal = MinUB.get();
}
}
- Expr *UBExpr = TestIsLessOp.value() ? UBVal : LBVal;
- Expr *LBExpr = TestIsLessOp.value() ? LBVal : UBVal;
+ Expr *UBExpr = *TestIsLessOp ? UBVal : LBVal;
+ Expr *LBExpr = *TestIsLessOp ? LBVal : UBVal;
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
@@ -8772,12 +8858,12 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
// init value.
Expr *MinExpr = nullptr;
Expr *MaxExpr = nullptr;
- Expr *LBExpr = TestIsLessOp.value() ? LB : UB;
- Expr *UBExpr = TestIsLessOp.value() ? UB : LB;
- bool LBNonRect = TestIsLessOp.value() ? InitDependOnLC.has_value()
- : CondDependOnLC.has_value();
- bool UBNonRect = TestIsLessOp.value() ? CondDependOnLC.has_value()
- : InitDependOnLC.has_value();
+ Expr *LBExpr = *TestIsLessOp ? LB : UB;
+ Expr *UBExpr = *TestIsLessOp ? UB : LB;
+ bool LBNonRect =
+ *TestIsLessOp ? InitDependOnLC.has_value() : CondDependOnLC.has_value();
+ bool UBNonRect =
+ *TestIsLessOp ? CondDependOnLC.has_value() : InitDependOnLC.has_value();
Expr *Lower =
LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get();
Expr *Upper =
@@ -8899,11 +8985,11 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
if (!NewLB.isUsable() || !NewUB.isUsable())
return nullptr;
- ExprResult CondExpr = SemaRef.BuildBinOp(
- S, DefaultLoc,
- TestIsLessOp.value() ? (TestIsStrictOp ? BO_LT : BO_LE)
- : (TestIsStrictOp ? BO_GT : BO_GE),
- NewLB.get(), NewUB.get());
+ ExprResult CondExpr =
+ SemaRef.BuildBinOp(S, DefaultLoc,
+ *TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE)
+ : (TestIsStrictOp ? BO_GT : BO_GE),
+ NewLB.get(), NewUB.get());
if (CondExpr.isUsable()) {
if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(),
SemaRef.Context.BoolTy))
@@ -8979,9 +9065,9 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
return nullptr;
// Upper - Lower
Expr *Upper =
- TestIsLessOp.value() ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get();
+ *TestIsLessOp ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get();
Expr *Lower =
- TestIsLessOp.value() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
+ *TestIsLessOp ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
if (!Upper || !Lower)
return nullptr;
@@ -9383,7 +9469,7 @@ static ExprResult widenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) {
static bool fitsInto(unsigned Bits, bool Signed, const Expr *E, Sema &SemaRef) {
if (E == nullptr)
return false;
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
E->getIntegerConstantExpr(SemaRef.Context))
return Signed ? Result->isSignedIntN(Bits) : Result->isIntN(Bits);
return false;
@@ -11012,9 +11098,50 @@ StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc,
return OMPBarrierDirective::Create(Context, StartLoc, EndLoc);
}
+StmtResult Sema::ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ bool InExContext) {
+ const OMPAtClause *AtC =
+ OMPExecutableDirective::getSingleClause<OMPAtClause>(Clauses);
+
+ if (AtC && !InExContext && AtC->getAtKind() == OMPC_AT_execution) {
+ Diag(AtC->getAtKindKwLoc(), diag::err_omp_unexpected_execution_modifier);
+ return StmtError();
+ }
+
+ const OMPSeverityClause *SeverityC =
+ OMPExecutableDirective::getSingleClause<OMPSeverityClause>(Clauses);
+ const OMPMessageClause *MessageC =
+ OMPExecutableDirective::getSingleClause<OMPMessageClause>(Clauses);
+ Expr *ME = MessageC ? MessageC->getMessageString() : nullptr;
+
+ if (!AtC || AtC->getAtKind() == OMPC_AT_compilation) {
+ if (SeverityC && SeverityC->getSeverityKind() == OMPC_SEVERITY_warning)
+ Diag(SeverityC->getSeverityKindKwLoc(), diag::warn_diagnose_if_succeeded)
+ << (ME ? cast<StringLiteral>(ME)->getString() : "WARNING");
+ else
+ Diag(StartLoc, diag::err_diagnose_if_succeeded)
+ << (ME ? cast<StringLiteral>(ME)->getString() : "ERROR");
+ if (!SeverityC || SeverityC->getSeverityKind() != OMPC_SEVERITY_warning)
+ return StmtError();
+ }
+ return OMPErrorDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
StmtResult Sema::ActOnOpenMPTaskwaitDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
+ const OMPNowaitClause *NowaitC =
+ OMPExecutableDirective::getSingleClause<OMPNowaitClause>(Clauses);
+ bool HasDependC =
+ !OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses)
+ .empty();
+ if (NowaitC && !HasDependC) {
+ Diag(StartLoc, diag::err_omp_nowait_clause_without_depend);
+ return StmtError();
+ }
+
return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
@@ -11569,6 +11696,9 @@ protected:
static bool CheckValue(const Expr *E, ErrorInfoTy &ErrorInfo,
bool ShouldBeLValue, bool ShouldBeInteger = false) {
+ if (E->isInstantiationDependent())
+ return true;
+
if (ShouldBeLValue && !E->isLValue()) {
ErrorInfo.Error = ErrorTy::XNotLValue;
ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
@@ -11576,25 +11706,23 @@ protected:
return false;
}
- if (!E->isInstantiationDependent()) {
- QualType QTy = E->getType();
- if (!QTy->isScalarType()) {
- ErrorInfo.Error = ErrorTy::NotScalar;
- ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
- ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
- return false;
- }
- if (ShouldBeInteger && !QTy->isIntegerType()) {
- ErrorInfo.Error = ErrorTy::NotInteger;
- ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
- ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
- return false;
- }
+ QualType QTy = E->getType();
+ if (!QTy->isScalarType()) {
+ ErrorInfo.Error = ErrorTy::NotScalar;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
+ return false;
+ }
+ if (ShouldBeInteger && !QTy->isIntegerType()) {
+ ErrorInfo.Error = ErrorTy::NotInteger;
+ ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc();
+ ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange();
+ return false;
}
return true;
}
-};
+ };
bool OpenMPAtomicCompareChecker::checkCondUpdateStmt(IfStmt *S,
ErrorInfoTy &ErrorInfo) {
@@ -12174,17 +12302,33 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S,
Stmt *UpdateStmt = nullptr;
Stmt *CondUpdateStmt = nullptr;
+ Stmt *CondExprStmt = nullptr;
if (auto *BO = dyn_cast<BinaryOperator>(S1)) {
- // { v = x; cond-update-stmt } or form 45.
- UpdateStmt = S1;
- CondUpdateStmt = S2;
- // Check if form 45.
- if (isa<BinaryOperator>(BO->getRHS()->IgnoreImpCasts()) &&
- isa<IfStmt>(S2))
- return checkForm45(CS, ErrorInfo);
- // It cannot be set before we the check for form45.
- IsPostfixUpdate = true;
+ // It could be one of the following cases:
+ // { v = x; cond-update-stmt }
+ // { v = x; cond-expr-stmt }
+ // { cond-expr-stmt; v = x; }
+ // form 45
+ if (isa<BinaryOperator>(BO->getRHS()->IgnoreImpCasts()) ||
+ isa<ConditionalOperator>(BO->getRHS()->IgnoreImpCasts())) {
+ // check if form 45
+ if (isa<IfStmt>(S2))
+ return checkForm45(CS, ErrorInfo);
+ // { cond-expr-stmt; v = x; }
+ CondExprStmt = S1;
+ UpdateStmt = S2;
+ } else {
+ IsPostfixUpdate = true;
+ UpdateStmt = S1;
+ if (isa<IfStmt>(S2)) {
+ // { v = x; cond-update-stmt }
+ CondUpdateStmt = S2;
+ } else {
+ // { v = x; cond-expr-stmt }
+ CondExprStmt = S2;
+ }
+ }
} else {
// { cond-update-stmt v = x; }
UpdateStmt = S2;
@@ -12200,10 +12344,7 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S,
return false;
}
- if (!checkCondUpdateStmt(IS, ErrorInfo))
- return false;
-
- return true;
+ return checkCondUpdateStmt(IS, ErrorInfo);
};
// CheckUpdateStmt has to be called *after* CheckCondUpdateStmt.
@@ -12236,7 +12377,9 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S,
return true;
};
- if (!CheckCondUpdateStmt(CondUpdateStmt))
+ if (CondUpdateStmt && !CheckCondUpdateStmt(CondUpdateStmt))
+ return false;
+ if (CondExprStmt && !checkCondExprStmt(CondExprStmt, ErrorInfo))
return false;
if (!CheckUpdateStmt(UpdateStmt))
return false;
@@ -12277,7 +12420,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
case OMPC_write:
case OMPC_update:
MutexClauseEncountered = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPC_capture:
case OMPC_compare: {
if (AtomicKind != OMPC_unknown && MutexClauseEncountered) {
@@ -15049,12 +15192,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_priority:
Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
- case OMPC_grainsize:
- Res = ActOnOpenMPGrainsizeClause(Expr, StartLoc, LParenLoc, EndLoc);
- break;
- case OMPC_num_tasks:
- Res = ActOnOpenMPNumTasksClause(Expr, StartLoc, LParenLoc, EndLoc);
- break;
case OMPC_hint:
Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
@@ -15076,9 +15213,17 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_partial:
Res = ActOnOpenMPPartialClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_message:
+ Res = ActOnOpenMPMessageClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_align:
Res = ActOnOpenMPAlignClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_ompx_dyn_cgroup_mem:
+ Res = ActOnOpenMPXDynCGroupMemClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
case OMPC_device:
case OMPC_if:
case OMPC_default:
@@ -15135,6 +15280,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
case OMPC_destroy:
case OMPC_inclusive:
case OMPC_exclusive:
@@ -15166,7 +15313,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
CaptureRegion = OMPD_parallel;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPD_target_parallel:
case OMPD_target_parallel_for:
case OMPD_target_parallel_loop:
@@ -15181,7 +15328,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
CaptureRegion = OMPD_parallel;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPD_target_teams_distribute_parallel_for:
// If this clause applies to the nested 'parallel' region, capture within
// the 'teams' region, otherwise do not capture.
@@ -15194,7 +15341,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
CaptureRegion = OMPD_parallel;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OMPD_teams_distribute_parallel_for:
CaptureRegion = OMPD_teams;
break;
@@ -15289,6 +15436,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15377,6 +15525,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15473,6 +15622,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15514,6 +15664,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
break;
case OMPC_thread_limit:
switch (DKind) {
+ case OMPD_target:
case OMPD_target_teams:
case OMPD_target_teams_distribute:
case OMPD_target_teams_distribute_simd:
@@ -15555,7 +15706,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel_for:
case OMPD_parallel_for_simd:
case OMPD_parallel_loop:
- case OMPD_target:
case OMPD_target_simd:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
@@ -15564,6 +15714,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15652,6 +15803,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15743,6 +15895,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15785,6 +15938,26 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
llvm_unreachable("Unknown OpenMP directive");
}
break;
+ case OMPC_ompx_dyn_cgroup_mem:
+ switch (DKind) {
+ 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_parallel_loop:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_teams_loop:
+ CaptureRegion = OMPD_target;
+ break;
+ default:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
case OMPC_device:
switch (DKind) {
case OMPD_target_update:
@@ -15837,6 +16010,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -15928,6 +16102,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
+ case OMPD_error:
case OMPD_barrier:
case OMPD_taskwait:
case OMPD_cancellation_point:
@@ -16052,6 +16227,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_destroy:
case OMPC_detach:
case OMPC_inclusive:
@@ -16190,7 +16368,7 @@ isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
ValExpr = Value.get();
// The expression must evaluate to a non-negative integer value.
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
ValExpr->getIntegerConstantExpr(SemaRef.Context)) {
if (Result->isSigned() &&
!((!StrictlyPositive && Result->isNonNegative()) ||
@@ -16320,10 +16498,22 @@ OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc,
/// Tries to find omp_allocator_handle_t type.
static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
DSAStackTy *Stack) {
- QualType OMPAllocatorHandleT = Stack->getOMPAllocatorHandleT();
- if (!OMPAllocatorHandleT.isNull())
+ if (!Stack->getOMPAllocatorHandleT().isNull())
return true;
- // Build the predefined allocator expressions.
+
+ // Set the allocator handle type.
+ IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_allocator_handle_t");
+ ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope());
+ if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
+ S.Diag(Loc, diag::err_omp_implied_type_not_found)
+ << "omp_allocator_handle_t";
+ return false;
+ }
+ QualType AllocatorHandleEnumTy = PT.get();
+ AllocatorHandleEnumTy.addConst();
+ Stack->setOMPAllocatorHandleT(AllocatorHandleEnumTy);
+
+ // Fill the predefined allocator map.
bool ErrorFound = false;
for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
@@ -16343,9 +16533,10 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
ErrorFound = true;
break;
}
- if (OMPAllocatorHandleT.isNull())
- OMPAllocatorHandleT = AllocatorType;
- if (!S.getASTContext().hasSameType(OMPAllocatorHandleT, AllocatorType)) {
+ Res = S.PerformImplicitConversion(Res.get(), AllocatorHandleEnumTy,
+ Sema::AA_Initializing,
+ /* AllowExplicit */ true);
+ if (!Res.isUsable()) {
ErrorFound = true;
break;
}
@@ -16356,8 +16547,7 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
<< "omp_allocator_handle_t";
return false;
}
- OMPAllocatorHandleT.addConst();
- Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT);
+
return true;
}
@@ -16442,10 +16632,6 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
- case OMPC_order:
- Res = ActOnOpenMPOrderClause(static_cast<OpenMPOrderClauseKind>(Argument),
- ArgumentLoc, StartLoc, LParenLoc, EndLoc);
- break;
case OMPC_update:
Res = ActOnOpenMPUpdateClause(static_cast<OpenMPDependClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
@@ -16454,6 +16640,15 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
Res = ActOnOpenMPBindClause(static_cast<OpenMPBindClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_at:
+ Res = ActOnOpenMPAtClause(static_cast<OpenMPAtClauseKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_severity:
+ Res = ActOnOpenMPSeverityClause(
+ static_cast<OpenMPSeverityClauseKind>(Argument), ArgumentLoc, StartLoc,
+ LParenLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -16529,6 +16724,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_uses_allocators:
case OMPC_affinity:
case OMPC_when:
+ case OMPC_message:
default:
llvm_unreachable("Clause is not allowed.");
}
@@ -16537,13 +16733,12 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
static std::string
getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
- ArrayRef<unsigned> Exclude = llvm::None) {
+ ArrayRef<unsigned> Exclude = std::nullopt) {
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
unsigned Skipped = Exclude.size();
- auto S = Exclude.begin(), E = Exclude.end();
for (unsigned I = First; I < Last; ++I) {
- if (std::find(S, E, I) != E) {
+ if (llvm::is_contained(Exclude, I)) {
--Skipped;
continue;
}
@@ -16633,22 +16828,87 @@ OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause(
LParenLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind,
- SourceLocation KindKwLoc,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
- if (Kind == OMPC_ORDER_unknown) {
+OMPClause *Sema::ActOnOpenMPAtClause(OpenMPAtClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_AT_unknown) {
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_at, /*First=*/0,
+ /*Last=*/OMPC_AT_unknown)
+ << getOpenMPClauseName(OMPC_at);
+ return nullptr;
+ }
+ return new (Context)
+ OMPAtClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPSeverityClause(OpenMPSeverityClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_SEVERITY_unknown) {
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_severity, /*First=*/0,
+ /*Last=*/OMPC_SEVERITY_unknown)
+ << getOpenMPClauseName(OMPC_severity);
+ return nullptr;
+ }
+ return new (Context)
+ OMPSeverityClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPMessageClause(Expr *ME, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ assert(ME && "NULL expr in Message clause");
+ if (!isa<StringLiteral>(ME)) {
+ Diag(ME->getBeginLoc(), diag::warn_clause_expected_string)
+ << getOpenMPClauseName(OMPC_message);
+ return nullptr;
+ }
+ return new (Context) OMPMessageClause(ME, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPOrderClause(
+ OpenMPOrderClauseModifier Modifier, OpenMPOrderClauseKind Kind,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc,
+ SourceLocation KindLoc, SourceLocation EndLoc) {
+ if (Kind != OMPC_ORDER_concurrent ||
+ (LangOpts.OpenMP < 51 && MLoc.isValid())) {
+ // Kind should be concurrent,
+ // Modifiers introduced in OpenMP 5.1
static_assert(OMPC_ORDER_unknown > 0,
"OMPC_ORDER_unknown not greater than 0");
- Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
- << getListOfPossibleValues(OMPC_order, /*First=*/0,
+
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_order,
+ /*First=*/0,
/*Last=*/OMPC_ORDER_unknown)
<< getOpenMPClauseName(OMPC_order);
return nullptr;
}
- return new (Context)
- OMPOrderClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+ if (LangOpts.OpenMP >= 51) {
+ if (Modifier == OMPC_ORDER_MODIFIER_unknown && MLoc.isValid()) {
+ Diag(MLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_order,
+ /*First=*/OMPC_ORDER_MODIFIER_unknown + 1,
+ /*Last=*/OMPC_ORDER_MODIFIER_last)
+ << getOpenMPClauseName(OMPC_order);
+ } else {
+ DSAStack->setRegionHasOrderConcurrent(/*HasOrderConcurrent=*/true);
+ if (DSAStack->getCurScope()) {
+ // mark the current scope with 'order' flag
+ unsigned existingFlags = DSAStack->getCurScope()->getFlags();
+ DSAStack->getCurScope()->setFlags(existingFlags |
+ Scope::OpenMPOrderClauseScope);
+ }
+ }
+ }
+ return new (Context) OMPOrderClause(Kind, KindLoc, StartLoc, LParenLoc,
+ EndLoc, Modifier, MLoc);
}
OMPClause *Sema::ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind,
@@ -16760,12 +17020,33 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind],
EndLoc);
break;
+ case OMPC_order:
+ enum { OrderModifier, OrderKind };
+ Res = ActOnOpenMPOrderClause(
+ static_cast<OpenMPOrderClauseModifier>(Argument[OrderModifier]),
+ static_cast<OpenMPOrderClauseKind>(Argument[OrderKind]), StartLoc,
+ LParenLoc, ArgumentLoc[OrderModifier], ArgumentLoc[OrderKind], EndLoc);
+ break;
case OMPC_device:
assert(Argument.size() == 1 && ArgumentLoc.size() == 1);
Res = ActOnOpenMPDeviceClause(
static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Expr,
StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc);
break;
+ case OMPC_grainsize:
+ assert(Argument.size() == 1 && ArgumentLoc.size() == 1 &&
+ "Modifier for grainsize clause and its location are expected.");
+ Res = ActOnOpenMPGrainsizeClause(
+ static_cast<OpenMPGrainsizeClauseModifier>(Argument.back()), Expr,
+ StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc);
+ break;
+ case OMPC_num_tasks:
+ assert(Argument.size() == 1 && ArgumentLoc.size() == 1 &&
+ "Modifier for num_tasks clause and its location are expected.");
+ Res = ActOnOpenMPNumTasksClause(
+ static_cast<OpenMPNumTasksClauseModifier>(Argument.back()), Expr,
+ StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc);
+ break;
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
@@ -16811,9 +17092,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_num_teams:
case OMPC_thread_limit:
case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_unknown:
case OMPC_uniform:
@@ -16831,7 +17110,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
- case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_destroy:
case OMPC_novariants:
case OMPC_nocontext:
@@ -16935,7 +17216,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
// OpenMP [2.7.1, Restrictions]
// chunk_size must be a loop invariant integer expression with a positive
// value.
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
ValExpr->getIntegerConstantExpr(Context)) {
if (Result->isSigned() && !Result->isStrictlyPositive()) {
Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
@@ -17088,6 +17369,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_match:
case OMPC_nontemporal:
case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_novariants:
case OMPC_nocontext:
case OMPC_detach:
@@ -17096,6 +17380,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_uses_allocators:
case OMPC_affinity:
case OMPC_when:
+ case OMPC_ompx_dyn_cgroup_mem:
default:
llvm_unreachable("Clause is not allowed.");
}
@@ -17247,32 +17532,28 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
// OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
// Each interop-var may be specified for at most one action-clause of each
// interop construct.
- llvm::SmallPtrSet<const VarDecl *, 4> InteropVars;
- for (const OMPClause *C : Clauses) {
+ llvm::SmallPtrSet<const ValueDecl *, 4> InteropVars;
+ for (OMPClause *C : Clauses) {
OpenMPClauseKind ClauseKind = C->getClauseKind();
- const DeclRefExpr *DRE = nullptr;
- SourceLocation VarLoc;
+ std::pair<ValueDecl *, bool> DeclResult;
+ SourceLocation ELoc;
+ SourceRange ERange;
if (ClauseKind == OMPC_init) {
- const auto *IC = cast<OMPInitClause>(C);
- VarLoc = IC->getVarLoc();
- DRE = dyn_cast_or_null<DeclRefExpr>(IC->getInteropVar());
+ auto *E = cast<OMPInitClause>(C)->getInteropVar();
+ DeclResult = getPrivateItem(*this, E, ELoc, ERange);
} else if (ClauseKind == OMPC_use) {
- const auto *UC = cast<OMPUseClause>(C);
- VarLoc = UC->getVarLoc();
- DRE = dyn_cast_or_null<DeclRefExpr>(UC->getInteropVar());
+ auto *E = cast<OMPUseClause>(C)->getInteropVar();
+ DeclResult = getPrivateItem(*this, E, ELoc, ERange);
} else if (ClauseKind == OMPC_destroy) {
- const auto *DC = cast<OMPDestroyClause>(C);
- VarLoc = DC->getVarLoc();
- DRE = dyn_cast_or_null<DeclRefExpr>(DC->getInteropVar());
+ auto *E = cast<OMPDestroyClause>(C)->getInteropVar();
+ DeclResult = getPrivateItem(*this, E, ELoc, ERange);
}
- if (!DRE)
- continue;
-
- if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (!InteropVars.insert(VD->getCanonicalDecl()).second) {
- Diag(VarLoc, diag::err_omp_interop_var_multiple_actions) << VD;
+ if (DeclResult.first) {
+ if (!InteropVars.insert(DeclResult.first).second) {
+ Diag(ELoc, diag::err_omp_interop_var_multiple_actions)
+ << DeclResult.first;
return StmtError();
}
}
@@ -17284,16 +17565,20 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses,
static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
SourceLocation VarLoc,
OpenMPClauseKind Kind) {
- if (InteropVarExpr->isValueDependent() || InteropVarExpr->isTypeDependent() ||
- InteropVarExpr->isInstantiationDependent() ||
- InteropVarExpr->containsUnexpandedParameterPack())
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *RefExpr = InteropVarExpr;
+ auto Res =
+ getPrivateItem(SemaRef, RefExpr, ELoc, ERange,
+ /*AllowArraySection=*/false, /*DiagType=*/"omp_interop_t");
+
+ if (Res.second) {
+ // It will be analyzed later.
return true;
+ }
- const auto *DRE = dyn_cast<DeclRefExpr>(InteropVarExpr);
- if (!DRE || !isa<VarDecl>(DRE->getDecl())) {
- SemaRef.Diag(VarLoc, diag::err_omp_interop_variable_expected) << 0;
+ if (!Res.first)
return false;
- }
// Interop variable should be of type omp_interop_t.
bool HasError = false;
@@ -17335,8 +17620,7 @@ static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr,
}
OMPClause *
-Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
- bool IsTarget, bool IsTargetSync,
+Sema::ActOnOpenMPInitClause(Expr *InteropVar, OMPInteropInfo &InteropInfo,
SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation VarLoc, SourceLocation EndLoc) {
@@ -17345,7 +17629,7 @@ Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
// Check prefer_type values. These foreign-runtime-id values are either
// string literals or constant integral expressions.
- for (const Expr *E : PrefExprs) {
+ for (const Expr *E : InteropInfo.PreferTypes) {
if (E->isValueDependent() || E->isTypeDependent() ||
E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
continue;
@@ -17357,9 +17641,8 @@ Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
return nullptr;
}
- return OMPInitClause::Create(Context, InteropVar, PrefExprs, IsTarget,
- IsTargetSync, StartLoc, LParenLoc, VarLoc,
- EndLoc);
+ return OMPInitClause::Create(Context, InteropVar, InteropInfo, StartLoc,
+ LParenLoc, VarLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPUseClause(Expr *InteropVar, SourceLocation StartLoc,
@@ -17549,7 +17832,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown &&
"Unexpected map modifier.");
Res = ActOnOpenMPMapClause(
- Data.MapTypeModifiers, Data.MapTypeModifiersLoc,
+ Data.IteratorExpr, Data.MapTypeModifiers, Data.MapTypeModifiersLoc,
Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId,
static_cast<OpenMPMapClauseKind>(ExtraModifier), Data.IsMapTypeImplicit,
ExtraModifierLoc, ColonLoc, VarList, Locs);
@@ -17644,6 +17927,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
case OMPC_device_type:
case OMPC_match:
case OMPC_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_destroy:
case OMPC_novariants:
case OMPC_nocontext:
@@ -18417,7 +18703,7 @@ static T filterLookupForUDReductionAndMapper(
static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
- for (auto RD : D->redecls()) {
+ for (auto *RD : D->redecls()) {
// Don't bother with extra checks if we already know this one isn't visible.
if (RD == D)
continue;
@@ -19744,7 +20030,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause(
// Warn about zero linear step (it would be probably better specified as
// making corresponding variables 'const').
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
StepExpr->getIntegerConstantExpr(Context)) {
if (!Result->isNegative() && !Result->isStrictlyPositive())
Diag(StepLoc, diag::warn_omp_linear_step_zero)
@@ -20927,8 +21213,8 @@ public:
}
// Pointer arithmetic is the only thing we expect to happen here so after we
- // make sure the binary operator is a pointer type, the we only thing need
- // to to is to visit the subtree that has the same type as root (so that we
+ // make sure the binary operator is a pointer type, the only thing we need
+ // to do is to visit the subtree that has the same type as root (so that we
// know the other subtree is just an offset)
Expr *LE = BO->getLHS()->IgnoreParenImpCasts();
Expr *RE = BO->getRHS()->IgnoreParenImpCasts();
@@ -21403,7 +21689,7 @@ static void checkMappableExpressionList(
CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId,
ArrayRef<Expr *> UnresolvedMappers,
OpenMPMapClauseKind MapType = OMPC_MAP_unknown,
- ArrayRef<OpenMPMapModifierKind> Modifiers = None,
+ ArrayRef<OpenMPMapModifierKind> Modifiers = std::nullopt,
bool IsMapTypeImplicit = false, bool NoDiagnose = false) {
// We only expect mappable expressions in 'to', 'from', and 'map' clauses.
assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) &&
@@ -21603,10 +21889,12 @@ static void checkMappableExpressionList(
// target enter data
// OpenMP [2.10.2, Restrictions, p. 99]
// A map-type must be specified in all map clauses and must be either
- // to or alloc.
+ // to or alloc. Starting with OpenMP 5.2 the default map type is `to` if
+ // no map type is present.
OpenMPDirectiveKind DKind = DSAS->getCurrentDirective();
if (DKind == OMPD_target_enter_data &&
- !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc)) {
+ !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc ||
+ SemaRef.getLangOpts().OpenMP >= 52)) {
SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
<< (IsMapTypeImplicit ? 1 : 0)
<< getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
@@ -21617,10 +21905,11 @@ static void checkMappableExpressionList(
// target exit_data
// OpenMP [2.10.3, Restrictions, p. 102]
// A map-type must be specified in all map clauses and must be either
- // from, release, or delete.
+ // from, release, or delete. Starting with OpenMP 5.2 the default map
+ // type is `from` if no map type is present.
if (DKind == OMPD_target_exit_data &&
!(MapType == OMPC_MAP_from || MapType == OMPC_MAP_release ||
- MapType == OMPC_MAP_delete)) {
+ MapType == OMPC_MAP_delete || SemaRef.getLangOpts().OpenMP >= 52)) {
SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
<< (IsMapTypeImplicit ? 1 : 0)
<< getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
@@ -21698,7 +21987,7 @@ static void checkMappableExpressionList(
/*WhereFoundClauseKind=*/OMPC_map);
// Save the components and declaration to create the clause. For purposes of
- // the clause creation, any component list that has has base 'this' uses
+ // the clause creation, any component list that has base 'this' uses
// null as base declaration.
MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
MVLI.VarComponents.back().append(CurComponents.begin(),
@@ -21709,7 +21998,7 @@ static void checkMappableExpressionList(
}
OMPClause *Sema::ActOnOpenMPMapClause(
- ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
+ Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
ArrayRef<SourceLocation> MapTypeModifiersLoc,
CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId,
OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc,
@@ -21719,9 +22008,14 @@ OMPClause *Sema::ActOnOpenMPMapClause(
OpenMPMapModifierKind Modifiers[] = {
OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown,
OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown,
- OMPC_MAP_MODIFIER_unknown};
+ OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown};
SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers];
+ if (IteratorModifier && !IteratorModifier->getType()->isSpecificBuiltinType(
+ BuiltinType::OMPIterator))
+ Diag(IteratorModifier->getExprLoc(),
+ diag::err_omp_map_modifier_not_iterator);
+
// Process map-type-modifiers, flag errors for duplicate modifiers.
unsigned Count = 0;
for (unsigned I = 0, E = MapTypeModifiers.size(); I < E; ++I) {
@@ -21745,11 +22039,11 @@ OMPClause *Sema::ActOnOpenMPMapClause(
// We need to produce a map clause even if we don't have variables so that
// other diagnostics related with non-existing map clauses are accurate.
- return OMPMapClause::Create(Context, Locs, MVLI.ProcessedVarList,
- MVLI.VarBaseDeclarations, MVLI.VarComponents,
- MVLI.UDMapperList, Modifiers, ModifiersLoc,
- MapperIdScopeSpec.getWithLocInContext(Context),
- MapperId, MapType, IsMapTypeImplicit, MapLoc);
+ return OMPMapClause::Create(
+ Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents, MVLI.UDMapperList, IteratorModifier, Modifiers,
+ ModifiersLoc, MapperIdScopeSpec.getWithLocInContext(Context), MapperId,
+ MapType, IsMapTypeImplicit, MapLoc);
}
QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
@@ -22143,6 +22437,11 @@ Sema::ActOnOpenMPDeclareMapperDirectiveVarDecl(Scope *S, QualType MapperType,
return E;
}
+void Sema::ActOnOpenMPIteratorVarDecl(VarDecl *VD) {
+ if (DSAStack->getDeclareMapperVarRef())
+ DSAStack->addIteratorVarDecl(VD);
+}
+
bool Sema::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const {
assert(LangOpts.OpenMP && "Expected OpenMP mode.");
const Expr *Ref = DSAStack->getDeclareMapperVarRef();
@@ -22151,6 +22450,8 @@ bool Sema::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const {
return true;
if (VD->isUsableInConstantExpressions(Context))
return true;
+ if (LangOpts.OpenMP >= 52 && DSAStack->isIteratorVarDecl(VD))
+ return true;
return false;
}
return true;
@@ -22235,10 +22536,21 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority,
StartLoc, LParenLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+OMPClause *Sema::ActOnOpenMPGrainsizeClause(
+ OpenMPGrainsizeClauseModifier Modifier, Expr *Grainsize,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ModifierLoc, SourceLocation EndLoc) {
+ assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 51) &&
+ "Unexpected grainsize modifier in OpenMP < 51.");
+
+ if (ModifierLoc.isValid() && Modifier == OMPC_GRAINSIZE_unknown) {
+ std::string Values = getListOfPossibleValues(OMPC_grainsize, /*First=*/0,
+ OMPC_GRAINSIZE_unknown);
+ Diag(ModifierLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_grainsize);
+ return nullptr;
+ }
+
Expr *ValExpr = Grainsize;
Stmt *HelperValStmt = nullptr;
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
@@ -22246,20 +22558,33 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
// 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, /*BuildCapture=*/true,
- DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
+ if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize,
+ /*StrictlyPositive=*/true,
+ /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(),
+ &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPGrainsizeClause(ValExpr, HelperValStmt, CaptureRegion,
- StartLoc, LParenLoc, EndLoc);
+ return new (Context)
+ OMPGrainsizeClause(Modifier, ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, ModifierLoc, EndLoc);
}
-OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+OMPClause *Sema::ActOnOpenMPNumTasksClause(
+ OpenMPNumTasksClauseModifier Modifier, Expr *NumTasks,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ModifierLoc, SourceLocation EndLoc) {
+ assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 51) &&
+ "Unexpected num_tasks modifier in OpenMP < 51.");
+
+ if (ModifierLoc.isValid() && Modifier == OMPC_NUMTASKS_unknown) {
+ std::string Values = getListOfPossibleValues(OMPC_num_tasks, /*First=*/0,
+ OMPC_NUMTASKS_unknown);
+ Diag(ModifierLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_num_tasks);
+ return nullptr;
+ }
+
Expr *ValExpr = NumTasks;
Stmt *HelperValStmt = nullptr;
OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
@@ -22273,8 +22598,9 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPNumTasksClause(ValExpr, HelperValStmt, CaptureRegion,
- StartLoc, LParenLoc, EndLoc);
+ return new (Context)
+ OMPNumTasksClause(Modifier, ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, ModifierLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
@@ -22384,7 +22710,7 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause(
// OpenMP [2.7.1, Restrictions]
// chunk_size must be a loop invariant integer expression with a positive
// value.
- if (Optional<llvm::APSInt> Result =
+ if (std::optional<llvm::APSInt> Result =
ValExpr->getIntegerConstantExpr(Context)) {
if (Result->isSigned() && !Result->isStrictlyPositive()) {
Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
@@ -22583,29 +22909,29 @@ void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
const unsigned Level = -1;
auto *VD = cast<ValueDecl>(ND);
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
- if (ActiveAttr && ActiveAttr.value()->getDevType() != DTCI.DT &&
- ActiveAttr.value()->getLevel() == Level) {
+ if (ActiveAttr && (*ActiveAttr)->getDevType() != DTCI.DT &&
+ (*ActiveAttr)->getLevel() == Level) {
Diag(Loc, diag::err_omp_device_type_mismatch)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DTCI.DT)
<< OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(
- ActiveAttr.value()->getDevType());
+ (*ActiveAttr)->getDevType());
return;
}
- if (ActiveAttr && ActiveAttr.value()->getMapType() != MT &&
- ActiveAttr.value()->getLevel() == Level) {
+ if (ActiveAttr && (*ActiveAttr)->getMapType() != MT &&
+ (*ActiveAttr)->getLevel() == Level) {
Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
return;
}
- if (ActiveAttr && ActiveAttr.value()->getLevel() == Level)
+ if (ActiveAttr && (*ActiveAttr)->getLevel() == Level)
return;
Expr *IndirectE = nullptr;
bool IsIndirect = false;
if (DTCI.Indirect) {
- IndirectE = DTCI.Indirect.value();
+ IndirectE = *DTCI.Indirect;
if (!IndirectE)
IsIndirect = true;
}
@@ -22623,13 +22949,14 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
if (!D || !isa<VarDecl>(D))
return;
auto *VD = cast<VarDecl>(D);
- Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (SemaRef.LangOpts.OpenMP >= 50 &&
(SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) ||
SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) &&
VD->hasGlobalStorage()) {
- if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) {
+ if (!MapTy || (*MapTy != OMPDeclareTargetDeclAttr::MT_To &&
+ *MapTy != OMPDeclareTargetDeclAttr::MT_Enter)) {
// 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
@@ -22678,7 +23005,7 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
D = FTD->getTemplatedDecl();
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD);
if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
Diag(IdLoc, diag::err_omp_function_in_link_clause);
@@ -22696,22 +23023,25 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
// Checking declaration inside declare target region.
if (isa<VarDecl>(D) || isa<FunctionDecl>(D) ||
isa<FunctionTemplateDecl>(D)) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr =
OMPDeclareTargetDeclAttr::getActiveAttr(VD);
unsigned Level = DeclareTargetNesting.size();
- if (ActiveAttr && ActiveAttr.value()->getLevel() >= Level)
+ if (ActiveAttr && (*ActiveAttr)->getLevel() >= Level)
return;
DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back();
Expr *IndirectE = nullptr;
bool IsIndirect = false;
if (DTCI.Indirect) {
- IndirectE = DTCI.Indirect.value();
+ IndirectE = *DTCI.Indirect;
if (!IndirectE)
IsIndirect = true;
}
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
- Context, OMPDeclareTargetDeclAttr::MT_To, DTCI.DT, IndirectE,
- IsIndirect, Level, SourceRange(DTCI.Loc, DTCI.Loc));
+ Context,
+ getLangOpts().OpenMP >= 52 ? OMPDeclareTargetDeclAttr::MT_Enter
+ : OMPDeclareTargetDeclAttr::MT_To,
+ DTCI.DT, IndirectE, IsIndirect, Level,
+ SourceRange(DTCI.Loc, DTCI.Loc));
D->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
@@ -23065,13 +23395,17 @@ OMPClause *Sema::ActOnOpenMPHasDeviceAddrClause(ArrayRef<Expr *> VarList,
// Store the components in the stack so that they can be used to check
// against other clauses later on.
+ Expr *Component = SimpleRefExpr;
+ auto *VD = dyn_cast<VarDecl>(D);
+ if (VD && (isa<OMPArraySectionExpr>(RefExpr->IgnoreParenImpCasts()) ||
+ isa<ArraySubscriptExpr>(RefExpr->IgnoreParenImpCasts())))
+ Component = DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get();
OMPClauseMappableExprCommon::MappableComponent MC(
- SimpleRefExpr, D, /*IsNonContiguous=*/false);
+ Component, D, /*IsNonContiguous=*/false);
DSAStack->addMappableExpressionComponents(
D, MC, /*WhereFoundClauseKind=*/OMPC_has_device_addr);
// Record the expression we've just processed.
- auto *VD = dyn_cast<VarDecl>(D);
if (!VD && !CurContext->isDependentContext()) {
DeclRefExpr *Ref =
buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
@@ -23336,17 +23670,26 @@ OMPClause *Sema::ActOnOpenMPUsesAllocatorClause(
AllocatorExpr = D.Allocator->IgnoreParenImpCasts();
auto *DRE = dyn_cast<DeclRefExpr>(AllocatorExpr);
bool IsPredefinedAllocator = false;
- if (DRE)
- IsPredefinedAllocator = PredefinedAllocators.count(DRE->getDecl());
- if (!DRE ||
- !(Context.hasSameUnqualifiedType(
- AllocatorExpr->getType(), DSAStack->getOMPAllocatorHandleT()) ||
- Context.typesAreCompatible(AllocatorExpr->getType(),
- DSAStack->getOMPAllocatorHandleT(),
- /*CompareUnqualified=*/true)) ||
- (!IsPredefinedAllocator &&
- (AllocatorExpr->getType().isConstant(Context) ||
- !AllocatorExpr->isLValue()))) {
+ if (DRE) {
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorTy =
+ getAllocatorKind(*this, DSAStack, AllocatorExpr);
+ IsPredefinedAllocator =
+ AllocatorTy !=
+ OMPAllocateDeclAttr::AllocatorTypeTy::OMPUserDefinedMemAlloc;
+ }
+ QualType OMPAllocatorHandleT = DSAStack->getOMPAllocatorHandleT();
+ QualType AllocatorExprType = AllocatorExpr->getType();
+ bool IsTypeCompatible = IsPredefinedAllocator;
+ IsTypeCompatible = IsTypeCompatible ||
+ Context.hasSameUnqualifiedType(AllocatorExprType,
+ OMPAllocatorHandleT);
+ IsTypeCompatible =
+ IsTypeCompatible ||
+ Context.typesAreCompatible(AllocatorExprType, OMPAllocatorHandleT);
+ bool IsNonConstantLValue =
+ !AllocatorExprType.isConstant(Context) && AllocatorExpr->isLValue();
+ if (!DRE || !IsTypeCompatible ||
+ (!IsPredefinedAllocator && !IsNonConstantLValue)) {
Diag(D.Allocator->getExprLoc(), diag::err_omp_var_expected)
<< "omp_allocator_handle_t" << (DRE ? 1 : 0)
<< AllocatorExpr->getType() << D.Allocator->getSourceRange();
@@ -23480,3 +23823,31 @@ OMPClause *Sema::ActOnOpenMPBindClause(OpenMPBindClauseKind Kind,
return OMPBindClause::Create(Context, Kind, KindLoc, StartLoc, LParenLoc,
EndLoc);
}
+
+OMPClause *Sema::ActOnOpenMPXDynCGroupMemClause(Expr *Size,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ Expr *ValExpr = Size;
+ Stmt *HelperValStmt = nullptr;
+
+ // OpenMP [2.5, Restrictions]
+ // The ompx_dyn_cgroup_mem expression must evaluate to a positive integer
+ // value.
+ if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_ompx_dyn_cgroup_mem,
+ /*StrictlyPositive=*/false))
+ return nullptr;
+
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
+ DKind, OMPC_ompx_dyn_cgroup_mem, LangOpts.OpenMP);
+ 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) OMPXDynCGroupMemClause(
+ ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
+}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d72cc33ed0f5..d68337a26d97 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12,14 +12,17 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DependenceFlags.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -30,12 +33,13 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Casting.h"
#include <algorithm>
#include <cstdlib>
+#include <optional>
using namespace clang;
using namespace sema;
@@ -63,9 +67,8 @@ static ExprResult CreateFunctionRefExpr(
// being used.
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
- DeclRefExpr *DRE =
- DeclRefExpr::Create(S.Context, Fn->getQualifierLoc(), SourceLocation(),
- Fn, false, Loc, Fn->getType(), VK_LValue, FoundDecl);
+ DeclRefExpr *DRE = new (S.Context)
+ DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
@@ -355,7 +358,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
- if (Optional<llvm::APSInt> IntConstantValue =
+ if (std::optional<llvm::APSInt> IntConstantValue =
Initializer->getIntegerConstantExpr(Ctx)) {
// Convert the integer to the floating type.
llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType));
@@ -438,7 +441,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
if (Initializer->isValueDependent())
return NK_Dependent_Narrowing;
- Optional<llvm::APSInt> OptInitializerValue;
+ std::optional<llvm::APSInt> OptInitializerValue;
if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) {
// Such conversions on variables are always narrowing.
return NK_Variable_Narrowing;
@@ -637,7 +640,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
auto *Saved = new (Context) DFIDeducedMismatchArgs;
Saved->FirstArg = Info.FirstArg;
Saved->SecondArg = Info.SecondArg;
- Saved->TemplateArgs = Info.take();
+ Saved->TemplateArgs = Info.takeSugared();
Saved->CallArgIndex = Info.CallArgIndex;
Result.Data = Saved;
break;
@@ -666,7 +669,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
}
case Sema::TDK_SubstitutionFailure:
- Result.Data = Info.take();
+ Result.Data = Info.takeSugared();
if (Info.hasSFINAEDiagnostic()) {
PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt(
SourceLocation(), PartialDiagnostic::NullDiagnostic());
@@ -677,7 +680,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
case Sema::TDK_ConstraintsNotSatisfied: {
CNSInfo *Saved = new (Context) CNSInfo;
- Saved->TemplateArgs = Info.take();
+ Saved->TemplateArgs = Info.takeSugared();
Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction;
Result.Data = Saved;
break;
@@ -685,6 +688,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context,
case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
llvm_unreachable("not a deduction failure");
}
@@ -734,6 +738,7 @@ void DeductionFailureInfo::Destroy() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
}
@@ -771,6 +776,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
@@ -806,6 +812,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
@@ -837,6 +844,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
@@ -868,24 +876,95 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() {
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
break;
}
return nullptr;
}
-llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
+std::optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
case Sema::TDK_DeducedMismatch:
case Sema::TDK_DeducedMismatchNested:
return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex;
default:
- return llvm::None;
+ return std::nullopt;
}
}
-bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
+static bool FunctionsCorrespond(ASTContext &Ctx, const FunctionDecl *X,
+ const FunctionDecl *Y) {
+ if (!X || !Y)
+ return false;
+ if (X->getNumParams() != Y->getNumParams())
+ return false;
+ for (unsigned I = 0; I < X->getNumParams(); ++I)
+ if (!Ctx.hasSameUnqualifiedType(X->getParamDecl(I)->getType(),
+ Y->getParamDecl(I)->getType()))
+ return false;
+ if (auto *FTX = X->getDescribedFunctionTemplate()) {
+ auto *FTY = Y->getDescribedFunctionTemplate();
+ if (!FTY)
+ return false;
+ if (!Ctx.isSameTemplateParameterList(FTX->getTemplateParameters(),
+ FTY->getTemplateParameters()))
+ return false;
+ }
+ return true;
+}
+
+static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc,
+ Expr *FirstOperand, FunctionDecl *EqFD) {
+ assert(EqFD->getOverloadedOperator() ==
+ OverloadedOperatorKind::OO_EqualEqual);
+ // C++2a [over.match.oper]p4:
+ // A non-template function or function template F named operator== is a
+ // rewrite target with first operand o unless a search for the name operator!=
+ // in the scope S from the instantiation context of the operator expression
+ // finds a function or function template that would correspond
+ // ([basic.scope.scope]) to F if its name were operator==, where S is the
+ // scope of the class type of o if F is a class member, and the namespace
+ // scope of which F is a member otherwise. A function template specialization
+ // named operator== is a rewrite target if its function template is a rewrite
+ // target.
+ DeclarationName NotEqOp = S.Context.DeclarationNames.getCXXOperatorName(
+ OverloadedOperatorKind::OO_ExclaimEqual);
+ if (isa<CXXMethodDecl>(EqFD)) {
+ // If F is a class member, search scope is class type of first operand.
+ QualType RHS = FirstOperand->getType();
+ auto *RHSRec = RHS->getAs<RecordType>();
+ if (!RHSRec)
+ return true;
+ LookupResult Members(S, NotEqOp, OpLoc,
+ Sema::LookupNameKind::LookupMemberName);
+ S.LookupQualifiedName(Members, RHSRec->getDecl());
+ Members.suppressDiagnostics();
+ for (NamedDecl *Op : Members)
+ if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction()))
+ return false;
+ return true;
+ }
+ // Otherwise the search scope is the namespace scope of which F is a member.
+ LookupResult NonMembers(S, NotEqOp, OpLoc,
+ Sema::LookupNameKind::LookupOperatorName);
+ S.LookupName(NonMembers,
+ S.getScopeForContext(EqFD->getEnclosingNamespaceContext()));
+ NonMembers.suppressDiagnostics();
+ for (NamedDecl *Op : NonMembers) {
+ auto *FD = Op->getAsFunction();
+ if(auto* UD = dyn_cast<UsingShadowDecl>(Op))
+ FD = UD->getUnderlyingDecl()->getAsFunction();
+ if (FunctionsCorrespond(S.Context, EqFD, FD) &&
+ declaresSameEntity(cast<Decl>(EqFD->getDeclContext()),
+ cast<Decl>(Op->getDeclContext())))
+ return false;
+ }
+ return true;
+}
+
+bool OverloadCandidateSet::OperatorRewriteInfo::allowsReversed(
OverloadedOperatorKind Op) {
if (!AllowRewrittenCandidates)
return false;
@@ -893,14 +972,21 @@ bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
}
bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
- ASTContext &Ctx, const FunctionDecl *FD) {
- if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator()))
+ Sema &S, ArrayRef<Expr *> OriginalArgs, FunctionDecl *FD) {
+ auto Op = FD->getOverloadedOperator();
+ if (!allowsReversed(Op))
return false;
+ if (Op == OverloadedOperatorKind::OO_EqualEqual) {
+ assert(OriginalArgs.size() == 2);
+ if (!shouldAddReversedEqEq(
+ S, OpLoc, /*FirstOperand in reversed args*/ OriginalArgs[1], FD))
+ 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()) ||
+ !S.Context.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),
+ FD->getParamDecl(1)->getType()) ||
FD->hasAttr<EnableIfAttr>();
}
@@ -1069,6 +1155,15 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
!shouldLinkPossiblyHiddenDecl(*I, New))
continue;
+ // C++20 [temp.friend] p9: A non-template friend declaration with a
+ // requires-clause shall be a definition. A friend function template
+ // with a constraint that depends on a template parameter from an
+ // enclosing template shall be a definition. Such a constrained friend
+ // function or function template declaration does not declare the same
+ // function or function template as a declaration in any other scope.
+ if (Context.FriendsDifferByConstraints(OldF, New))
+ continue;
+
Match = *I;
return Ovl_Match;
}
@@ -1185,25 +1280,52 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
!FunctionParamTypesAreEqual(OldType, NewType)))
return true;
- // C++ [temp.over.link]p4:
- // The signature of a function template consists of its function
- // signature, its return type and its template parameter list. The names
- // of the template parameters are significant only for establishing the
- // relationship between the template parameters and the rest of the
- // signature.
- //
- // We check the return type and template parameter lists for function
- // templates first; the remaining checks follow.
- //
- // However, we don't consider either of these when deciding whether
- // a member introduced by a shadow declaration is hidden.
- if (!UseMemberUsingDeclRules && NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- false, TPL_TemplateMatch) ||
- !Context.hasSameType(Old->getDeclaredReturnType(),
- New->getDeclaredReturnType())))
- return true;
+ if (NewTemplate) {
+ // C++ [temp.over.link]p4:
+ // The signature of a function template consists of its function
+ // signature, its return type and its template parameter list. The names
+ // of the template parameters are significant only for establishing the
+ // relationship between the template parameters and the rest of the
+ // signature.
+ //
+ // We check the return type and template parameter lists for function
+ // templates first; the remaining checks follow.
+ bool SameTemplateParameterList = TemplateParameterListsAreEqual(
+ NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(), false, TPL_TemplateMatch);
+ bool SameReturnType = Context.hasSameType(Old->getDeclaredReturnType(),
+ New->getDeclaredReturnType());
+ // FIXME(GH58571): Match template parameter list even for non-constrained
+ // template heads. This currently ensures that the code prior to C++20 is
+ // not newly broken.
+ bool ConstraintsInTemplateHead =
+ NewTemplate->getTemplateParameters()->hasAssociatedConstraints() ||
+ OldTemplate->getTemplateParameters()->hasAssociatedConstraints();
+ // C++ [namespace.udecl]p11:
+ // The set of declarations named by a using-declarator that inhabits a
+ // class C does not include member functions and member function
+ // templates of a base class that "correspond" to (and thus would
+ // conflict with) a declaration of a function or function template in
+ // C.
+ // Comparing return types is not required for the "correspond" check to
+ // decide whether a member introduced by a shadow declaration is hidden.
+ if (UseMemberUsingDeclRules && ConstraintsInTemplateHead &&
+ !SameTemplateParameterList)
+ return true;
+ if (!UseMemberUsingDeclRules &&
+ (!SameTemplateParameterList || !SameReturnType))
+ return true;
+ }
+
+ if (ConsiderRequiresClauses) {
+ Expr *NewRC = New->getTrailingRequiresClause(),
+ *OldRC = Old->getTrailingRequiresClause();
+ if ((NewRC != nullptr) != (OldRC != nullptr))
+ return true;
+
+ if (NewRC && !AreConstraintExpressionsEqual(Old, OldRC, New, NewRC))
+ return true;
+ }
// If the function is a class member, its signature includes the
// cv-qualifiers (if any) and ref-qualifier (if any) on the function itself.
@@ -1221,14 +1343,15 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
if (!UseMemberUsingDeclRules &&
(OldMethod->getRefQualifier() == RQ_None ||
NewMethod->getRefQualifier() == RQ_None)) {
- // C++0x [over.load]p2:
- // - Member function declarations with the same name and the same
- // parameter-type-list as well as member function template
- // declarations with the same name, the same parameter-type-list, and
- // the same template parameter lists cannot be overloaded if any of
- // them, but not all, have a ref-qualifier (8.3.5).
+ // C++20 [over.load]p2:
+ // - Member function declarations with the same name, the same
+ // parameter-type-list, and the same trailing requires-clause (if
+ // any), as well as member function template declarations with the
+ // same name, the same parameter-type-list, the same trailing
+ // requires-clause (if any), and the same template-head, cannot be
+ // overloaded if any of them, but not all, have a ref-qualifier.
Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
- << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
+ << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
Diag(OldMethod->getLocation(), diag::note_previous_declaration);
}
return true;
@@ -1292,23 +1415,6 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
}
}
- if (ConsiderRequiresClauses) {
- Expr *NewRC = New->getTrailingRequiresClause(),
- *OldRC = Old->getTrailingRequiresClause();
- if ((NewRC != nullptr) != (OldRC != nullptr))
- // RC are most certainly different - these are overloads.
- return true;
-
- if (NewRC) {
- llvm::FoldingSetNodeID NewID, OldID;
- NewRC->Profile(NewID, Context, /*Canonical=*/true);
- OldRC->Profile(OldID, Context, /*Canonical=*/true);
- if (NewID != OldID)
- // RCs are not equivalent - these are overloads.
- return true;
- }
- }
-
// The signatures match; this is not an overload.
return false;
}
@@ -1620,7 +1726,7 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
/// conversion.
static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
ImplicitConversionKind &ICK, Expr *From,
- bool InOverloadResolution) {
+ bool InOverloadResolution, bool CStyle) {
// We need at least one of these types to be a vector type to have a vector
// conversion.
if (!ToType->isVectorType() && !FromType->isVectorType())
@@ -1665,7 +1771,7 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
if (S.isLaxVectorConversion(FromType, ToType) &&
S.anyAltivecTypes(FromType, ToType) &&
!S.areSameVectorElemTypes(FromType, ToType) &&
- !InOverloadResolution) {
+ !InOverloadResolution && !CStyle) {
S.Diag(From->getBeginLoc(), diag::warn_deprecated_lax_vec_conv_all)
<< FromType << ToType;
}
@@ -1918,7 +2024,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// Pointer to member conversions (4.11).
SCS.Second = ICK_Pointer_Member;
} else if (IsVectorConversion(S, FromType, ToType, SecondICK, From,
- InOverloadResolution)) {
+ InOverloadResolution, CStyle)) {
SCS.Second = SecondICK;
FromType = ToType.getUnqualifiedType();
} else if (!S.getLangOpts().CPlusPlus &&
@@ -2073,9 +2179,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// int can represent all the values of the source type; otherwise,
// the source rvalue can be converted to an rvalue of type unsigned
// int (C++ 4.5p1).
- if (FromType->isPromotableIntegerType() && !FromType->isBooleanType() &&
+ if (Context.isPromotableIntegerType(FromType) && !FromType->isBooleanType() &&
!FromType->isEnumeralType()) {
- if (// We can promote any signed, promotable integer type to an int
+ if ( // We can promote any signed, promotable integer type to an int
(FromType->isSignedIntegerType() ||
// We can promote any unsigned integer type whose size is
// less than int to an int.
@@ -2187,7 +2293,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
// compatibility.
if (From) {
if (FieldDecl *MemberDecl = From->getSourceBitField()) {
- Optional<llvm::APSInt> BitWidth;
+ std::optional<llvm::APSInt> BitWidth;
if (FromType->isIntegralType(Context) &&
(BitWidth =
MemberDecl->getBitWidth()->getIntegerConstantExpr(Context))) {
@@ -3506,7 +3612,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
- /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs),
+ /*ExplicitArgs*/ nullptr, llvm::ArrayRef(Args, NumArgs),
CandidateSet, SuppressUserConversions,
/*PartialOverloading*/ false,
AllowExplicit == AllowedExplicit::All);
@@ -3514,8 +3620,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
- llvm::makeArrayRef(Args, NumArgs),
- CandidateSet, SuppressUserConversions,
+ llvm::ArrayRef(Args, NumArgs), CandidateSet,
+ SuppressUserConversions,
/*PartialOverloading*/ false,
AllowExplicit == AllowedExplicit::All);
}
@@ -4495,15 +4601,6 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
return ImplicitConversionSequence::Indistinguishable;
}
-/// Determine whether the given type is valid, e.g., it is not an invalid
-/// C++ class.
-static bool isTypeValid(QualType T) {
- if (CXXRecordDecl *Record = T->getAsCXXRecordDecl())
- return !Record->isInvalidDecl();
-
- return true;
-}
-
static QualType withoutUnaligned(ASTContext &Ctx, QualType T) {
if (!T.getQualifiers().hasUnaligned())
return T;
@@ -4553,7 +4650,6 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (isCompleteType(Loc, OrigT2) &&
- isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
IsDerivedFrom(Loc, UnqualT2, UnqualT1))
Conv |= ReferenceConversions::DerivedToBase;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
@@ -5096,7 +5192,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
}
if (CT->getSize().ugt(e)) {
// Need an init from empty {}, is there one?
- InitListExpr EmptyList(S.Context, From->getEndLoc(), None,
+ InitListExpr EmptyList(S.Context, From->getEndLoc(), std::nullopt,
From->getEndLoc());
EmptyList.setType(S.Context.VoidTy);
DfltElt = TryListConversion(
@@ -5725,7 +5821,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
return ExprError();
case ImplicitConversionSequence::EllipsisConversion:
- llvm_unreachable("ellipsis conversion in converted constant expression");
+ case ImplicitConversionSequence::StaticObjectArgumentConversion:
+ llvm_unreachable("bad conversion in converted constant expression");
}
// Check that we would only use permitted conversions.
@@ -5760,9 +5857,9 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
// C++2a [intro.execution]p5:
// A full-expression is [...] a constant-expression [...]
- Result =
- S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(),
- /*DiscardedValue=*/false, /*IsConstexpr=*/true);
+ Result = S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(),
+ /*DiscardedValue=*/false, /*IsConstexpr=*/true,
+ CCE == Sema::CCEKind::CCEK_TemplateArg);
if (Result.isInvalid())
return Result;
@@ -5909,6 +6006,7 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
case ImplicitConversionSequence::BadConversion:
case ImplicitConversionSequence::AmbiguousConversion:
case ImplicitConversionSequence::EllipsisConversion:
+ case ImplicitConversionSequence::StaticObjectArgumentConversion:
break;
case ImplicitConversionSequence::UserDefinedConversion:
@@ -6242,7 +6340,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
HadMultipleCandidates,
ExplicitConversions))
return ExprError();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OR_Deleted:
// We'll complain below about a non-integral condition type.
break;
@@ -6422,8 +6520,11 @@ void Sema::AddOverloadCandidate(
}
}
- if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
- !Function->getAttr<TargetAttr>()->isDefaultVersion()) {
+ if (Function->isMultiVersion() &&
+ ((Function->hasAttr<TargetAttr>() &&
+ !Function->getAttr<TargetAttr>()->isDefaultVersion()) ||
+ (Function->hasAttr<TargetVersionAttr>() &&
+ !Function->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
return;
@@ -6516,7 +6617,8 @@ void Sema::AddOverloadCandidate(
if (Function->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(Function, Satisfaction) ||
+ if (CheckFunctionConstraints(Function, Satisfaction, /*Loc*/ {},
+ /*ForOverloadResolution*/ true) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -6742,7 +6844,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function,
// very difficult. Ideally, we should handle them more gracefully.
if (EIA->getCond()->isValueDependent() ||
!EIA->getCond()->EvaluateWithSubstitution(
- Result, Context, Function, llvm::makeArrayRef(ConvertedArgs)))
+ Result, Context, Function, llvm::ArrayRef(ConvertedArgs)))
return EIA;
if (!Result.isInt() || !Result.getInt().getBoolValue())
@@ -6914,7 +7016,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, ObjectClassification, Args, CandidateSet,
- SuppressUserConversions, false, None, PO);
+ SuppressUserConversions, false, std::nullopt, PO);
}
}
@@ -6994,17 +7096,27 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.Viable = true;
- if (Method->isStatic() || ObjectType.isNull())
- // The implicit object argument is ignored.
+ unsigned FirstConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
+ if (ObjectType.isNull())
Candidate.IgnoreObjectArgument = true;
- else {
- unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
+ else if (Method->isStatic()) {
+ // [over.best.ics.general]p8
+ // When the parameter is the implicit object parameter of a static member
+ // function, the implicit conversion sequence is a standard conversion
+ // sequence that is neither better nor worse than any other standard
+ // conversion sequence.
+ //
+ // This is a rule that was introduced in C++23 to support static lambdas. We
+ // apply it retroactively because we want to support static lambdas as an
+ // extension and it doesn't hurt previous code.
+ Candidate.Conversions[FirstConvIdx].setStaticObjectArgument();
+ } else {
// Determine the implicit conversion sequence for the object
// parameter.
- Candidate.Conversions[ConvIdx] = TryObjectArgumentInitialization(
+ Candidate.Conversions[FirstConvIdx] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext);
- if (Candidate.Conversions[ConvIdx].isBad()) {
+ if (Candidate.Conversions[FirstConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
@@ -7022,7 +7134,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
if (Method->getTrailingRequiresClause()) {
ConstraintSatisfaction Satisfaction;
- if (CheckFunctionConstraints(Method, Satisfaction) ||
+ if (CheckFunctionConstraints(Method, Satisfaction, /*Loc*/ {},
+ /*ForOverloadResolution*/ true) ||
!Satisfaction.IsSatisfied) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_constraints_not_satisfied;
@@ -7071,8 +7184,11 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
return;
}
- if (Method->isMultiVersion() && Method->hasAttr<TargetAttr>() &&
- !Method->getAttr<TargetAttr>()->isDefaultVersion()) {
+ if (Method->isMultiVersion() &&
+ ((Method->hasAttr<TargetAttr>() &&
+ !Method->getAttr<TargetAttr>()->isDefaultVersion()) ||
+ (Method->hasAttr<TargetVersionAttr>() &&
+ !Method->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
}
@@ -7518,15 +7634,18 @@ void Sema::AddConversionCandidate(
}
if (EnableIfAttr *FailedAttr =
- CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) {
+ CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
- if (Conversion->isMultiVersion() && Conversion->hasAttr<TargetAttr>() &&
- !Conversion->getAttr<TargetAttr>()->isDefaultVersion()) {
+ if (Conversion->isMultiVersion() &&
+ ((Conversion->hasAttr<TargetAttr>() &&
+ !Conversion->getAttr<TargetAttr>()->isDefaultVersion()) ||
+ (Conversion->hasAttr<TargetVersionAttr>() &&
+ !Conversion->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_non_default_multiversion_function;
}
@@ -7689,7 +7808,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
if (EnableIfAttr *FailedAttr =
- CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) {
+ CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_enable_if;
Candidate.DeductionFailure.Data = FailedAttr;
@@ -7721,7 +7840,7 @@ void Sema::AddNonMemberOperatorCandidates(
if (FunTmpl) {
AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs,
FunctionArgs, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD))
AddTemplateOverloadCandidate(
FunTmpl, F.getPair(), ExplicitTemplateArgs,
{FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false,
@@ -7730,11 +7849,11 @@ void Sema::AddNonMemberOperatorCandidates(
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);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD))
+ AddOverloadCandidate(
+ FD, F.getPair(), {FunctionArgs[1], FunctionArgs[0]}, CandidateSet,
+ false, false, true, false, ADLCallKind::NotADL, std::nullopt,
+ OverloadCandidateParamOrder::Reversed);
}
}
}
@@ -7781,12 +7900,17 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
Operators.suppressDiagnostics();
for (LookupResult::iterator Oper = Operators.begin(),
- OperEnd = Operators.end();
- Oper != OperEnd;
- ++Oper)
+ OperEnd = Operators.end();
+ Oper != OperEnd; ++Oper) {
+ if (Oper->getAsFunction() &&
+ PO == OverloadCandidateParamOrder::Reversed &&
+ !CandidateSet.getRewriteInfo().shouldAddReversed(
+ *this, {Args[1], Args[0]}, Oper->getAsFunction()))
+ continue;
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
Args[0]->Classify(Context), Args.slice(1),
CandidateSet, /*SuppressUserConversion=*/false, PO);
+ }
}
}
@@ -9312,7 +9436,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_Plus: // '+' is either unary or binary
if (Args.size() == 1)
OpBuilder.addUnaryPlusPointerOverloads();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OO_Minus: // '-' is either unary or binary
if (Args.size() == 1) {
@@ -9387,12 +9511,12 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
case OO_Equal:
OpBuilder.addAssignmentMemberPointerOrEnumeralOverloads();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OO_PlusEqual:
case OO_MinusEqual:
OpBuilder.addAssignmentPointerOverloads(Op == OO_Equal);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case OO_StarEqual:
case OO_SlashEqual:
@@ -9482,12 +9606,13 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false,
PartialOverloading, /*AllowExplicit=*/true,
/*AllowExplicitConversion=*/false, ADLCallKind::UsesADL);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) {
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) {
AddOverloadCandidate(
FD, FoundDecl, {Args[1], Args[0]}, CandidateSet,
/*SuppressUserConversions=*/false, PartialOverloading,
/*AllowExplicit=*/true, /*AllowExplicitConversion=*/false,
- ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed);
+ ADLCallKind::UsesADL, std::nullopt,
+ OverloadCandidateParamOrder::Reversed);
}
} else {
auto *FTD = cast<FunctionTemplateDecl>(*I);
@@ -9496,7 +9621,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
/*SuppressUserConversions=*/false, PartialOverloading,
/*AllowExplicit=*/true, ADLCallKind::UsesADL);
if (CandidateSet.getRewriteInfo().shouldAddReversed(
- Context, FTD->getTemplatedDecl())) {
+ *this, Args, FTD->getTemplatedDecl())) {
AddTemplateOverloadCandidate(
FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]},
CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading,
@@ -9538,8 +9663,8 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
llvm::FoldingSetNodeID Cand1ID, Cand2ID;
for (auto Pair : zip_longest(Cand1Attrs, Cand2Attrs)) {
- Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
- Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
+ std::optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
+ std::optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
// It's impossible for Cand1 to be better than (or equal to) Cand2 if Cand1
// has fewer enable_if attributes than Cand2, and vice versa.
@@ -9617,12 +9742,12 @@ isBetterMultiversionCandidate(const OverloadCandidate &Cand1,
}
/// Compute the type of the implicit object parameter for the given function,
-/// if any. Returns None if there is no implicit object parameter, and a null
-/// QualType if there is a 'matches anything' implicit object parameter.
-static Optional<QualType> getImplicitObjectParamType(ASTContext &Context,
- const FunctionDecl *F) {
+/// if any. Returns std::nullopt if there is no implicit object parameter, and a
+/// null QualType if there is a 'matches anything' implicit object parameter.
+static std::optional<QualType>
+getImplicitObjectParamType(ASTContext &Context, const FunctionDecl *F) {
if (!isa<CXXMethodDecl>(F) || isa<CXXConstructorDecl>(F))
- return llvm::None;
+ return std::nullopt;
auto *M = cast<CXXMethodDecl>(F);
// Static member functions' object parameters match all types.
@@ -9642,7 +9767,7 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
auto NextParam = [&](const FunctionDecl *F, unsigned &I, bool First) {
if (First) {
- if (Optional<QualType> T = getImplicitObjectParamType(Context, F))
+ if (std::optional<QualType> T = getImplicitObjectParamType(Context, F))
return *T;
}
assert(I < F->getNumParams());
@@ -9662,19 +9787,13 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1,
/// We're allowed to use constraints partial ordering only if the candidates
/// have the same parameter types:
-/// [temp.func.order]p6.2.2 [...] or if the function parameters that
-/// positionally correspond between the two templates are not of the same type,
-/// neither template is more specialized than the other.
/// [over.match.best]p2.6
/// F1 and F2 are non-template functions with the same parameter-type-lists,
/// and F1 is more constrained than F2 [...]
-static bool canCompareFunctionConstraints(Sema &S,
+static bool sameFunctionParameterTypeLists(Sema &S,
const OverloadCandidate &Cand1,
const OverloadCandidate &Cand2) {
- // FIXME: Per P2113R0 we also need to compare the template parameter lists
- // when comparing template functions.
- if (Cand1.Function && Cand2.Function && Cand1.Function->hasPrototype() &&
- Cand2.Function->hasPrototype()) {
+ if (Cand1.Function && Cand2.Function) {
auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType());
auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType());
if (PT1->getNumParams() == PT2->getNumParams() &&
@@ -9767,7 +9886,7 @@ bool clang::isBetterOverloadCandidate(
}
}
- // C++ [over.match.best]p1:
+ // C++ [over.match.best]p1: (Changed in C++2b)
//
// -- if F is a static member function, ICS1(F) is defined such
// that ICS1(F) is neither better nor worse than ICS1(G) for
@@ -9917,22 +10036,28 @@ bool clang::isBetterOverloadCandidate(
isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion
: TPOC_Call,
Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments,
- Cand1.isReversed() ^ Cand2.isReversed(),
- canCompareFunctionConstraints(S, Cand1, Cand2)))
+ Cand1.isReversed() ^ Cand2.isReversed()))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
// -— F1 and F2 are non-template functions with the same
// parameter-type-lists, and F1 is more constrained than F2 [...],
if (!Cand1IsSpecialization && !Cand2IsSpecialization &&
- canCompareFunctionConstraints(S, Cand1, Cand2)) {
- Expr *RC1 = Cand1.Function->getTrailingRequiresClause();
- Expr *RC2 = Cand2.Function->getTrailingRequiresClause();
+ sameFunctionParameterTypeLists(S, Cand1, Cand2)) {
+ FunctionDecl *Function1 = Cand1.Function;
+ FunctionDecl *Function2 = Cand2.Function;
+ if (FunctionDecl *MF = Function1->getInstantiatedFromMemberFunction())
+ Function1 = MF;
+ if (FunctionDecl *MF = Function2->getInstantiatedFromMemberFunction())
+ Function2 = MF;
+
+ const Expr *RC1 = Function1->getTrailingRequiresClause();
+ const Expr *RC2 = Function2->getTrailingRequiresClause();
if (RC1 && RC2) {
bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, {RC2},
+ if (S.IsAtLeastAsConstrained(Function1, RC1, Function2, RC2,
AtLeastAsConstrained1) ||
- S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, {RC1},
+ S.IsAtLeastAsConstrained(Function2, RC2, Function1, RC1,
AtLeastAsConstrained2))
return false;
if (AtLeastAsConstrained1 != AtLeastAsConstrained2)
@@ -10103,6 +10228,13 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
}
}
+bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const {
+ return FailureKind == ovl_fail_bad_deduction &&
+ DeductionFailure.Result == Sema::TDK_ConstraintsNotSatisfied &&
+ static_cast<CNSInfo *>(DeductionFailure.Data)
+ ->Satisfaction.ContainsErrors;
+}
+
/// Computes the best viable function (C++ 13.3.3)
/// within an overload candidate set.
///
@@ -10155,10 +10287,18 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
Best = end();
for (auto *Cand : Candidates) {
Cand->Best = false;
- if (Cand->Viable)
+ if (Cand->Viable) {
if (Best == end() ||
isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
Best = Cand;
+ } else if (Cand->NotValidBecauseConstraintExprHasError()) {
+ // This candidate has constraint that we were unable to evaluate because
+ // it referenced an expression that contained an error. Rather than fall
+ // back onto a potentially unintended candidate (made worse by
+ // subsuming constraints), treat this as 'no viable candidate'.
+ Best = end();
+ return OR_No_Viable_Function;
+ }
}
// If we didn't find any viable functions, abort.
@@ -10431,6 +10571,9 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
if (Fn->isMultiVersion() && Fn->hasAttr<TargetAttr>() &&
!Fn->getAttr<TargetAttr>()->isDefaultVersion())
return;
+ if (Fn->isMultiVersion() && Fn->hasAttr<TargetVersionAttr>() &&
+ !Fn->getAttr<TargetVersionAttr>()->isDefaultVersion())
+ return;
if (shouldSkipNotingLambdaConversionDecl(Fn))
return;
@@ -10774,10 +10917,13 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< ToTy << (unsigned)isObjectArgument << I + 1
<< (unsigned)(Cand->Fix.Kind);
- // If we can fix the conversion, suggest the FixIts.
- for (std::vector<FixItHint>::iterator HI = Cand->Fix.Hints.begin(),
- HE = Cand->Fix.Hints.end(); HI != HE; ++HI)
- FDiag << *HI;
+ // Check that location of Fn is not in system header.
+ if (!S.SourceMgr.isInSystemHeader(Fn->getLocation())) {
+ // If we can fix the conversion, suggest the FixIts.
+ for (const FixItHint &HI : Cand->Fix.Hints)
+ FDiag << HI;
+ }
+
S.Diag(Fn->getLocation(), FDiag);
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
@@ -11483,6 +11629,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) {
switch ((Sema::TemplateDeductionResult)DFI.Result) {
case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_AlreadyDiagnosed:
llvm_unreachable("non-deduction failure while diagnosing bad deduction");
case Sema::TDK_Invalid:
@@ -12239,6 +12386,9 @@ private:
const auto *TA = FunDecl->getAttr<TargetAttr>();
if (TA && !TA->isDefaultVersion())
return false;
+ const auto *TVA = FunDecl->getAttr<TargetVersionAttr>();
+ if (TVA && !TVA->isDefaultVersion())
+ return false;
}
// If any candidate has a placeholder return type, trigger its deduction
@@ -12501,20 +12651,24 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
DeclAccessPair DAP;
SmallVector<FunctionDecl *, 2> AmbiguousDecls;
- auto CheckMoreConstrained =
- [&] (FunctionDecl *FD1, FunctionDecl *FD2) -> Optional<bool> {
- SmallVector<const Expr *, 1> AC1, AC2;
- FD1->getAssociatedConstraints(AC1);
- FD2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1))
- return None;
- if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2))
- return None;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return None;
- return AtLeastAsConstrained1;
- };
+ auto CheckMoreConstrained = [&](FunctionDecl *FD1,
+ FunctionDecl *FD2) -> std::optional<bool> {
+ if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction())
+ FD1 = MF;
+ if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction())
+ FD2 = MF;
+ SmallVector<const Expr *, 1> AC1, AC2;
+ FD1->getAssociatedConstraints(AC1);
+ FD2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1))
+ return std::nullopt;
+ if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2))
+ return std::nullopt;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return std::nullopt;
+ return AtLeastAsConstrained1;
+ };
// Don't use the AddressOfResolver because we're specifically looking for
// cases where we have one overload candidate that lacks
@@ -12530,8 +12684,8 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
// We have more than one result - see if it is more constrained than the
// previous one.
if (Result) {
- Optional<bool> MoreConstrainedThanPrevious = CheckMoreConstrained(FD,
- Result);
+ std::optional<bool> MoreConstrainedThanPrevious =
+ CheckMoreConstrained(FD, Result);
if (!MoreConstrainedThanPrevious) {
IsResultAmbiguous = true;
AmbiguousDecls.push_back(FD);
@@ -12569,7 +12723,7 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) {
/// Returns false if resolveAddressOfSingleOverloadCandidate fails.
/// Otherwise, returns true. This may emit diagnostics and return true.
bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
- ExprResult &SrcExpr, bool DoFunctionPointerConverion) {
+ ExprResult &SrcExpr, bool DoFunctionPointerConversion) {
Expr *E = SrcExpr.get();
assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
@@ -12585,7 +12739,7 @@ bool Sema::resolveAndFixAddressOfSingleOverloadCandidate(
DiagnoseUseOfDecl(Found, E->getExprLoc());
CheckAddressOfMemberAccess(E, DAP);
Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found);
- if (DoFunctionPointerConverion && Fixed->getType()->isFunctionType())
+ if (DoFunctionPointerConversion && Fixed->getType()->isFunctionType())
SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
else
SrcExpr = Fixed;
@@ -12687,10 +12841,9 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// expression, regardless of whether or not it succeeded. Always
// returns true if 'complain' is set.
bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
- ExprResult &SrcExpr, bool doFunctionPointerConverion,
- bool complain, SourceRange OpRangeForComplaining,
- QualType DestTypeForComplaining,
- unsigned DiagIDForComplaining) {
+ ExprResult &SrcExpr, bool doFunctionPointerConversion, bool complain,
+ SourceRange OpRangeForComplaining, QualType DestTypeForComplaining,
+ unsigned DiagIDForComplaining) {
assert(SrcExpr.get()->getType() == Context.OverloadTy);
OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get());
@@ -12731,7 +12884,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
FixOverloadedFunctionReference(SrcExpr.get(), found, fn);
// If desired, do function-to-pointer decay.
- if (doFunctionPointerConverion) {
+ if (doFunctionPointerConversion) {
SingleFunctionExpression =
DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.get());
if (SingleFunctionExpression.isInvalid()) {
@@ -13008,17 +13161,16 @@ DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
namespace {
class BuildRecoveryCallExprRAII {
Sema &SemaRef;
+ Sema::SatisfactionStackResetRAII SatStack;
+
public:
- BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S) {
+ BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S), SatStack(S) {
assert(SemaRef.IsBuildingRecoveryCallExpr == false);
SemaRef.IsBuildingRecoveryCallExpr = true;
}
- ~BuildRecoveryCallExprRAII() {
- SemaRef.IsBuildingRecoveryCallExpr = false;
- }
+ ~BuildRecoveryCallExprRAII() { SemaRef.IsBuildingRecoveryCallExpr = false; }
};
-
}
/// Attempts to recover from a call where no functions were found.
@@ -13191,7 +13343,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
// Guess at what the return type for an unresolvable overload should be.
static QualType chooseRecoveryType(OverloadCandidateSet &CS,
OverloadCandidateSet::iterator *Best) {
- llvm::Optional<QualType> Result;
+ std::optional<QualType> Result;
// Adjust Type after seeing a candidate.
auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) {
if (!Candidate.Function)
@@ -13594,14 +13746,14 @@ void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet,
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
- if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))
+ if (CandidateSet.getRewriteInfo().allowsReversed(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))
+ if (CandidateSet.getRewriteInfo().allowsReversed(ExtraOp))
AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
CandidateSet,
OverloadCandidateParamOrder::Reversed);
@@ -13732,9 +13884,9 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build the overload set.
- OverloadCandidateSet CandidateSet(
- OpLoc, OverloadCandidateSet::CSK_Operator,
- OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates));
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator,
+ OverloadCandidateSet::OperatorRewriteInfo(
+ Op, OpLoc, AllowRewrittenCandidates));
if (DefaultedFn)
CandidateSet.exclude(DefaultedFn);
LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL);
@@ -13809,6 +13961,22 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (AmbiguousWithSelf) {
Diag(FnDecl->getLocation(),
diag::note_ovl_ambiguous_oper_binary_reversed_self);
+ // Mark member== const or provide matching != to disallow reversed
+ // args. Eg.
+ // struct S { bool operator==(const S&); };
+ // S()==S();
+ if (auto *MD = dyn_cast<CXXMethodDecl>(FnDecl))
+ if (Op == OverloadedOperatorKind::OO_EqualEqual &&
+ !MD->isConst() &&
+ Context.hasSameUnqualifiedType(
+ MD->getThisObjectType(),
+ MD->getParamDecl(0)->getType().getNonReferenceType()) &&
+ Context.hasSameUnqualifiedType(MD->getThisObjectType(),
+ Args[0]->getType()) &&
+ Context.hasSameUnqualifiedType(MD->getThisObjectType(),
+ Args[1]->getType()))
+ Diag(FnDecl->getLocation(),
+ diag::note_ovl_ambiguous_eqeq_reversed_self_non_const);
} else {
Diag(FnDecl->getLocation(),
diag::note_ovl_ambiguous_oper_binary_selected_candidate);
@@ -13932,7 +14100,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
R = CreateOverloadedBinOp(
OpLoc, Opc, Fns, IsReversed ? ZeroLiteral : R.get(),
- IsReversed ? R.get() : ZeroLiteral, PerformADL,
+ IsReversed ? R.get() : ZeroLiteral, /*PerformADL=*/true,
/*AllowRewrittenCandidates=*/false);
popCodeSynthesisContext();
@@ -14206,7 +14374,7 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
MultiExprArg ArgExpr) {
SmallVector<Expr *, 2> Args;
Args.push_back(Base);
- for (auto e : ArgExpr) {
+ for (auto *e : ArgExpr) {
Args.push_back(e);
}
DeclarationName OpName =
@@ -14271,12 +14439,17 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
SmallVector<Expr *, 2> MethodArgs;
- ExprResult Arg0 = PerformObjectArgumentInitialization(
- Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
- if (Arg0.isInvalid())
- return ExprError();
- MethodArgs.push_back(Arg0.get());
+ // Handle 'this' parameter if the selected function is not static.
+ if (Method->isInstance()) {
+ ExprResult Arg0 = PerformObjectArgumentInitialization(
+ Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method);
+ if (Arg0.isInvalid())
+ return ExprError();
+
+ MethodArgs.push_back(Arg0.get());
+ }
+
bool IsError = PrepareArgumentsForCallToObjectOfClassType(
*this, MethodArgs, Method, ArgExpr, LLoc);
if (IsError)
@@ -14296,9 +14469,16 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc,
- CurFPFeatureOverrides());
+ CallExpr *TheCall;
+ if (Method->isInstance())
+ TheCall = CXXOperatorCallExpr::Create(
+ Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK,
+ RLoc, CurFPFeatureOverrides());
+ else
+ TheCall =
+ CallExpr::Create(Context, FnExpr.get(), MethodArgs, ResultTy, VK,
+ RLoc, CurFPFeatureOverrides());
+
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
@@ -14535,7 +14715,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Method = cast<CXXMethodDecl>(Best->Function);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
- if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
+ if (DiagnoseUseOfOverloadedDecl(Best->FoundDecl, UnresExpr->getNameLoc()))
break;
// If FoundDecl is different from Method (such as if one is a template
// and the other a specialization), make sure DiagnoseUseOfDecl is
@@ -14544,7 +14724,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
// DiagnoseUseOfDecl to accept both the FoundDecl and the decl
// being used.
if (Method != FoundDecl.getDecl() &&
- DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc()))
+ DiagnoseUseOfOverloadedDecl(Method, UnresExpr->getNameLoc()))
break;
Succeeded = true;
break;
@@ -14874,15 +15054,18 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
bool IsError = false;
- // Initialize the implicit object parameter.
- ExprResult ObjRes =
- PerformObjectArgumentInitialization(Object.get(), /*Qualifier=*/nullptr,
- Best->FoundDecl, Method);
- if (ObjRes.isInvalid())
- IsError = true;
- else
- Object = ObjRes;
- MethodArgs.push_back(Object.get());
+ // Initialize the implicit object parameter if needed.
+ // Since C++2b, this could also be a call to a static call operator
+ // which we emit as a regular CallExpr.
+ if (Method->isInstance()) {
+ ExprResult ObjRes = PerformObjectArgumentInitialization(
+ Object.get(), /*Qualifier=*/nullptr, Best->FoundDecl, Method);
+ if (ObjRes.isInvalid())
+ IsError = true;
+ else
+ Object = ObjRes;
+ MethodArgs.push_back(Object.get());
+ }
IsError |= PrepareArgumentsForCallToObjectOfClassType(
*this, MethodArgs, Method, Args, LParenLoc);
@@ -14908,9 +15091,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
- CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc,
- CurFPFeatureOverrides());
+ CallExpr *TheCall;
+ if (Method->isInstance())
+ TheCall = CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(),
+ MethodArgs, ResultTy, VK, RParenLoc,
+ CurFPFeatureOverrides());
+ else
+ TheCall = CallExpr::Create(Context, NewFn.get(), MethodArgs, ResultTy, VK,
+ RParenLoc, CurFPFeatureOverrides());
if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
return true;
@@ -14956,7 +15144,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
- None, CandidateSet, /*SuppressUserConversion=*/false);
+ std::nullopt, CandidateSet,
+ /*SuppressUserConversion=*/false);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -15105,8 +15294,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
ResultTy = ResultTy.getNonLValueExprType(Context);
UserDefinedLiteral *UDL = UserDefinedLiteral::Create(
- Context, Fn.get(), llvm::makeArrayRef(ConvArgs, Args.size()), ResultTy,
- VK, LitEndLoc, UDSuffixLoc, CurFPFeatureOverrides());
+ Context, Fn.get(), llvm::ArrayRef(ConvArgs, Args.size()), ResultTy, VK,
+ LitEndLoc, UDSuffixLoc, CurFPFeatureOverrides());
if (CheckCallReturnType(FD->getReturnType(), UDSuffixLoc, UDL, FD))
return ExprError();
@@ -15146,7 +15335,8 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc,
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
}
- *CallExpr = BuildCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr);
+ *CallExpr =
+ BuildCallExpr(S, MemberRef.get(), Loc, std::nullopt, Loc, nullptr);
if (CallExpr->isInvalid()) {
*CallExpr = ExprError();
return FRS_DiagnosticIssued;
diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp
index 7fdb34905b61..abbdc12e7047 100644
--- a/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/clang/lib/Sema/SemaPseudoObject.cpp
@@ -737,11 +737,11 @@ ExprResult ObjCPropertyOpBuilder::buildGet() {
assert(InstanceReceiver || RefExpr->isSuperReceiver());
msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
GenericLoc, Getter->getSelector(),
- Getter, None);
+ Getter, std::nullopt);
} else {
msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(),
- GenericLoc, Getter->getSelector(),
- Getter, None);
+ GenericLoc, Getter->getSelector(), Getter,
+ std::nullopt);
}
return msg;
}
@@ -1200,7 +1200,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
/*TInfo=*/nullptr,
SC_None,
nullptr);
- AtIndexGetter->setMethodParams(S.Context, Argument, None);
+ AtIndexGetter->setMethodParams(S.Context, Argument, std::nullopt);
}
if (!AtIndexGetter) {
@@ -1316,7 +1316,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
SC_None,
nullptr);
Params.push_back(key);
- AtIndexSetter->setMethodParams(S.Context, Params, None);
+ AtIndexSetter->setMethodParams(S.Context, Params, std::nullopt);
}
if (!AtIndexSetter) {
diff --git a/clang/lib/Sema/SemaRISCVVectorLookup.cpp b/clang/lib/Sema/SemaRISCVVectorLookup.cpp
index 50fd841c231b..7716dfb15458 100644
--- a/clang/lib/Sema/SemaRISCVVectorLookup.cpp
+++ b/clang/lib/Sema/SemaRISCVVectorLookup.cpp
@@ -20,6 +20,7 @@
#include "clang/Sema/Sema.h"
#include "clang/Support/RISCVVIntrinsicUtils.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
#include <string>
#include <vector>
@@ -66,7 +67,7 @@ static const RVVIntrinsicRecord RVVIntrinsicRecords[] = {
// Get subsequence of signature table.
static ArrayRef<PrototypeDescriptor> ProtoSeq2ArrayRef(uint16_t Index,
uint8_t Length) {
- return makeArrayRef(&RVVSignatureTable[Index], Length);
+ return ArrayRef(&RVVSignatureTable[Index], Length);
}
static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) {
@@ -115,7 +116,7 @@ static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) {
llvm_unreachable("Unhandled type.");
}
if (Type->isVector())
- QT = Context.getScalableVectorType(QT, Type->getScale().getValue());
+ QT = Context.getScalableVectorType(QT, *Type->getScale());
if (Type->isConstant())
QT = Context.getConstType(QT);
@@ -132,6 +133,7 @@ class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager {
private:
Sema &S;
ASTContext &Context;
+ RVVTypeCache TypeCache;
// List of all RVV intrinsic.
std::vector<RVVIntrinsicDef> IntrinsicList;
@@ -146,7 +148,7 @@ private:
// Create RVVIntrinsicDef.
void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr,
StringRef OverloadedSuffixStr, bool IsMask,
- RVVTypes &Types);
+ RVVTypes &Types, bool HasPolicy, Policy PolicyAttrs);
// Create FunctionDecl for a vector intrinsic.
void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II,
@@ -185,15 +187,32 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef(
Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize);
+ PolicyScheme UnMaskedPolicyScheme =
+ static_cast<PolicyScheme>(Record.UnMaskedPolicyScheme);
+ PolicyScheme MaskedPolicyScheme =
+ static_cast<PolicyScheme>(Record.MaskedPolicyScheme);
+
+ const Policy DefaultPolicy(Record.HasTailPolicy, Record.HasMaskPolicy);
+
llvm::SmallVector<PrototypeDescriptor> ProtoSeq =
RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false,
/*HasMaskedOffOperand=*/false,
- Record.HasVL, Record.NF);
+ Record.HasVL, Record.NF,
+ UnMaskedPolicyScheme, DefaultPolicy);
llvm::SmallVector<PrototypeDescriptor> ProtoMaskSeq =
- RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/true,
- Record.HasMaskedOffOperand,
- Record.HasVL, Record.NF);
+ RVVIntrinsic::computeBuiltinTypes(
+ BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand,
+ Record.HasVL, Record.NF, MaskedPolicyScheme, DefaultPolicy);
+
+ bool UnMaskedHasPolicy = UnMaskedPolicyScheme != PolicyScheme::SchemeNone;
+ bool MaskedHasPolicy = MaskedPolicyScheme != PolicyScheme::SchemeNone;
+ SmallVector<Policy> SupportedUnMaskedPolicies =
+ RVVIntrinsic::getSupportedUnMaskedPolicies(Record.HasTailPolicy,
+ Record.HasMaskPolicy);
+ SmallVector<Policy> SupportedMaskedPolicies =
+ RVVIntrinsic::getSupportedMaskedPolicies(Record.HasTailPolicy,
+ Record.HasMaskPolicy);
for (unsigned int TypeRangeMaskShift = 0;
TypeRangeMaskShift <= static_cast<unsigned int>(BasicType::MaxOffset);
@@ -229,46 +248,72 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3))))
continue;
- Optional<RVVTypes> Types =
- RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
+ std::optional<RVVTypes> Types =
+ TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
// Ignored to create new intrinsic if there are any illegal types.
- if (!Types.hasValue())
+ if (!Types.has_value())
continue;
- std::string SuffixStr =
- RVVIntrinsic::getSuffixStr(BaseType, Log2LMUL, SuffixProto);
+ std::string SuffixStr = RVVIntrinsic::getSuffixStr(
+ TypeCache, BaseType, Log2LMUL, SuffixProto);
std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
- BaseType, Log2LMUL, OverloadedSuffixProto);
+ TypeCache, BaseType, Log2LMUL, OverloadedSuffixProto);
// Create non-masked intrinsic.
- InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types);
-
- if (Record.HasMasked) {
- // Create masked intrinsic.
- Optional<RVVTypes> MaskTypes = RVVType::computeTypes(
- BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
-
- InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
- *MaskTypes);
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types,
+ UnMaskedHasPolicy, DefaultPolicy);
+
+ // Create non-masked policy intrinsic.
+ if (Record.UnMaskedPolicyScheme != PolicyScheme::SchemeNone) {
+ for (auto P : SupportedUnMaskedPolicies) {
+ llvm::SmallVector<PrototypeDescriptor> PolicyPrototype =
+ RVVIntrinsic::computeBuiltinTypes(
+ BasicProtoSeq, /*IsMasked=*/false,
+ /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF,
+ UnMaskedPolicyScheme, P);
+ std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes(
+ BaseType, Log2LMUL, Record.NF, PolicyPrototype);
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr,
+ /*IsMask=*/false, *PolicyTypes, UnMaskedHasPolicy,
+ P);
+ }
}
- }
- }
+ if (!Record.HasMasked)
+ continue;
+ // Create masked intrinsic.
+ std::optional<RVVTypes> MaskTypes =
+ TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
+ *MaskTypes, MaskedHasPolicy, DefaultPolicy);
+ if (Record.MaskedPolicyScheme == PolicyScheme::SchemeNone)
+ continue;
+ // Create masked policy intrinsic.
+ for (auto P : SupportedMaskedPolicies) {
+ llvm::SmallVector<PrototypeDescriptor> PolicyPrototype =
+ RVVIntrinsic::computeBuiltinTypes(
+ BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand,
+ Record.HasVL, Record.NF, MaskedPolicyScheme, P);
+ std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes(
+ BaseType, Log2LMUL, Record.NF, PolicyPrototype);
+ InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr,
+ /*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P);
+ }
+ } // End for different LMUL
+ } // End for different TypeRange
}
}
// Compute name and signatures for intrinsic with practical types.
void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
const RVVIntrinsicRecord &Record, StringRef SuffixStr,
- StringRef OverloadedSuffixStr, bool IsMask, RVVTypes &Signature) {
+ StringRef OverloadedSuffixStr, bool IsMasked, RVVTypes &Signature,
+ bool HasPolicy, Policy PolicyAttrs) {
// Function name, e.g. vadd_vv_i32m1.
std::string Name = Record.Name;
if (!SuffixStr.empty())
Name += "_" + SuffixStr.str();
- if (IsMask)
- Name += "_m";
-
// Overloaded function name, e.g. vadd.
std::string OverloadedName;
if (!Record.OverloadedName)
@@ -280,8 +325,9 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
// clang built-in function name, e.g. __builtin_rvv_vadd.
std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name);
- if (IsMask)
- BuiltinName += "_m";
+
+ RVVIntrinsic::updateNamesAndPolicy(IsMasked, HasPolicy, Name, BuiltinName,
+ OverloadedName, PolicyAttrs);
// Put into IntrinsicList.
size_t Index = IntrinsicList.size();
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index c6ca10c0342c..f15603fd0bd4 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -382,7 +382,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
// type of the left operand could be used for SFINAE, so technically it is
// *used*.
if (DiagID != diag::warn_unused_comma_left_operand || !isSFINAEContext())
- DiagIfReachable(Loc, S ? llvm::makeArrayRef(S) : llvm::None,
+ DiagIfReachable(Loc, S ? llvm::ArrayRef(S) : std::nullopt,
PDiag(DiagID) << R1 << R2);
}
@@ -1499,7 +1499,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond &&
ET && ET->getDecl()->isCompleteDefinition() &&
- !empty(ET->getDecl()->enumerators())) {
+ !ET->getDecl()->enumerators().empty()) {
const EnumDecl *ED = ET->getDecl();
EnumValsTy EnumVals;
@@ -2308,11 +2308,14 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
// If the type contained 'auto', deduce the 'auto' to 'id'.
if (FirstType->getContainedAutoType()) {
- OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(),
- VK_PRValue);
+ SourceLocation Loc = D->getLocation();
+ OpaqueValueExpr OpaqueId(Loc, Context.getObjCIdType(), VK_PRValue);
Expr *DeducedInit = &OpaqueId;
- if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) ==
- DAR_Failed)
+ TemplateDeductionInfo Info(Loc);
+ FirstType = QualType();
+ TemplateDeductionResult Result = DeduceAutoType(
+ D->getTypeSourceInfo()->getTypeLoc(), DeducedInit, FirstType, Info);
+ if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
DiagnoseAutoDeductionFailure(D, DeducedInit);
if (FirstType.isNull()) {
D->setInvalidDecl();
@@ -2376,10 +2379,16 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init,
// Deduce the type for the iterator variable now rather than leaving it to
// AddInitializerToDecl, so we can produce a more suitable diagnostic.
QualType InitType;
- if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) ||
- SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) ==
- Sema::DAR_Failed)
+ if (!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) {
SemaRef.Diag(Loc, DiagID) << Init->getType();
+ } else {
+ TemplateDeductionInfo Info(Init->getExprLoc());
+ Sema::TemplateDeductionResult Result = SemaRef.DeduceAutoType(
+ Decl->getTypeSourceInfo()->getTypeLoc(), Init, InitType, Info);
+ if (Result != Sema::TDK_Success && Result != Sema::TDK_AlreadyDiagnosed)
+ SemaRef.Diag(Loc, DiagID) << Init->getType();
+ }
+
if (InitType.isNull()) {
Decl->setInvalidDecl();
return true;
@@ -2660,7 +2669,7 @@ BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange,
SemaRef.PDiag(diag::err_for_range_invalid)
<< BeginRange->getType() << BEFFound),
SemaRef, OCD_AllCandidates, BeginRange);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Sema::FRS_DiagnosticIssued:
for (NamedDecl *D : OldFound) {
@@ -3769,17 +3778,13 @@ TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const {
/// C++1y [dcl.spec.auto]p6.
bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
SourceLocation ReturnLoc,
- Expr *&RetExpr,
- const AutoType *AT) {
+ Expr *RetExpr, const AutoType *AT) {
// If this is the conversion function for a lambda, we choose to deduce its
// type from the corresponding call operator, not from the synthesized return
// statement within it. See Sema::DeduceReturnType.
if (isLambdaConversionOperator(FD))
return false;
- TypeLoc OrigResultType = getReturnTypeLoc(FD);
- QualType Deduced;
-
if (RetExpr && isa<InitListExpr>(RetExpr)) {
// If the deduction is for a return statement and the initializer is
// a braced-init-list, the program is ill-formed.
@@ -3799,87 +3804,74 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
return false;
}
- if (RetExpr) {
- // Otherwise, [...] deduce a value for U using the rules of template
- // argument deduction.
- DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced);
-
- if (DAR == DAR_Failed && !FD->isInvalidDecl())
- Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
- << OrigResultType.getType() << RetExpr->getType();
-
- if (DAR != DAR_Succeeded)
- return true;
-
- // If a local type is part of the returned type, mark its fields as
- // referenced.
- LocalTypedefNameReferencer Referencer(*this);
- Referencer.TraverseType(RetExpr->getType());
- } else {
- // For a function with a deduced result type to return void,
- // the result type as written must be 'auto' or 'decltype(auto)',
- // possibly cv-qualified or constrained, but not ref-qualified.
+ TypeLoc OrigResultType = getReturnTypeLoc(FD);
+ // In the case of a return with no operand, the initializer is considered
+ // to be void().
+ CXXScalarValueInitExpr VoidVal(Context.VoidTy, nullptr, SourceLocation());
+ if (!RetExpr) {
+ // For a function with a deduced result type to return with omitted
+ // expression, the result type as written must be 'auto' or
+ // 'decltype(auto)', possibly cv-qualified or constrained, but not
+ // ref-qualified.
if (!OrigResultType.getType()->getAs<AutoType>()) {
Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto)
- << OrigResultType.getType();
+ << OrigResultType.getType();
return true;
}
- // In the case of a return with no operand, the initializer is considered
- // to be 'void()'.
- Expr *Dummy = new (Context) CXXScalarValueInitExpr(
- Context.VoidTy,
- Context.getTrivialTypeSourceInfo(Context.VoidTy, ReturnLoc), ReturnLoc);
- DeduceAutoResult DAR = DeduceAutoType(OrigResultType, Dummy, Deduced);
-
- if (DAR == DAR_Failed && !FD->isInvalidDecl())
- Diag(ReturnLoc, diag::err_auto_fn_deduction_failure)
- << OrigResultType.getType() << Dummy->getType();
-
- if (DAR != DAR_Succeeded)
- return true;
+ RetExpr = &VoidVal;
}
- // 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();
+ QualType Deduced = AT->getDeducedType();
+ {
+ // Otherwise, [...] deduce a value for U using the rules of template
+ // argument deduction.
+ TemplateDeductionInfo Info(RetExpr->getExprLoc());
+ TemplateDeductionResult Res =
+ DeduceAutoType(OrigResultType, RetExpr, Deduced, Info);
+ if (Res != TDK_Success && FD->isInvalidDecl())
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,
- // the program is ill-formed.
- QualType DeducedT = AT->getDeducedType();
- if (!DeducedT.isNull() && !FD->isInvalidDecl()) {
- AutoType *NewAT = Deduced->getContainedAutoType();
- // It is possible that NewAT->getDeducedType() is null. When that happens,
- // we should not crash, instead we ignore this deduction.
- if (NewAT->getDeducedType().isNull())
- return false;
-
- CanQualType OldDeducedType = Context.getCanonicalFunctionResultType(
- DeducedT);
- CanQualType NewDeducedType = Context.getCanonicalFunctionResultType(
- NewAT->getDeducedType());
- if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) {
+ switch (Res) {
+ case TDK_Success:
+ break;
+ case TDK_AlreadyDiagnosed:
+ return true;
+ case TDK_Inconsistent: {
+ // 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, the program is ill-formed.
const LambdaScopeInfo *LambdaSI = getCurLambda();
- if (LambdaSI && LambdaSI->HasImplicitReturnType) {
+ if (LambdaSI && LambdaSI->HasImplicitReturnType)
Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
- << NewAT->getDeducedType() << DeducedT
- << true /*IsLambda*/;
- } else {
+ << Info.SecondArg << Info.FirstArg << true /*IsLambda*/;
+ else
Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
- << (AT->isDecltypeAuto() ? 1 : 0)
- << NewAT->getDeducedType() << DeducedT;
- }
+ << (AT->isDecltypeAuto() ? 1 : 0) << Info.SecondArg
+ << Info.FirstArg;
return true;
}
- } else if (!FD->isInvalidDecl()) {
+ default:
+ Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure)
+ << OrigResultType.getType() << RetExpr->getType();
+ return true;
+ }
+ }
+
+ // If a local type is part of the returned type, mark its fields as
+ // referenced.
+ LocalTypedefNameReferencer(*this).TraverseType(RetExpr->getType());
+
+ // CUDA: Kernel function must have 'void' return type.
+ if (getLangOpts().CUDA && FD->hasAttr<CUDAGlobalAttr>() &&
+ !Deduced->isVoidType()) {
+ Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
+ << FD->getType() << FD->getSourceRange();
+ return true;
+ }
+
+ if (!FD->isInvalidDecl() && AT->getDeducedType() != Deduced)
// Update all declarations of the function to have the deduced return type.
Context.adjustDeducedFunctionResultType(FD, Deduced);
- }
return false;
}
@@ -4695,11 +4687,11 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI,
if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP)
S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel);
- Captures.push_back(CapturedStmt::Capture(Cap.getLocation(),
- Cap.isReferenceCapture()
- ? CapturedStmt::VCK_ByRef
- : CapturedStmt::VCK_ByCopy,
- Cap.getVariable()));
+ Captures.push_back(CapturedStmt::Capture(
+ Cap.getLocation(),
+ Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef
+ : CapturedStmt::VCK_ByCopy,
+ cast<VarDecl>(Cap.getVariable())));
}
CaptureInits.push_back(Init.get());
}
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 8dfcf9899e3f..97400483c63a 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -24,6 +24,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -330,7 +331,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
if (RequireCompleteType(OutputExpr->getBeginLoc(), Exprs[i]->getType(),
diag::err_dereference_incomplete_type))
return StmtError();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return StmtError(Diag(OutputExpr->getBeginLoc(),
diag::err_asm_invalid_lvalue_in_output)
@@ -377,6 +378,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
Expr *InputExpr = Exprs[i];
+ if (InputExpr->getType()->isMemberPointerType())
+ return StmtError(Diag(InputExpr->getBeginLoc(),
+ diag::err_asm_pmf_through_constraint_not_permitted)
+ << InputExpr->getSourceRange());
+
// Referring to parameters is not allowed in naked functions.
if (CheckNakedParmReference(InputExpr, *this))
return StmtError();
@@ -454,7 +460,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
<< Info.getConstraintStr();
}
- Optional<SourceLocation> UnwindClobberLoc;
+ std::optional<SourceLocation> UnwindClobberLoc;
// Check that the clobbers are valid.
for (unsigned i = 0; i != NumClobbers; i++) {
@@ -932,13 +938,24 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
bool IsSimple = (NumOutputs != 0 || NumInputs != 0);
setFunctionHasBranchProtectedScope();
+ bool InvalidOperand = false;
for (uint64_t I = 0; I < NumOutputs + NumInputs; ++I) {
- if (Exprs[I]->getType()->isBitIntType())
- return StmtError(
- Diag(Exprs[I]->getBeginLoc(), diag::err_asm_invalid_type)
- << Exprs[I]->getType() << (I < NumOutputs)
- << Exprs[I]->getSourceRange());
+ Expr *E = Exprs[I];
+ if (E->getType()->isBitIntType()) {
+ InvalidOperand = true;
+ Diag(E->getBeginLoc(), diag::err_asm_invalid_type)
+ << E->getType() << (I < NumOutputs)
+ << E->getSourceRange();
+ } else if (E->refersToBitField()) {
+ InvalidOperand = true;
+ FieldDecl *BitField = E->getSourceBitField();
+ Diag(E->getBeginLoc(), diag::err_ms_asm_bitfield_unsupported)
+ << E->getSourceRange();
+ Diag(BitField->getLocation(), diag::note_bitfield_decl);
+ }
}
+ if (InvalidOperand)
+ return StmtError();
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index b03c055a4f50..6d443837a4c5 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -19,6 +19,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -306,21 +307,33 @@ CheckForIncompatibleAttributes(Sema &S,
if (!DiagnoseMutualExclusions(S, Attrs))
return;
- // There are 6 categories of loop hints attributes: vectorize, interleave,
- // unroll, unroll_and_jam, pipeline and distribute. Except for distribute they
- // come in two variants: a state form and a numeric form. The state form
- // selectively defaults/enables/disables the transformation for the loop
- // (for unroll, default indicates full unrolling rather than enabling the
- // transformation). The numeric form form provides an integer hint (for
- // example, unroll count) to the transformer. The following array accumulates
- // the hints encountered while iterating through the attributes to check for
- // compatibility.
+ enum CategoryType {
+ // For the following categories, they come in two variants: a state form and
+ // a numeric form. The state form may be one of default, enable, and
+ // disable. The numeric form provides an integer hint (for example, unroll
+ // count) to the transformer.
+ Vectorize,
+ Interleave,
+ UnrollAndJam,
+ Pipeline,
+ // For unroll, default indicates full unrolling rather than enabling the
+ // transformation.
+ Unroll,
+ // The loop distribution transformation only has a state form that is
+ // exposed by #pragma clang loop distribute (enable | disable).
+ Distribute,
+ // The vector predication only has a state form that is exposed by
+ // #pragma clang loop vectorize_predicate (enable | disable).
+ VectorizePredicate,
+ // This serves as a indicator to how many category are listed in this enum.
+ NumberOfCategories
+ };
+ // The following array accumulates the hints encountered while iterating
+ // through the attributes to check for compatibility.
struct {
const LoopHintAttr *StateAttr;
const LoopHintAttr *NumericAttr;
- } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr},
- {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr},
- {nullptr, nullptr}};
+ } HintAttrs[CategoryType::NumberOfCategories] = {};
for (const auto *I : Attrs) {
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
@@ -329,16 +342,8 @@ CheckForIncompatibleAttributes(Sema &S,
if (!LH)
continue;
+ CategoryType Category = CategoryType::NumberOfCategories;
LoopHintAttr::OptionType Option = LH->getOption();
- enum {
- Vectorize,
- Interleave,
- Unroll,
- UnrollAndJam,
- Distribute,
- Pipeline,
- VectorizePredicate
- } Category;
switch (Option) {
case LoopHintAttr::Vectorize:
case LoopHintAttr::VectorizeWidth:
@@ -369,7 +374,7 @@ CheckForIncompatibleAttributes(Sema &S,
break;
};
- assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0]));
+ assert(Category != NumberOfCategories && "Unhandled loop hint option");
auto &CategoryState = HintAttrs[Category];
const LoopHintAttr *PrevAttr;
if (Option == LoopHintAttr::Vectorize ||
@@ -420,7 +425,7 @@ static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
unsigned UnrollFactor = 0;
if (A.getNumArgs() == 1) {
Expr *E = A.getArgAsExpr(0);
- Optional<llvm::APSInt> ArgVal;
+ std::optional<llvm::APSInt> ArgVal;
if (!(ArgVal = E->getIntegerConstantExpr(S.Context))) {
S.Diag(A.getLoc(), diag::err_attribute_argument_type)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1542a07713fb..4b144c239fa4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -39,6 +39,7 @@
#include "llvm/ADT/StringExtras.h"
#include <iterator>
+#include <optional>
using namespace clang;
using namespace sema;
@@ -109,7 +110,7 @@ NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D,
return D;
}
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ if (const auto *Record = dyn_cast<CXXRecordDecl>(D)) {
// C++ [temp.local]p1:
// Like normal (non-template) classes, class templates have an
// injected-class-name (Clause 9). The injected-class-name
@@ -126,8 +127,7 @@ NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D,
if (Record->getDescribedClassTemplate())
return Record->getDescribedClassTemplate();
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Record))
+ if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Record))
return Spec->getSpecializedTemplate();
}
@@ -399,6 +399,7 @@ bool Sema::LookupTemplateName(LookupResult &Found,
LookupCtx = computeDeclContext(ObjectType);
IsDependent = !LookupCtx && ObjectType->isDependentType();
assert((IsDependent || !ObjectType->isIncompleteType() ||
+ !ObjectType->getAs<TagType>() ||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
@@ -816,7 +817,7 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
if (!Complain || (PatternDef && PatternDef->isInvalidDecl()))
return true;
- llvm::Optional<unsigned> Note;
+ std::optional<unsigned> Note;
QualType InstantiationTy;
if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation))
InstantiationTy = Context.getTypeDeclType(TD);
@@ -941,7 +942,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
TemplateName Template = Arg.getAsTemplate().get();
TemplateArgument TArg;
if (Arg.getEllipsisLoc().isValid())
- TArg = TemplateArgument(Template, Optional<unsigned int>());
+ TArg = TemplateArgument(Template, std::optional<unsigned int>());
else
TArg = Template;
return TemplateArgumentLoc(
@@ -1207,7 +1208,7 @@ static ExprResult formImmediatelyDeclaredConstraint(
ImmediatelyDeclaredConstraint.get(), BO_LAnd,
EllipsisLoc, /*RHS=*/nullptr,
/*RParenLoc=*/SourceLocation(),
- /*NumExpansions=*/None);
+ /*NumExpansions=*/std::nullopt);
}
/// Attach a type-constraint to a template parameter.
@@ -1530,11 +1531,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
CheckValidDeclSpecifiers();
- if (TInfo->getType()->isUndeducedType()) {
- Diag(D.getIdentifierLoc(),
- diag::warn_cxx14_compat_template_nontype_parm_auto_type)
- << QualType(TInfo->getType()->getContainedAutoType(), 0);
- }
+ if (const auto *T = TInfo->getType()->getContainedDeducedType())
+ if (isa<AutoType>(T))
+ Diag(D.getIdentifierLoc(),
+ diag::warn_cxx14_compat_template_nontype_parm_auto_type)
+ << QualType(TInfo->getType()->getContainedAutoType(), 0);
assert(S->isTemplateParamScope() &&
"Non-type template parameter not in template parameter scope!");
@@ -1591,9 +1592,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument))
return Param;
- TemplateArgument Converted;
- ExprResult DefaultRes =
- CheckTemplateArgument(Param, Param->getType(), Default, Converted);
+ TemplateArgument SugaredConverted, CanonicalConverted;
+ ExprResult DefaultRes = CheckTemplateArgument(
+ Param, Param->getType(), Default, SugaredConverted, CanonicalConverted,
+ CTAK_Specified);
if (DefaultRes.isInvalid()) {
Param->setInvalidDecl();
return Param;
@@ -1686,6 +1688,99 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
return Param;
}
+namespace {
+class ConstraintRefersToContainingTemplateChecker
+ : public TreeTransform<ConstraintRefersToContainingTemplateChecker> {
+ bool Result = false;
+ const FunctionDecl *Friend = nullptr;
+ unsigned TemplateDepth = 0;
+
+ // Check a record-decl that we've seen to see if it is a lexical parent of the
+ // Friend, likely because it was referred to without its template arguments.
+ void CheckIfContainingRecord(const CXXRecordDecl *CheckingRD) {
+ CheckingRD = CheckingRD->getMostRecentDecl();
+
+ for (const DeclContext *DC = Friend->getLexicalDeclContext();
+ DC && !DC->isFileContext(); DC = DC->getParent())
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
+ if (CheckingRD == RD->getMostRecentDecl())
+ Result = true;
+ }
+
+ void CheckNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ assert(D->getDepth() <= TemplateDepth &&
+ "Nothing should reference a value below the actual template depth, "
+ "depth is likely wrong");
+ if (D->getDepth() != TemplateDepth)
+ Result = true;
+
+ // Necessary because the type of the NTTP might be what refers to the parent
+ // constriant.
+ TransformType(D->getType());
+ }
+
+public:
+ using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>;
+
+ ConstraintRefersToContainingTemplateChecker(Sema &SemaRef,
+ const FunctionDecl *Friend,
+ unsigned TemplateDepth)
+ : inherited(SemaRef), Friend(Friend), TemplateDepth(TemplateDepth) {}
+ bool getResult() const { return Result; }
+
+ // This should be the only template parm type that we have to deal with.
+ // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and
+ // FunctionParmPackExpr are all partially substituted, which cannot happen
+ // with concepts at this point in translation.
+ using inherited::TransformTemplateTypeParmType;
+ QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+ TemplateTypeParmTypeLoc TL, bool) {
+ assert(TL.getDecl()->getDepth() <= TemplateDepth &&
+ "Nothing should reference a value below the actual template depth, "
+ "depth is likely wrong");
+ if (TL.getDecl()->getDepth() != TemplateDepth)
+ Result = true;
+ return inherited::TransformTemplateTypeParmType(
+ TLB, TL,
+ /*SuppressObjCLifetime=*/false);
+ }
+
+ Decl *TransformDecl(SourceLocation Loc, Decl *D) {
+ if (!D)
+ return D;
+ // FIXME : This is possibly an incomplete list, but it is unclear what other
+ // Decl kinds could be used to refer to the template parameters. This is a
+ // best guess so far based on examples currently available, but the
+ // unreachable should catch future instances/cases.
+ if (auto *TD = dyn_cast<TypedefNameDecl>(D))
+ TransformType(TD->getUnderlyingType());
+ else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D))
+ CheckNonTypeTemplateParmDecl(NTTPD);
+ else if (auto *VD = dyn_cast<ValueDecl>(D))
+ TransformType(VD->getType());
+ else if (auto *TD = dyn_cast<TemplateDecl>(D))
+ TransformTemplateParameterList(TD->getTemplateParameters());
+ else if (auto *RD = dyn_cast<CXXRecordDecl>(D))
+ CheckIfContainingRecord(RD);
+ else if (isa<NamedDecl>(D)) {
+ // No direct types to visit here I believe.
+ } else
+ llvm_unreachable("Don't know how to handle this declaration type yet");
+ return D;
+ }
+};
+} // namespace
+
+bool Sema::ConstraintExpressionDependsOnEnclosingTemplate(
+ const FunctionDecl *Friend, unsigned TemplateDepth,
+ const Expr *Constraint) {
+ assert(Friend->getFriendObjectKind() && "Only works on a friend");
+ ConstraintRefersToContainingTemplateChecker Checker(*this, Friend,
+ TemplateDepth);
+ Checker.TransformExpr(const_cast<Expr *>(Constraint));
+ return Checker.getResult();
+}
+
/// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally
/// constrained by RequiresClause, that contains the template parameters in
/// Params.
@@ -1705,8 +1800,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth,
return TemplateParameterList::Create(
Context, TemplateLoc, LAngleLoc,
- llvm::makeArrayRef(Params.data(), Params.size()),
- RAngleLoc, RequiresClause);
+ llvm::ArrayRef(Params.data(), Params.size()), RAngleLoc, RequiresClause);
}
static void SetNestedNameSpecifier(Sema &S, TagDecl *T,
@@ -1985,8 +2079,8 @@ DeclResult Sema::CheckClassTemplate(
SetNestedNameSpecifier(*this, NewClass, SS);
if (NumOuterTemplateParamLists > 0)
NewClass->setTemplateParameterListsInfo(
- Context, llvm::makeArrayRef(OuterTemplateParamLists,
- NumOuterTemplateParamLists));
+ Context,
+ llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
@@ -2284,10 +2378,12 @@ private:
/*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(),
TTP->getIdentifier(), TTP->wasDeclaredWithTypename(),
TTP->isParameterPack(), TTP->hasTypeConstraint(),
- TTP->isExpandedParameterPack() ?
- llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
+ TTP->isExpandedParameterPack()
+ ? std::optional<unsigned>(TTP->getNumExpansionParameters())
+ : std::nullopt);
if (const auto *TC = TTP->getTypeConstraint())
- SemaRef.SubstTypeConstraint(NewTTP, TC, Args);
+ SemaRef.SubstTypeConstraint(NewTTP, TC, Args,
+ /*EvaluateConstraint*/ true);
if (TTP->hasDefaultArgument()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args,
@@ -2444,6 +2540,8 @@ private:
TInfo->getType(), TInfo, LocEnd, Ctor);
Guide->setImplicit();
Guide->setParams(Params);
+ if (Ctor && Ctor->getTrailingRequiresClause())
+ Guide->setTrailingRequiresClause(Ctor->getTrailingRequiresClause());
for (auto *Param : Params)
Param->setDeclContext(Guide);
@@ -2535,7 +2633,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
// additional function template derived as above from a hypothetical
// constructor C().
if (!AddedAny)
- Transform.buildSimpleDeductionGuide(None);
+ Transform.buildSimpleDeductionGuide(std::nullopt);
// -- An additional function template derived as above from a hypothetical
// constructor C(C), called the copy deduction candidate.
@@ -3411,7 +3509,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// Fabricate an empty template parameter list for the invented header.
return TemplateParameterList::Create(Context, SourceLocation(),
- SourceLocation(), None,
+ SourceLocation(), std::nullopt,
SourceLocation(), nullptr);
}
@@ -3496,45 +3594,54 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
static QualType
checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
- const SmallVectorImpl<TemplateArgument> &Converted,
+ ArrayRef<TemplateArgument> Converted,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
ASTContext &Context = SemaRef.getASTContext();
+
switch (BTD->getBuiltinTemplateKind()) {
case BTK__make_integer_seq: {
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
+ QualType OrigType = Converted[1].getAsType();
// C++14 [inteseq.intseq]p1:
// T shall be an integer type.
- if (!Converted[1].getAsType()->isIntegralType(Context)) {
+ if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) {
SemaRef.Diag(TemplateArgs[1].getLocation(),
diag::err_integer_sequence_integral_element_type);
return QualType();
}
- // C++14 [inteseq.make]p1:
- // If N is negative the program is ill-formed.
TemplateArgument NumArgsArg = Converted[2];
- llvm::APSInt NumArgs = NumArgsArg.getAsIntegral();
- if (NumArgs < 0) {
+ if (NumArgsArg.isDependent())
+ return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
+ Converted);
+
+ TemplateArgumentListInfo SyntheticTemplateArgs;
+ // The type argument, wrapped in substitution sugar, gets reused as the
+ // first template argument in the synthetic template argument list.
+ SyntheticTemplateArgs.addArgument(
+ TemplateArgumentLoc(TemplateArgument(OrigType),
+ SemaRef.Context.getTrivialTypeSourceInfo(
+ OrigType, TemplateArgs[1].getLocation())));
+
+ if (llvm::APSInt NumArgs = NumArgsArg.getAsIntegral(); NumArgs >= 0) {
+ // Expand N into 0 ... N-1.
+ for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
+ I < NumArgs; ++I) {
+ TemplateArgument TA(Context, I, OrigType);
+ SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
+ TA, OrigType, TemplateArgs[2].getLocation()));
+ }
+ } else {
+ // C++14 [inteseq.make]p1:
+ // If N is negative the program is ill-formed.
SemaRef.Diag(TemplateArgs[2].getLocation(),
diag::err_integer_sequence_negative_length);
return QualType();
}
- QualType ArgTy = NumArgsArg.getIntegralType();
- TemplateArgumentListInfo SyntheticTemplateArgs;
- // The type argument gets reused as the first template argument in the
- // synthetic template argument list.
- SyntheticTemplateArgs.addArgument(TemplateArgs[1]);
- // Expand N into 0 ... N-1.
- for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
- I < NumArgs; ++I) {
- TemplateArgument TA(Context, I, ArgTy);
- SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
- TA, ArgTy, TemplateArgs[2].getLocation()));
- }
// The first template argument will be reused as the template decl that
// our synthetic template arguments will be applied to.
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
@@ -3548,11 +3655,15 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
assert(Converted.size() == 2 &&
"__type_pack_element should be given an index and a parameter pack");
- // If the Index is out of bounds, the program is ill-formed.
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
+ if (IndexArg.isDependent() || Ts.isDependent())
+ return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD),
+ Converted);
+
llvm::APSInt Index = IndexArg.getAsIntegral();
assert(Index >= 0 && "the index used with __type_pack_element should be of "
"type std::size_t, and hence be non-negative");
+ // If the Index is out of bounds, the program is ill-formed.
if (Index >= Ts.pack_size()) {
SemaRef.Diag(TemplateArgs[0].getLocation(),
diag::err_type_pack_element_out_of_bounds);
@@ -3560,8 +3671,8 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
}
// We simply return the type at index `Index`.
- auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
- return Nth->getAsType();
+ int64_t N = Index.getExtValue();
+ return Ts.getPackAsArray()[N].getAsType();
}
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
@@ -3585,9 +3696,8 @@ static void collectConjunctionTerms(Expr *Clause,
if (BinOp->getOpcode() == BO_LAnd) {
collectConjunctionTerms(BinOp->getLHS(), Terms);
collectConjunctionTerms(BinOp->getRHS(), Terms);
+ return;
}
-
- return;
}
Terms.push_back(Clause);
@@ -3715,10 +3825,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// assume the template is a type template. Either our assumption is
// correct, or the code is ill-formed and will be diagnosed when the
// dependent name is substituted.
- return Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ return Context.getDependentTemplateSpecializationType(
+ ETK_None, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
if (Name.getAsAssumedTemplateName() &&
resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc))
@@ -3730,7 +3839,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
- return Context.getTemplateSpecializationType(Name, TemplateArgs);
+ return Context.getTemplateSpecializationType(Name,
+ TemplateArgs.arguments());
Diag(TemplateLoc, diag::err_template_id_not_a_type)
<< Name;
@@ -3740,9 +3850,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
- false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false,
+ SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return QualType();
@@ -3756,12 +3866,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
if (Pattern->isInvalidDecl())
return QualType();
- TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
- Converted);
-
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs);
+ TemplateArgLists.addOuterTemplateArguments(Template, CanonicalConverted,
+ /*Final=*/false);
TemplateArgLists.addOuterRetainedLevels(
AliasTemplate->getTemplateParameters()->getDepth());
@@ -3808,9 +3916,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType();
}
+ } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
+ CanonType = checkBuiltinTemplateIdType(*this, BTD, SugaredConverted,
+ TemplateLoc, TemplateArgs);
} else if (Name.isDependent() ||
TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs, Converted)) {
+ TemplateArgs, CanonicalConverted)) {
// This class template specialization is a dependent
// type. Therefore, its canonical type is another class template
// specialization type that contains all of the converted
@@ -3818,7 +3929,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// A<T, T> have identical types when A is declared as:
//
// template<typename T, typename U = T> struct A;
- CanonType = Context.getCanonicalTemplateSpecializationType(Name, Converted);
+ CanonType = Context.getCanonicalTemplateSpecializationType(
+ Name, CanonicalConverted);
// This might work out to be a current instantiation, in which
// case the canonical type needs to be the InjectedClassNameType.
@@ -3857,13 +3969,13 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
break;
}
}
- } else if (ClassTemplateDecl *ClassTemplate
- = dyn_cast<ClassTemplateDecl>(Template)) {
+ } else if (ClassTemplateDecl *ClassTemplate =
+ dyn_cast<ClassTemplateDecl>(Template)) {
// Find the class template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *Decl
- = ClassTemplate->findSpecialization(Converted, InsertPos);
+ ClassTemplateSpecializationDecl *Decl =
+ ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
if (!Decl) {
// This is the first time we have referenced this class template
// specialization. Create the canonical declaration and add it to
@@ -3872,7 +3984,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
Context, ClassTemplate->getTemplatedDecl()->getTagKind(),
ClassTemplate->getDeclContext(),
ClassTemplate->getTemplatedDecl()->getBeginLoc(),
- ClassTemplate->getLocation(), ClassTemplate, Converted, nullptr);
+ ClassTemplate->getLocation(), ClassTemplate, CanonicalConverted,
+ nullptr);
ClassTemplate->AddSpecialization(Decl, InsertPos);
if (ClassTemplate->isOutOfLine())
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
@@ -3882,8 +3995,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
ClassTemplate->getTemplatedDecl()->hasAttrs()) {
InstantiatingTemplate Inst(*this, TemplateLoc, Decl);
if (!Inst.isInvalid()) {
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(Converted);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template,
+ CanonicalConverted,
+ /*Final=*/false);
InstantiateAttrsForDecl(TemplateArgLists,
ClassTemplate->getTemplatedDecl(), Decl);
}
@@ -3895,15 +4009,15 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
CanonType = Context.getTypeDeclType(Decl);
assert(isa<RecordType>(CanonType) &&
"type of non-dependent specialization is not a RecordType");
- } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
- CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
- TemplateArgs);
+ } else {
+ llvm_unreachable("Unhandled template kind");
}
// Build the fully-sugared type for this class template
// specialization, which refers back to the class template
// specialization we created or found.
- return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
+ return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(),
+ CanonType);
}
void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName,
@@ -3964,7 +4078,8 @@ TypeResult Sema::ActOnTemplateIdType(
TemplateTy TemplateD, IdentifierInfo *TemplateII,
SourceLocation TemplateIILoc, SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc,
- bool IsCtorOrDtorName, bool IsClassName) {
+ bool IsCtorOrDtorName, bool IsClassName,
+ ImplicitTypenameContext AllowImplicitTypename) {
if (SS.isInvalid())
return true;
@@ -3978,9 +4093,18 @@ TypeResult Sema::ActOnTemplateIdType(
// qualified-id denotes a type, forming an
// elaborated-type-specifier (7.1.5.3).
if (!LookupCtx && isDependentScopeSpecifier(SS)) {
- Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
- << SS.getScopeRep() << TemplateII->getName();
- // Recover as if 'typename' were specified.
+ // C++2a relaxes some of those restrictions in [temp.res]p5.
+ if (AllowImplicitTypename == ImplicitTypenameContext::Yes) {
+ if (getLangOpts().CPlusPlus20)
+ Diag(SS.getBeginLoc(), diag::warn_cxx17_compat_implicit_typename);
+ else
+ Diag(SS.getBeginLoc(), diag::ext_implicit_typename)
+ << SS.getScopeRep() << TemplateII->getName()
+ << FixItHint::CreateInsertion(SS.getBeginLoc(), "typename ");
+ } else
+ Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
+ << SS.getScopeRep() << TemplateII->getName();
+
// FIXME: This is not quite correct recovery as we don't transform SS
// into the corresponding dependent form (and we don't diagnose missing
// 'template' keywords within SS as a result).
@@ -4014,11 +4138,10 @@ TypeResult Sema::ActOnTemplateIdType(
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType T
- = Context.getDependentTemplateSpecializationType(ETK_None,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ assert(SS.getScopeRep() == DTN->getQualifier());
+ QualType T = Context.getDependentTemplateSpecializationType(
+ ETK_None, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Build type-source information.
TypeLocBuilder TLB;
DependentTemplateSpecializationTypeLoc SpecTL
@@ -4034,14 +4157,14 @@ TypeResult Sema::ActOnTemplateIdType(
return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T));
}
- QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
- if (Result.isNull())
+ QualType SpecTy = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs);
+ if (SpecTy.isNull())
return true;
// Build type-source information.
TypeLocBuilder TLB;
- TemplateSpecializationTypeLoc SpecTL
- = TLB.push<TemplateSpecializationTypeLoc>(Result);
+ TemplateSpecializationTypeLoc SpecTL =
+ TLB.push<TemplateSpecializationTypeLoc>(SpecTy);
SpecTL.setTemplateKeywordLoc(TemplateKWLoc);
SpecTL.setTemplateNameLoc(TemplateIILoc);
SpecTL.setLAngleLoc(LAngleLoc);
@@ -4049,18 +4172,14 @@ TypeResult Sema::ActOnTemplateIdType(
for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i)
SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo());
- // NOTE: avoid constructing an ElaboratedTypeLoc if this is a
- // constructor or destructor name (in such a case, the scope specifier
- // will be attached to the enclosing Decl or Expr node).
- if (SS.isNotEmpty() && !IsCtorOrDtorName) {
- // Create an elaborated-type-specifier containing the nested-name-specifier.
- Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result);
- ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result);
- ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ // Create an elaborated-type-specifier containing the nested-name-specifier.
+ QualType ElTy = getElaboratedType(
+ ETK_None, !IsCtorOrDtorName ? SS : CXXScopeSpec(), SpecTy);
+ ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(ElTy);
+ ElabTL.setElaboratedKeywordLoc(SourceLocation());
+ if (!ElabTL.isEmpty())
ElabTL.setQualifierLoc(SS.getWithLocInContext(Context));
- }
-
- return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
+ return CreateParsedType(ElTy, TLB.getTypeSourceInfo(Context, ElTy));
}
TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
@@ -4088,10 +4207,10 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK,
= TypeWithKeyword::getKeywordForTagTypeKind(TagKind);
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType T = Context.getDependentTemplateSpecializationType(Keyword,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ assert(SS.getScopeRep() == DTN->getQualifier());
+ QualType T = Context.getDependentTemplateSpecializationType(
+ Keyword, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Build type-source information.
TypeLocBuilder TLB;
@@ -4386,9 +4505,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
- false, Converted,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -4396,21 +4515,22 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// corresponds to these arguments.
if (IsPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate,
- TemplateArgs.size(), Converted))
+ TemplateArgs.size(),
+ CanonicalConverted))
return true;
// FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we
// also do them during instantiation.
if (!Name.isDependent() &&
- !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted)) {
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< VarTemplate->getDeclName();
IsPartialSpecialization = false;
}
if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
- Converted) &&
+ CanonicalConverted) &&
(!Context.getLangOpts().CPlusPlus20 ||
!TemplateParams->hasAssociatedConstraints())) {
// C++ [temp.class.spec]p9b3:
@@ -4431,10 +4551,10 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplateSpecializationDecl *PrevDecl = nullptr;
if (IsPartialSpecialization)
- PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams,
- InsertPos);
+ PrevDecl = VarTemplate->findPartialSpecialization(
+ CanonicalConverted, TemplateParams, InsertPos);
else
- PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
+ PrevDecl = VarTemplate->findSpecialization(CanonicalConverted, InsertPos);
VarTemplateSpecializationDecl *Specialization = nullptr;
@@ -4461,7 +4581,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
- Converted, TemplateArgs);
+ CanonicalConverted, TemplateArgs);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -4478,7 +4598,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// this explicit specialization or friend declaration.
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
- VarTemplate, DI->getType(), DI, SC, Converted);
+ VarTemplate, DI->getType(), DI, SC, CanonicalConverted);
Specialization->setTemplateArgsInfo(TemplateArgs);
if (!PrevDecl)
@@ -4556,24 +4676,25 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
assert(Template && "A variable template id without template?");
// Check that the template argument list is well-formed for this template.
- SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- Converted, /*UpdateArgsWithConversions=*/true))
+ SugaredConverted, CanonicalConverted,
+ /*UpdateArgsWithConversions=*/true))
return true;
// Produce a placeholder value if the specialization is dependent.
if (Template->getDeclContext()->isDependentContext() ||
- TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted))
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted))
return DeclResult();
// Find the variable template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(
- Converted, InsertPos)) {
+ if (VarTemplateSpecializationDecl *Spec =
+ Template->findSpecialization(CanonicalConverted, InsertPos)) {
checkSpecializationReachability(TemplateNameLoc, Spec);
// If we already have a variable template specialization, return it.
return Spec;
@@ -4585,7 +4706,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// that it represents. That is,
VarDecl *InstantiationPattern = Template->getTemplatedDecl();
TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
- Converted);
+ CanonicalConverted);
TemplateArgumentList *InstantiationArgs = &TemplateArgList;
bool AmbiguousPartialSpec = false;
typedef PartialSpecMatchResult MatchResult;
@@ -4617,7 +4738,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
} else {
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
- Matched.back().Args = Info.take();
+ Matched.back().Args = Info.takeCanonical();
}
}
@@ -4673,7 +4794,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// FIXME: LateAttrs et al.?
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
Template, InstantiationPattern, *InstantiationArgs, TemplateArgs,
- Converted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
+ CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
if (!Decl)
return true;
@@ -4744,29 +4865,41 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
const TemplateArgumentListInfo *TemplateArgs) {
assert(NamedConcept && "A concept template id without a template?");
- llvm::SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(),
- const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
- /*PartialTemplateArgs=*/false, Converted,
- /*UpdateArgsWithConversions=*/false))
+ llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(
+ NamedConcept, ConceptNameInfo.getLoc(),
+ const_cast<TemplateArgumentListInfo &>(*TemplateArgs),
+ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted,
+ /*UpdateArgsWithConversions=*/false))
return ExprError();
+ auto *CSD = ImplicitConceptSpecializationDecl::Create(
+ Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
+ CanonicalConverted);
ConstraintSatisfaction Satisfaction;
bool AreArgsDependent =
- TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
- Converted);
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ *TemplateArgs, CanonicalConverted);
+ MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted,
+ /*Final=*/false);
+ LocalInstantiationScope Scope(*this);
+
+ EnterExpressionEvaluationContext EECtx{
+ *this, ExpressionEvaluationContext::ConstantEvaluated, CSD};
+
if (!AreArgsDependent &&
CheckConstraintSatisfaction(
- NamedConcept, {NamedConcept->getConstraintExpr()}, Converted,
+ NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL,
SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(),
TemplateArgs->getRAngleLoc()),
Satisfaction))
return ExprError();
- return ConceptSpecializationExpr::Create(Context,
+ return ConceptSpecializationExpr::Create(
+ Context,
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
- ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
+ ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), CSD,
AreArgsDependent ? nullptr : &Satisfaction);
}
@@ -5008,9 +5141,10 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S,
return TNK_Non_template;
}
-bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
- TemplateArgumentLoc &AL,
- SmallVectorImpl<TemplateArgument> &Converted) {
+bool Sema::CheckTemplateTypeArgument(
+ TemplateTypeParmDecl *Param, TemplateArgumentLoc &AL,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted) {
const TemplateArgument &Arg = AL.getArgument();
QualType ArgType;
TypeSourceInfo *TSI = nullptr;
@@ -5087,7 +5221,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
}
}
// fallthrough
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
default: {
// We have a template type parameter but the template argument
@@ -5103,9 +5237,6 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
if (CheckTemplateArgument(TSI))
return true;
- // Add the converted template type argument.
- ArgType = Context.getCanonicalType(ArgType);
-
// Objective-C ARC:
// If an explicitly-specified template argument type is a lifetime type
// with no lifetime qualifier, the __strong lifetime qualifier is inferred.
@@ -5117,7 +5248,9 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
ArgType = Context.getQualifiedType(ArgType, Qs);
}
- Converted.push_back(TemplateArgument(ArgType));
+ SugaredConverted.push_back(TemplateArgument(ArgType));
+ CanonicalConverted.push_back(
+ TemplateArgument(Context.getCanonicalType(ArgType)));
return false;
}
@@ -5142,31 +5275,27 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
/// \param Converted the list of template arguments provided for template
/// parameters that precede \p Param in the template parameter list.
/// \returns the substituted template argument, or NULL if an error occurred.
-static TypeSourceInfo *
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- TemplateTypeParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted) {
+static TypeSourceInfo *SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, TemplateTypeParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted) {
TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo();
// If the argument type is dependent, instantiate it now based
// on the previously-computed template arguments.
if (ArgType->getType()->isInstantiationDependentType()) {
- Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Param, Template, Converted,
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return nullptr;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
bool ForLambdaCallOperator = false;
if (const auto *Rec = dyn_cast<CXXRecordDecl>(Template->getDeclContext()))
@@ -5203,26 +5332,22 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// parameters that precede \p Param in the template parameter list.
///
/// \returns the substituted template argument, or NULL if an error occurred.
-static ExprResult
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- NonTypeTemplateParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted) {
- Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Param, Template, Converted,
+static ExprResult SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted) {
+ Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return ExprError();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext ConstantEvaluated(
@@ -5255,27 +5380,23 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// source-location information) that precedes the template name.
///
/// \returns the substituted template argument, or NULL if an error occurred.
-static TemplateName
-SubstDefaultTemplateArgument(Sema &SemaRef,
- TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- TemplateTemplateParmDecl *Param,
- SmallVectorImpl<TemplateArgument> &Converted,
- NestedNameSpecifierLoc &QualifierLoc) {
+static TemplateName SubstDefaultTemplateArgument(
+ Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted,
+ NestedNameSpecifierLoc &QualifierLoc) {
Sema::InstantiatingTemplate Inst(
- SemaRef, TemplateLoc, TemplateParameter(Param), Template, Converted,
- SourceRange(TemplateLoc, RAngleLoc));
+ SemaRef, TemplateLoc, TemplateParameter(Param), Template,
+ SugaredConverted, SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return TemplateName();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
-
// Only substitute for the innermost template argument list.
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted,
+ /*Final=*/true);
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
- TemplateArgLists.addOuterTemplateArguments(None);
+ TemplateArgLists.addOuterTemplateArguments(std::nullopt);
Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
// Substitute into the nested-name-specifier first,
@@ -5297,14 +5418,11 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
/// If the given template parameter has a default template
/// argument, substitute into that default template argument and
/// return the corresponding template argument.
-TemplateArgumentLoc
-Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- Decl *Param,
- SmallVectorImpl<TemplateArgument>
- &Converted,
- bool &HasDefaultArg) {
+TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable(
+ TemplateDecl *Template, SourceLocation TemplateLoc,
+ SourceLocation RAngleLoc, Decl *Param,
+ ArrayRef<TemplateArgument> SugaredConverted,
+ ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg) {
HasDefaultArg = false;
if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) {
@@ -5312,11 +5430,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
return TemplateArgumentLoc();
HasDefaultArg = true;
- TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TypeParm,
- Converted);
+ TypeSourceInfo *DI = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TypeParm, SugaredConverted,
+ CanonicalConverted);
if (DI)
return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI);
@@ -5329,11 +5445,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
return TemplateArgumentLoc();
HasDefaultArg = true;
- ExprResult Arg = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- NonTypeParm,
- Converted);
+ ExprResult Arg = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, NonTypeParm, SugaredConverted,
+ CanonicalConverted);
if (Arg.isInvalid())
return TemplateArgumentLoc();
@@ -5348,12 +5462,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template,
HasDefaultArg = true;
NestedNameSpecifierLoc QualifierLoc;
- TemplateName TName = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TempTempParm,
- Converted,
- QualifierLoc);
+ TemplateName TName = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TempTempParm, SugaredConverted,
+ CanonicalConverted, QualifierLoc);
if (TName.isNull())
return TemplateArgumentLoc();
@@ -5423,17 +5534,17 @@ convertTypeTemplateArgumentToTemplate(ASTContext &Context, TypeLoc TLoc) {
/// explicitly written, deduced, etc.
///
/// \returns true on error, false otherwise.
-bool Sema::CheckTemplateArgument(NamedDecl *Param,
- TemplateArgumentLoc &Arg,
- NamedDecl *Template,
- SourceLocation TemplateLoc,
- SourceLocation RAngleLoc,
- unsigned ArgumentPackIndex,
- SmallVectorImpl<TemplateArgument> &Converted,
- CheckTemplateArgumentKind CTAK) {
+bool Sema::CheckTemplateArgument(
+ NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template,
+ SourceLocation TemplateLoc, SourceLocation RAngleLoc,
+ unsigned ArgumentPackIndex,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted,
+ CheckTemplateArgumentKind CTAK) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
- return CheckTemplateTypeArgument(TTP, Arg, Converted);
+ return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
+ CanonicalConverted);
// Check non-type template parameters.
if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) {
@@ -5448,27 +5559,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
!isa<TemplateTemplateParmDecl>(Template) &&
!Template->getDeclContext()->isDependentContext()) {
// Do substitution on the type of the non-type template parameter.
- InstantiatingTemplate Inst(*this, TemplateLoc, Template,
- NTTP, Converted,
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted);
-
+ MultiLevelTemplateArgumentList MLTAL(Template, SugaredConverted,
+ /*Final=*/true);
// If the parameter is a pack expansion, expand this slice of the pack.
if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this,
ArgumentPackIndex);
- NTTPType = SubstType(PET->getPattern(),
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
+ NTTPType = SubstType(PET->getPattern(), MLTAL, NTTP->getLocation(),
NTTP->getDeclName());
} else {
- NTTPType = SubstType(NTTPType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
+ NTTPType = SubstType(NTTPType, MLTAL, NTTP->getLocation(),
NTTP->getDeclName());
}
@@ -5486,11 +5592,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
llvm_unreachable("Should never see a NULL template argument here");
case TemplateArgument::Expression: {
- TemplateArgument Result;
+ Expr *E = Arg.getArgument().getAsExpr();
+ TemplateArgument SugaredResult, CanonicalResult;
unsigned CurSFINAEErrors = NumSFINAEErrors;
- ExprResult Res =
- CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(),
- Result, CTAK);
+ ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult,
+ CanonicalResult, CTAK);
if (Res.isInvalid())
return true;
// If the current template argument causes an error, give up now.
@@ -5499,12 +5605,13 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// If the resulting expression is new, then use it in place of the
// old expression in the template argument.
- if (Res.get() != Arg.getArgument().getAsExpr()) {
+ if (Res.get() != E) {
TemplateArgument TA(Res.get());
Arg = TemplateArgumentLoc(TA, Res.get());
}
- Converted.push_back(Result);
+ SugaredConverted.push_back(SugaredResult);
+ CanonicalConverted.push_back(CanonicalResult);
break;
}
@@ -5513,7 +5620,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::NullPtr:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
- Converted.push_back(Arg.getArgument());
+ SugaredConverted.push_back(Arg.getArgument());
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg.getArgument()));
break;
case TemplateArgument::Template:
@@ -5549,12 +5658,14 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;
}
- TemplateArgument Result;
- E = CheckTemplateArgument(NTTP, NTTPType, E.get(), Result);
+ TemplateArgument SugaredResult, CanonicalResult;
+ E = CheckTemplateArgument(NTTP, NTTPType, E.get(), SugaredResult,
+ CanonicalResult, CTAK_Specified);
if (E.isInvalid())
return true;
- Converted.push_back(Result);
+ SugaredConverted.push_back(SugaredResult);
+ CanonicalConverted.push_back(CanonicalResult);
break;
}
@@ -5611,15 +5722,17 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
{
// Set up a template instantiation context.
LocalInstantiationScope Scope(*this);
- InstantiatingTemplate Inst(*this, TemplateLoc, Template,
- TempParm, Converted,
+ InstantiatingTemplate Inst(*this, TemplateLoc, Template, TempParm,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
- Params = SubstTemplateParams(Params, CurContext,
- MultiLevelTemplateArgumentList(TemplateArgs));
+ Params =
+ SubstTemplateParams(Params, CurContext,
+ MultiLevelTemplateArgumentList(
+ Template, SugaredConverted, /*Final=*/true),
+ /*EvaluateConstraints=*/false);
if (!Params)
return true;
}
@@ -5644,7 +5757,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
if (CheckTemplateTemplateArgument(TempParm, Params, Arg))
return true;
- Converted.push_back(Arg.getArgument());
+ SugaredConverted.push_back(Arg.getArgument());
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg.getArgument()));
break;
case TemplateArgument::Expression:
@@ -5711,7 +5826,8 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
bool Sema::CheckTemplateArgumentList(
TemplateDecl *Template, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
- SmallVectorImpl<TemplateArgument> &Converted,
+ SmallVectorImpl<TemplateArgument> &SugaredConverted,
+ SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) {
if (ConstraintsNotSatisfied)
@@ -5737,7 +5853,8 @@ bool Sema::CheckTemplateArgumentList(
// corresponding parameter declared by the template in its
// template-parameter-list.
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
- SmallVector<TemplateArgument, 2> ArgumentPack;
+ SmallVector<TemplateArgument, 2> SugaredArgumentPack;
+ SmallVector<TemplateArgument, 2> CanonicalArgumentPack;
unsigned ArgIdx = 0, NumArgs = NewArgs.size();
LocalInstantiationScope InstScope(*this, true);
for (TemplateParameterList::iterator Param = Params->begin(),
@@ -5745,13 +5862,17 @@ bool Sema::CheckTemplateArgumentList(
Param != ParamEnd; /* increment in loop */) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
- if (Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
- if (*Expansions == ArgumentPack.size()) {
+ if (std::optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
+ if (*Expansions == SugaredArgumentPack.size()) {
// We're done with this parameter pack. Pack up its arguments and add
// them to the list.
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
- ArgumentPack.clear();
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ SugaredArgumentPack.clear();
+
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ CanonicalArgumentPack.clear();
// This argument is assigned to the next parameter.
++Param;
@@ -5770,9 +5891,10 @@ bool Sema::CheckTemplateArgumentList(
if (ArgIdx < NumArgs) {
// Check the template argument we were given.
- if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template,
- TemplateLoc, RAngleLoc,
- ArgumentPack.size(), Converted))
+ if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
+ RAngleLoc, SugaredArgumentPack.size(),
+ SugaredConverted, CanonicalConverted,
+ CTAK_Specified))
return true;
bool PackExpansionIntoNonPack =
@@ -5801,7 +5923,8 @@ bool Sema::CheckTemplateArgumentList(
// deduced argument and place it on the argument pack. Note that we
// stay on the same template parameter so that we can deduce more
// arguments.
- ArgumentPack.push_back(Converted.pop_back_val());
+ SugaredArgumentPack.push_back(SugaredConverted.pop_back_val());
+ CanonicalArgumentPack.push_back(CanonicalConverted.pop_back_val());
} else {
// Move to the next template parameter.
++Param;
@@ -5811,16 +5934,25 @@ bool Sema::CheckTemplateArgumentList(
// the remaining arguments, because we don't know what parameters they'll
// match up with.
if (PackExpansionIntoNonPack) {
- if (!ArgumentPack.empty()) {
+ if (!SugaredArgumentPack.empty()) {
// If we were part way through filling in an expanded parameter pack,
// fall back to just producing individual arguments.
- Converted.insert(Converted.end(),
- ArgumentPack.begin(), ArgumentPack.end());
- ArgumentPack.clear();
+ SugaredConverted.insert(SugaredConverted.end(),
+ SugaredArgumentPack.begin(),
+ SugaredArgumentPack.end());
+ SugaredArgumentPack.clear();
+
+ CanonicalConverted.insert(CanonicalConverted.end(),
+ CanonicalArgumentPack.begin(),
+ CanonicalArgumentPack.end());
+ CanonicalArgumentPack.clear();
}
while (ArgIdx < NumArgs) {
- Converted.push_back(NewArgs[ArgIdx].getArgument());
+ const TemplateArgument &Arg = NewArgs[ArgIdx].getArgument();
+ SugaredConverted.push_back(Arg);
+ CanonicalConverted.push_back(
+ Context.getCanonicalTemplateArgument(Arg));
++ArgIdx;
}
@@ -5832,9 +5964,12 @@ bool Sema::CheckTemplateArgumentList(
// If we're checking a partial template argument list, we're done.
if (PartialTemplateArgs) {
- if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty())
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
+ if ((*Param)->isTemplateParameterPack() && !SugaredArgumentPack.empty()) {
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ }
return false;
}
@@ -5847,12 +5982,20 @@ bool Sema::CheckTemplateArgumentList(
// A non-expanded parameter pack before the end of the parameter list
// only occurs for an ill-formed template parameter list, unless we've
// got a partial argument list for a function template, so just bail out.
- if (Param + 1 != ParamEnd)
+ if (Param + 1 != ParamEnd) {
+ assert(
+ (Template->getMostRecentDecl()->getKind() != Decl::Kind::Concept) &&
+ "Concept templates must have parameter packs at the end.");
return true;
+ }
+
+ SugaredConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack));
+ SugaredArgumentPack.clear();
- Converted.push_back(
- TemplateArgument::CreatePackCopy(Context, ArgumentPack));
- ArgumentPack.clear();
+ CanonicalConverted.push_back(
+ TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack));
+ CanonicalArgumentPack.clear();
++Param;
continue;
@@ -5871,12 +6014,9 @@ bool Sema::CheckTemplateArgumentList(
return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP,
NewArgs);
- TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this,
- Template,
- TemplateLoc,
- RAngleLoc,
- TTP,
- Converted);
+ TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TTP, SugaredConverted,
+ CanonicalConverted);
if (!ArgType)
return true;
@@ -5888,11 +6028,9 @@ bool Sema::CheckTemplateArgumentList(
return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP,
NewArgs);
- ExprResult E = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- NTTP,
- Converted);
+ ExprResult E = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, NTTP, SugaredConverted,
+ CanonicalConverted);
if (E.isInvalid())
return true;
@@ -5907,12 +6045,9 @@ bool Sema::CheckTemplateArgumentList(
NewArgs);
NestedNameSpecifierLoc QualifierLoc;
- TemplateName Name = SubstDefaultTemplateArgument(*this, Template,
- TemplateLoc,
- RAngleLoc,
- TempParm,
- Converted,
- QualifierLoc);
+ TemplateName Name = SubstDefaultTemplateArgument(
+ *this, Template, TemplateLoc, RAngleLoc, TempParm, SugaredConverted,
+ CanonicalConverted, QualifierLoc);
if (Name.isNull())
return true;
@@ -5925,14 +6060,16 @@ bool Sema::CheckTemplateArgumentList(
// the default template argument. We're not actually instantiating a
// template here, we just create this object to put a note into the
// context stack.
- InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, Converted,
+ InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param,
+ SugaredConverted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return true;
// Check the default template argument.
- if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc,
- RAngleLoc, 0, Converted))
+ if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
+ SugaredConverted, CanonicalConverted,
+ CTAK_Specified))
return true;
// Core issue 150 (assumed resolution): if this is a template template
@@ -5952,8 +6089,12 @@ bool Sema::CheckTemplateArgumentList(
// still dependent).
if (ArgIdx < NumArgs && CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack()) {
- while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion())
- Converted.push_back(NewArgs[ArgIdx++].getArgument());
+ while (ArgIdx < NumArgs &&
+ NewArgs[ArgIdx].getArgument().isPackExpansion()) {
+ const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument();
+ SugaredConverted.push_back(Arg);
+ CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg));
+ }
}
// If we have any leftover arguments, then there were too many arguments.
@@ -5974,13 +6115,39 @@ bool Sema::CheckTemplateArgumentList(
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
- if (!PartialTemplateArgs &&
- EnsureTemplateArgumentListConstraints(
- Template, Converted, SourceRange(TemplateLoc,
- TemplateArgs.getRAngleLoc()))) {
- if (ConstraintsNotSatisfied)
- *ConstraintsNotSatisfied = true;
- return true;
+ if (!PartialTemplateArgs) {
+ TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
+ CanonicalConverted);
+ // Setup the context/ThisScope for the case where we are needing to
+ // re-instantiate constraints outside of normal instantiation.
+ DeclContext *NewContext = Template->getDeclContext();
+
+ // If this template is in a template, make sure we extract the templated
+ // decl.
+ if (auto *TD = dyn_cast<TemplateDecl>(NewContext))
+ NewContext = Decl::castToDeclContext(TD->getTemplatedDecl());
+ auto *RD = dyn_cast<CXXRecordDecl>(NewContext);
+
+ Qualifiers ThisQuals;
+ if (const auto *Method =
+ dyn_cast_or_null<CXXMethodDecl>(Template->getTemplatedDecl()))
+ ThisQuals = Method->getMethodQualifiers();
+
+ ContextRAII Context(*this, NewContext);
+ CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);
+
+ MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
+ Template, /*Final=*/false, &StackTemplateArgs,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConceptInstantiation=*/true);
+ if (EnsureTemplateArgumentListConstraints(
+ Template, MLTAL,
+ SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
+ if (ConstraintsNotSatisfied)
+ *ConstraintsNotSatisfied = true;
+ return true;
+ }
}
return false;
@@ -6125,7 +6292,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTypeOfExprType(const TypeOfExprType*) {
}
bool UnnamedLocalNoLinkageFinder::VisitTypeOfType(const TypeOfType* T) {
- return Visit(T->getUnderlyingType());
+ return Visit(T->getUnmodifiedType());
}
bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) {
@@ -6274,8 +6441,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
assert(ArgInfo && "invalid TypeSourceInfo");
QualType Arg = ArgInfo->getType();
SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
+ QualType CanonArg = Context.getCanonicalType(Arg);
- if (Arg->isVariablyModifiedType()) {
+ if (CanonArg->isVariablyModifiedType()) {
return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg;
} else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) {
return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR;
@@ -6288,9 +6456,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
//
// C++11 allows these, and even in C++03 we allow them as an extension with
// a warning.
- if (LangOpts.CPlusPlus11 || Arg->hasUnnamedOrLocalType()) {
+ if (LangOpts.CPlusPlus11 || CanonArg->hasUnnamedOrLocalType()) {
UnnamedLocalNoLinkageFinder Finder(*this, SR);
- (void)Finder.Visit(Context.getCanonicalType(Arg));
+ (void)Finder.Visit(CanonArg);
}
return false;
@@ -6362,7 +6530,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
// - a constant expression that evaluates to a null pointer value (4.10); or
// - a constant expression that evaluates to a null member pointer value
// (4.11); or
- if ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) ||
+ if ((EvalResult.Val.isLValue() && EvalResult.Val.isNullPointer()) ||
(EvalResult.Val.isMemberPointer() &&
!EvalResult.Val.getMemberPointerDecl())) {
// If our expression has an appropriate type, we've succeeded.
@@ -6380,6 +6548,16 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
return NPV_NullPointer;
}
+ if (EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) {
+ // We found a pointer that isn't null, but doesn't refer to an object.
+ // We could just return NPV_NotNullPointer, but we can print a better
+ // message with the information we have here.
+ S.Diag(Arg->getExprLoc(), diag::err_template_arg_invalid)
+ << EvalResult.Val.getAsString(S.Context, ParamType);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return NPV_Error;
+ }
+
// If we don't have a null pointer value, but we do have a NULL pointer
// constant, suggest a cast to the appropriate type.
if (Arg->isNullPointerConstant(S.Context, Expr::NPC_NeverValueDependent)) {
@@ -6457,12 +6635,9 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
/// Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
-static bool
-CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
- NonTypeTemplateParmDecl *Param,
- QualType ParamType,
- Expr *ArgIn,
- TemplateArgument &Converted) {
+static bool CheckTemplateArgumentAddressOfObjectOrFunction(
+ Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn,
+ TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ArgIn;
QualType ArgType = Arg->getType();
@@ -6566,8 +6741,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
Entity)) {
case NPV_NullPointer:
S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
- /*isNullPtr=*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr=*/true);
+ CanonicalConverted =
+ TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr=*/true);
return false;
case NPV_Error:
@@ -6581,7 +6759,9 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Stop checking the precise nature of the argument if it is value dependent,
// it should be checked when instantiated.
if (Arg->isValueDependent()) {
- Converted = TemplateArgument(ArgIn);
+ SugaredConverted = TemplateArgument(ArgIn);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
return false;
}
@@ -6711,19 +6891,21 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
return true;
// Create the template argument.
- Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
- S.Context.getCanonicalType(ParamType));
+ SugaredConverted = TemplateArgument(Entity, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
S.MarkAnyDeclReferenced(Arg->getBeginLoc(), Entity, false);
return false;
}
/// Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
-static bool CheckTemplateArgumentPointerToMember(Sema &S,
- NonTypeTemplateParmDecl *Param,
- QualType ParamType,
- Expr *&ResultArg,
- TemplateArgument &Converted) {
+static bool
+CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param,
+ QualType ParamType, Expr *&ResultArg,
+ TemplateArgument &SugaredConverted,
+ TemplateArgument &CanonicalConverted) {
bool Invalid = false;
Expr *Arg = ResultArg;
@@ -6771,10 +6953,14 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
if (VD->getType()->isMemberPointerType()) {
if (isa<NonTypeTemplateParmDecl>(VD)) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
} else {
- VD = cast<ValueDecl>(VD->getCanonicalDecl());
- Converted = TemplateArgument(VD, ParamType);
+ SugaredConverted = TemplateArgument(VD, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
}
return Invalid;
}
@@ -6792,8 +6978,10 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
return true;
case NPV_NullPointer:
S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(S.Context.getCanonicalType(ParamType),
- /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr*/ true);
+ CanonicalConverted = TemplateArgument(S.Context.getCanonicalType(ParamType),
+ /*isNullPtr*/ true);
return false;
case NPV_NotNullPointer:
break;
@@ -6830,10 +7018,15 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
// Okay: this is the address of a non-static member, and therefore
// a member pointer constant.
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ S.Context.getCanonicalTemplateArgument(SugaredConverted);
} else {
- ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
- Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType));
+ ValueDecl *D = DRE->getDecl();
+ SugaredConverted = TemplateArgument(D, ParamType);
+ CanonicalConverted =
+ TemplateArgument(cast<ValueDecl>(D->getCanonicalDecl()),
+ S.Context.getCanonicalType(ParamType));
}
return Invalid;
}
@@ -6854,7 +7047,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
/// type of the non-type template parameter after it has been instantiated.
ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType ParamType, Expr *Arg,
- TemplateArgument &Converted,
+ TemplateArgument &SugaredConverted,
+ TemplateArgument &CanonicalConverted,
CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getBeginLoc();
@@ -6869,7 +7063,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) {
auto *AT = dyn_cast<AutoType>(DeducedT);
if (AT && AT->isDecltypeAuto()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg;
}
}
@@ -6877,7 +7073,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
- Optional<unsigned> Depth = Param->getDepth() + 1;
Expr *DeductionArg = Arg;
if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg))
DeductionArg = PE->getPattern();
@@ -6893,20 +7088,30 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, Inits);
if (ParamType.isNull())
return ExprError();
- } else if (DeduceAutoType(
- TSI, DeductionArg, ParamType, Depth,
- // We do not check constraints right now because the
- // immediately-declared constraint of the auto type is also
- // an associated constraint, and will be checked along with
- // the other associated constraints after checking the
- // template argument list.
- /*IgnoreConstraints=*/true) == DAR_Failed) {
- Diag(Arg->getExprLoc(),
- diag::err_non_type_template_parm_type_deduction_failure)
- << Param->getDeclName() << Param->getType() << Arg->getType()
- << Arg->getSourceRange();
- Diag(Param->getLocation(), diag::note_template_param_here);
- return ExprError();
+ } else {
+ TemplateDeductionInfo Info(DeductionArg->getExprLoc(),
+ Param->getDepth() + 1);
+ ParamType = QualType();
+ TemplateDeductionResult Result =
+ DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info,
+ /*DependentDeduction=*/true,
+ // We do not check constraints right now because the
+ // immediately-declared constraint of the auto type is
+ // also an associated constraint, and will be checked
+ // along with the other associated constraints after
+ // checking the template argument list.
+ /*IgnoreConstraints=*/true);
+ if (Result == TDK_AlreadyDiagnosed) {
+ if (ParamType.isNull())
+ return ExprError();
+ } else if (Result != TDK_Success) {
+ Diag(Arg->getExprLoc(),
+ diag::err_non_type_template_parm_type_deduction_failure)
+ << Param->getDeclName() << Param->getType() << Arg->getType()
+ << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return ExprError();
+ }
}
// CheckNonTypeTemplateParameterType will produce a diagnostic if there's
// an error. The error message normally references the parameter
@@ -6938,7 +7143,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// work. Similarly for CTAD, when comparing 'A<x>' against 'A'.
if ((ParamType->isDependentType() || Arg->isTypeDependent()) &&
!Arg->getType()->getContainedDeducedType()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return Arg;
}
// FIXME: This attempts to implement C++ [temp.deduct.type]p17. Per DR1770,
@@ -6953,11 +7160,8 @@ 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. 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()) {
+ // type-dependent, there's nothing we can check now.
+ if (ParamType->isDependentType() || Arg->isTypeDependent()) {
// Force the argument to the type of the parameter to maintain invariants.
auto *PE = dyn_cast<PackExpansionExpr>(Arg);
if (PE)
@@ -6975,7 +7179,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(),
PE->getNumExpansions());
}
- Converted = TemplateArgument(E.get());
+ SugaredConverted = TemplateArgument(E.get());
+ CanonicalConverted = TemplateArgument(
+ Context.getCanonicalTemplateArgument(SugaredConverted));
return E;
}
@@ -7000,11 +7206,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Context.hasSameUnqualifiedType(ParamType, InnerArg->getType())) {
NamedDecl *ND = cast<DeclRefExpr>(InnerArg)->getDecl();
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
- Converted = TemplateArgument(TPO, CanonParamType);
+
+ SugaredConverted = TemplateArgument(TPO, ParamType);
+ CanonicalConverted =
+ TemplateArgument(TPO->getCanonicalDecl(), CanonParamType);
return Arg;
}
if (isa<NonTypeTemplateParmDecl>(ND)) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
}
@@ -7021,7 +7232,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// For a value-dependent argument, CheckConvertedConstantExpression is
// permitted (and expected) to be unable to determine a value.
if (ArgResult.get()->isValueDependent()) {
- Converted = TemplateArgument(ArgResult.get());
+ SugaredConverted = TemplateArgument(ArgResult.get());
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return ArgResult;
}
@@ -7029,14 +7242,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
switch (Value.getKind()) {
case APValue::None:
assert(ParamType->isNullPtrType());
- Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted = TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
case APValue::Indeterminate:
llvm_unreachable("result of constant evaluation should be initialized");
break;
case APValue::Int:
assert(ParamType->isIntegralOrEnumerationType());
- Converted = TemplateArgument(Context, Value.getInt(), CanonParamType);
+ SugaredConverted = TemplateArgument(Context, Value.getInt(), ParamType);
+ CanonicalConverted =
+ TemplateArgument(Context, Value.getInt(), CanonParamType);
break;
case APValue::MemberPointer: {
assert(ParamType->isMemberPointerType());
@@ -7051,8 +7267,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl());
- Converted = VD ? TemplateArgument(VD, CanonParamType)
- : TemplateArgument(CanonParamType, /*isNullPtr*/true);
+ SugaredConverted = VD ? TemplateArgument(VD, ParamType)
+ : TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted =
+ VD ? TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ CanonParamType)
+ : TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
}
case APValue::LValue: {
@@ -7092,17 +7312,25 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
- Converted = VD ? TemplateArgument(VD, CanonParamType)
- : TemplateArgument(CanonParamType, /*isNullPtr*/true);
+
+ SugaredConverted = VD ? TemplateArgument(VD, ParamType)
+ : TemplateArgument(ParamType, /*isNullPtr=*/true);
+ CanonicalConverted =
+ VD ? TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()),
+ CanonParamType)
+ : TemplateArgument(CanonParamType, /*isNullPtr=*/true);
break;
}
case APValue::Struct:
- case APValue::Union:
+ case APValue::Union: {
// Get or create the corresponding template parameter object.
- Converted = TemplateArgument(
- Context.getTemplateParamObjectDecl(CanonParamType, Value),
- CanonParamType);
+ TemplateParamObjectDecl *D =
+ Context.getTemplateParamObjectDecl(ParamType, Value);
+ SugaredConverted = TemplateArgument(D, ParamType);
+ CanonicalConverted =
+ TemplateArgument(D->getCanonicalDecl(), CanonParamType);
break;
+ }
case APValue::AddrLabelDiff:
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
case APValue::FixedPoint:
@@ -7152,7 +7380,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// We can't check arbitrary value-dependent arguments.
if (ArgResult.get()->isValueDependent()) {
- Converted = TemplateArgument(ArgResult.get());
+ SugaredConverted = TemplateArgument(ArgResult.get());
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return ArgResult;
}
@@ -7166,8 +7396,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
? Context.getIntWidth(IntegerType)
: Context.getTypeSize(IntegerType));
- Converted = TemplateArgument(Context, Value,
- Context.getCanonicalType(ParamType));
+ SugaredConverted = TemplateArgument(Context, Value, ParamType);
+ CanonicalConverted =
+ TemplateArgument(Context, Value, Context.getCanonicalType(ParamType));
return ArgResult;
}
@@ -7237,13 +7468,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
if (Arg->isValueDependent()) {
// The argument is value-dependent. Create a new
// TemplateArgument with the converted expression.
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
- QualType IntegerType = Context.getCanonicalType(ParamType);
- if (const EnumType *Enum = IntegerType->getAs<EnumType>())
- IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType());
+ QualType IntegerType = ParamType;
+ if (const EnumType *Enum = IntegerType->getAs<EnumType>()) {
+ IntegerType = Enum->getDecl()->getIntegerType();
+ }
if (ParamType->isBooleanType()) {
// Value must be zero or one.
@@ -7289,10 +7523,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
}
- Converted = TemplateArgument(Context, Value,
- ParamType->isEnumeralType()
- ? Context.getCanonicalType(ParamType)
- : IntegerType);
+ QualType T = ParamType->isEnumeralType() ? ParamType : IntegerType;
+ SugaredConverted = TemplateArgument(Context, Value, T);
+ CanonicalConverted =
+ TemplateArgument(Context, Value, Context.getCanonicalType(T));
return Arg;
}
@@ -7337,15 +7571,15 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
if (!ParamType->isMemberPointerType()) {
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted,
+ CanonicalConverted))
return ExprError();
return Arg;
}
- if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
- Converted))
+ if (CheckTemplateArgumentPointerToMember(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7358,9 +7592,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
assert(ParamType->getPointeeType()->isIncompleteOrObjectType() &&
"Only object pointers allowed here");
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7389,9 +7622,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}
- if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
- ParamType,
- Arg, Converted))
+ if (CheckTemplateArgumentAddressOfObjectOrFunction(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7399,7 +7631,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// Deal with parameters of type std::nullptr_t.
if (ParamType->isNullPtrType()) {
if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
+ SugaredConverted = TemplateArgument(Arg);
+ CanonicalConverted =
+ Context.getCanonicalTemplateArgument(SugaredConverted);
return Arg;
}
@@ -7415,8 +7649,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
case NPV_NullPointer:
Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null);
- Converted = TemplateArgument(Context.getCanonicalType(ParamType),
- /*isNullPtr*/true);
+ SugaredConverted = TemplateArgument(ParamType,
+ /*isNullPtr=*/true);
+ CanonicalConverted = TemplateArgument(Context.getCanonicalType(ParamType),
+ /*isNullPtr=*/true);
return Arg;
}
}
@@ -7425,8 +7661,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// member, qualification conversions (4.4) are applied.
assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
- if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg,
- Converted))
+ if (CheckTemplateArgumentPointerToMember(
+ *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted))
return ExprError();
return Arg;
}
@@ -7499,10 +7735,10 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template,
Arg.getLocation())) {
- // C++2a[temp.func.order]p2
+ // P2113
+ // C++20[temp.func.order]p2
// [...] If both deductions succeed, the partial ordering selects the
- // more constrained template as described by the rules in
- // [temp.constr.order].
+ // more constrained template (if one exists) as determined below.
SmallVector<const Expr *, 3> ParamsAC, TemplateAC;
Params->getAssociatedConstraints(ParamsAC);
// C++2a[temp.arg.template]p3
@@ -7510,7 +7746,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
// are not considered.
if (ParamsAC.empty())
return false;
+
Template->getAssociatedConstraints(TemplateAC);
+
bool IsParamAtLeastAsConstrained;
if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC,
IsParamAtLeastAsConstrained))
@@ -7685,8 +7923,8 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(),
Kind, T, Loc);
} else if (T->isBooleanType()) {
- E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(),
- T, Loc);
+ E = CXXBoolLiteralExpr::Create(Context, Arg.getAsIntegral().getBoolValue(),
+ T, Loc);
} else if (T->isNullPtrType()) {
E = new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc);
} else {
@@ -7706,10 +7944,11 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
}
/// Match two template parameters within template parameter lists.
-static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
- bool Complain,
- Sema::TemplateParameterListEqualKind Kind,
- SourceLocation TemplateArgLoc) {
+static bool MatchTemplateParameterKind(
+ Sema &S, NamedDecl *New, const NamedDecl *NewInstFrom, NamedDecl *Old,
+ const NamedDecl *OldInstFrom, bool Complain,
+ Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc,
+ bool PartialOrdering) {
// Check the actual kind (type, non-type, template).
if (Old->getKind() != New->getKind()) {
if (Complain) {
@@ -7791,20 +8030,34 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
else if (TemplateTemplateParmDecl *OldTTP
= dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
- if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
- OldTTP->getTemplateParameters(),
- Complain,
- (Kind == Sema::TPL_TemplateMatch
- ? Sema::TPL_TemplateTemplateParmMatch
- : Kind),
- TemplateArgLoc))
+ if (!S.TemplateParameterListsAreEqual(
+ NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
+ OldTTP->getTemplateParameters(), Complain,
+ (Kind == Sema::TPL_TemplateMatch
+ ? Sema::TPL_TemplateTemplateParmMatch
+ : Kind),
+ TemplateArgLoc, PartialOrdering))
return false;
- } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) {
+ }
+
+ if (!PartialOrdering && Kind != Sema::TPL_TemplateTemplateArgumentMatch &&
+ !isa<TemplateTemplateParmDecl>(Old)) {
const Expr *NewC = nullptr, *OldC = nullptr;
- if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
- NewC = TC->getImmediatelyDeclaredConstraint();
- if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
- OldC = TC->getImmediatelyDeclaredConstraint();
+
+ if (isa<TemplateTypeParmDecl>(New)) {
+ if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint())
+ NewC = TC->getImmediatelyDeclaredConstraint();
+ if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint())
+ OldC = TC->getImmediatelyDeclaredConstraint();
+ } else if (isa<NonTypeTemplateParmDecl>(New)) {
+ if (const Expr *E = cast<NonTypeTemplateParmDecl>(New)
+ ->getPlaceholderTypeConstraint())
+ NewC = E;
+ if (const Expr *E = cast<NonTypeTemplateParmDecl>(Old)
+ ->getPlaceholderTypeConstraint())
+ OldC = E;
+ } else
+ llvm_unreachable("unexpected template parameter type");
auto Diagnose = [&] {
S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(),
@@ -7820,10 +8073,8 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
}
if (NewC) {
- llvm::FoldingSetNodeID OldCID, NewCID;
- OldC->Profile(OldCID, S.Context, /*Canonical=*/true);
- NewC->Profile(NewCID, S.Context, /*Canonical=*/true);
- if (OldCID != NewCID) {
+ if (!S.AreConstraintExpressionsEqual(OldInstFrom, OldC, NewInstFrom,
+ NewC)) {
if (Complain)
Diagnose();
return false;
@@ -7879,12 +8130,11 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
///
/// \returns True if the template parameter lists are equal, false
/// otherwise.
-bool
-Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
- TemplateParameterList *Old,
- bool Complain,
- TemplateParameterListEqualKind Kind,
- SourceLocation TemplateArgLoc) {
+bool Sema::TemplateParameterListsAreEqual(
+ const NamedDecl *NewInstFrom, TemplateParameterList *New,
+ const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
+ TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc,
+ bool PartialOrdering) {
if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) {
if (Complain)
DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
@@ -7914,8 +8164,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
- if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
- Kind, TemplateArgLoc))
+ if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+ OldInstFrom, Complain, Kind,
+ TemplateArgLoc, PartialOrdering))
return false;
++NewParm;
@@ -7930,8 +8181,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
// template parameter pack in P (ignoring whether those template
// parameters are template parameter packs).
for (; NewParm != NewParmEnd; ++NewParm) {
- if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain,
- Kind, TemplateArgLoc))
+ if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+ OldInstFrom, Complain, Kind,
+ TemplateArgLoc, PartialOrdering))
return false;
}
}
@@ -7945,7 +8197,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
- if (Kind != TPL_TemplateTemplateArgumentMatch) {
+ if (!PartialOrdering && Kind != TPL_TemplateTemplateArgumentMatch) {
const Expr *NewRC = New->getRequiresClause();
const Expr *OldRC = Old->getRequiresClause();
@@ -7963,10 +8215,8 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
}
if (NewRC) {
- llvm::FoldingSetNodeID OldRCID, NewRCID;
- OldRC->Profile(OldRCID, Context, /*Canonical=*/true);
- NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
- if (OldRCID != NewRCID) {
+ if (!AreConstraintExpressionsEqual(OldInstFrom, OldRC, NewInstFrom,
+ NewRC)) {
if (Complain)
Diagnose();
return false;
@@ -8413,9 +8663,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
@@ -8423,14 +8673,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// corresponds to these arguments.
if (isPartialSpecialization) {
if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate,
- TemplateArgs.size(), Converted))
+ TemplateArgs.size(),
+ CanonicalConverted))
return true;
// FIXME: Move this to CheckTemplatePartialSpecializationArgs so we
// also do it during instantiation.
if (!Name.isDependent() &&
- !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs,
- Converted)) {
+ !TemplateSpecializationType::anyDependentTemplateArguments(
+ TemplateArgs, CanonicalConverted)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< ClassTemplate->getDeclName();
isPartialSpecialization = false;
@@ -8441,11 +8692,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
ClassTemplateSpecializationDecl *PrevDecl = nullptr;
if (isPartialSpecialization)
- PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
- TemplateParams,
- InsertPos);
+ PrevDecl = ClassTemplate->findPartialSpecialization(
+ CanonicalConverted, TemplateParams, InsertPos);
else
- PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
+ PrevDecl = ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
ClassTemplateSpecializationDecl *Specialization = nullptr;
@@ -8464,7 +8714,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// arguments of the class template partial specialization.
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(CanonTemplate,
- Converted);
+ CanonicalConverted);
if (Context.hasSameType(CanonType,
ClassTemplate->getInjectedClassNameSpecialization()) &&
@@ -8494,16 +8744,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// Create a new class template partial specialization declaration node.
ClassTemplatePartialSpecializationDecl *PrevPartial
= cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
- ClassTemplatePartialSpecializationDecl *Partial
- = ClassTemplatePartialSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- TemplateParams,
- ClassTemplate,
- Converted,
- TemplateArgs,
- CanonType,
- PrevPartial);
+ ClassTemplatePartialSpecializationDecl *Partial =
+ ClassTemplatePartialSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc,
+ TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted,
+ TemplateArgs, CanonType, PrevPartial);
SetNestedNameSpecifier(*this, Partial, SS);
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
Partial->setTemplateParameterListsInfo(
@@ -8523,13 +8768,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
} else {
// Create a new class template specialization declaration node for
// this explicit specialization or friend declaration.
- Specialization
- = ClassTemplateSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- ClassTemplate,
- Converted,
- PrevDecl);
+ Specialization = ClassTemplateSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
+ ClassTemplate, CanonicalConverted, PrevDecl);
SetNestedNameSpecifier(*this, Specialization, SS);
if (TemplateParameterLists.size() > 0) {
Specialization->setTemplateParameterListsInfo(Context,
@@ -8541,8 +8782,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
if (CurContext->isDependentContext()) {
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
- CanonType = Context.getTemplateSpecializationType(
- CanonTemplate, Converted);
+ CanonType = Context.getTemplateSpecializationType(CanonTemplate,
+ CanonicalConverted);
} else {
CanonType = Context.getTypeDeclType(Specialization);
}
@@ -8686,17 +8927,33 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
return nullptr;
}
- if (TemplateParameterLists.front()->size() == 0) {
+ TemplateParameterList *Params = TemplateParameterLists.front();
+
+ if (Params->size() == 0) {
Diag(NameLoc, diag::err_concept_no_parameters);
return nullptr;
}
+ // Ensure that the parameter pack, if present, is the last parameter in the
+ // template.
+ for (TemplateParameterList::const_iterator ParamIt = Params->begin(),
+ ParamEnd = Params->end();
+ ParamIt != ParamEnd; ++ParamIt) {
+ Decl const *Param = *ParamIt;
+ if (Param->isParameterPack()) {
+ if (++ParamIt == ParamEnd)
+ break;
+ Diag(Param->getLocation(),
+ diag::err_template_param_pack_must_be_last_template_parameter);
+ return nullptr;
+ }
+ }
+
if (DiagnoseUnexpandedParameterPack(ConstraintExpr))
return nullptr;
- ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
- TemplateParameterLists.front(),
- ConstraintExpr);
+ ConceptDecl *NewDecl =
+ ConceptDecl::Create(Context, DC, NameLoc, Name, Params, ConstraintExpr);
if (NewDecl->hasAssociatedConstraints()) {
// C++2a [temp.concept]p4:
@@ -8728,7 +8985,7 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
if (Previous.empty())
return;
- auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl());
+ auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl()->getUnderlyingDecl());
if (!OldConcept) {
auto *Old = Previous.getRepresentativeDecl();
Diag(NewDecl->getLocation(), diag::err_redefinition_different_kind)
@@ -8746,7 +9003,8 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
AddToScope = false;
return;
}
- if (hasReachableDefinition(OldConcept)) {
+ if (hasReachableDefinition(OldConcept) &&
+ IsRedefinitionInModule(NewDecl, OldConcept)) {
Diag(NewDecl->getLocation(), diag::err_redefinition)
<< NewDecl->getDeclName();
notePreviousDefinition(OldConcept, NewDecl->getLocation());
@@ -8758,14 +9016,18 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
// Other decls (e.g. namespaces) also have this shortcoming.
return;
}
- Context.setPrimaryMergedDecl(NewDecl, OldConcept);
+ // We unwrap canonical decl late to check for module visibility.
+ Context.setPrimaryMergedDecl(NewDecl, OldConcept->getCanonicalDecl());
}
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
-static void StripImplicitInstantiation(NamedDecl *D) {
- D->dropAttr<DLLImportAttr>();
- D->dropAttr<DLLExportAttr>();
+static void StripImplicitInstantiation(NamedDecl *D, bool MinGW) {
+ if (MinGW || (isa<FunctionDecl>(D) &&
+ cast<FunctionDecl>(D)->isFunctionTemplateSpecialization())) {
+ D->dropAttr<DLLImportAttr>();
+ D->dropAttr<DLLExportAttr>();
+ }
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
FD->setInlineSpecified(false);
@@ -8840,11 +9102,13 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
if (PrevPointOfInstantiation.isInvalid()) {
// The declaration itself has not actually been instantiated, so it is
// still okay to specialize it.
- StripImplicitInstantiation(PrevDecl);
+ StripImplicitInstantiation(
+ PrevDecl,
+ Context.getTargetInfo().getTriple().isWindowsGNUEnvironment());
return false;
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
@@ -9701,17 +9965,17 @@ DeclResult Sema::ActOnExplicitInstantiation(
// Check that the template argument list is well-formed for this
// template.
- SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
+ false, SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return true;
// Find the class template specialization declaration that
// corresponds to these arguments.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findSpecialization(Converted, InsertPos);
+ ClassTemplateSpecializationDecl *PrevDecl =
+ ClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
TemplateSpecializationKind PrevDecl_TSK
= PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
@@ -9768,13 +10032,9 @@ DeclResult Sema::ActOnExplicitInstantiation(
if (!Specialization) {
// Create a new class template specialization declaration node for
// this explicit specialization.
- Specialization
- = ClassTemplateSpecializationDecl::Create(Context, Kind,
- ClassTemplate->getDeclContext(),
- KWLoc, TemplateNameLoc,
- ClassTemplate,
- Converted,
- PrevDecl);
+ Specialization = ClassTemplateSpecializationDecl::Create(
+ Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
+ ClassTemplate, CanonicalConverted, PrevDecl);
SetNestedNameSpecifier(*this, Specialization, SS);
if (!HasNoEffect && !PrevDecl) {
@@ -9921,13 +10181,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc,
bool Owned = false;
bool IsDependent = false;
- Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference,
- KWLoc, SS, Name, NameLoc, Attr, AS_none,
- /*ModulePrivateLoc=*/SourceLocation(),
- MultiTemplateParamsArg(), Owned, IsDependent,
- SourceLocation(), false, TypeResult(),
- /*IsTypeSpecifier*/false,
- /*IsTemplateParamOrArg*/false);
+ UsingShadowDecl* FoundUsing = nullptr;
+ Decl *TagD =
+ ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr,
+ AS_none, /*ModulePrivateLoc=*/SourceLocation(),
+ MultiTemplateParamsArg(), Owned, IsDependent, SourceLocation(),
+ false, TypeResult(), /*IsTypeSpecifier*/ false,
+ /*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside, FoundUsing)
+ .get();
assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
if (!TagD)
@@ -10469,10 +10730,11 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result));
}
-TypeResult
-Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
- const CXXScopeSpec &SS, const IdentifierInfo &II,
- SourceLocation IdLoc) {
+TypeResult Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
+ const CXXScopeSpec &SS,
+ const IdentifierInfo &II,
+ SourceLocation IdLoc,
+ ImplicitTypenameContext IsImplicitTypename) {
if (SS.isInvalid())
return true;
@@ -10485,9 +10747,13 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
TypeSourceInfo *TSI = nullptr;
- QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None,
- TypenameLoc, QualifierLoc, II, IdLoc, &TSI,
- /*DeducedTSTContext=*/true);
+ QualType T =
+ CheckTypenameType((TypenameLoc.isValid() ||
+ IsImplicitTypename == ImplicitTypenameContext::Yes)
+ ? ETK_Typename
+ : ETK_None,
+ TypenameLoc, QualifierLoc, II, IdLoc, &TSI,
+ /*DeducedTSTContext=*/true);
if (T.isNull())
return true;
return CreateParsedType(T, TSI);
@@ -10533,10 +10799,9 @@ Sema::ActOnTypenameType(Scope *S,
// Construct a dependent template specialization type.
assert(DTN && "dependent template has non-dependent name?");
assert(DTN->getQualifier() == SS.getScopeRep());
- QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename,
- DTN->getQualifier(),
- DTN->getIdentifier(),
- TemplateArgs);
+ QualType T = Context.getDependentTemplateSpecializationType(
+ ETK_Typename, DTN->getQualifier(), DTN->getIdentifier(),
+ TemplateArgs.arguments());
// Create source-location information for this type.
TypeLocBuilder Builder;
@@ -10745,7 +11010,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
}
// Fall through to create a dependent typename type, from which we can recover
// better.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 9ec33e898198..9e48a2a35a34 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -45,7 +45,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -54,7 +53,9 @@
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
+#include <optional>
#include <tuple>
+#include <type_traits>
#include <utility>
namespace clang {
@@ -235,11 +236,13 @@ checkDeducedTemplateArguments(ASTContext &Context,
case TemplateArgument::Null:
llvm_unreachable("Non-deduced template arguments handled above");
- case TemplateArgument::Type:
+ case TemplateArgument::Type: {
// If two template type arguments have the same type, they're compatible.
- if (Y.getKind() == TemplateArgument::Type &&
- Context.hasSameType(X.getAsType(), Y.getAsType()))
- return X;
+ QualType TX = X.getAsType(), TY = Y.getAsType();
+ if (Y.getKind() == TemplateArgument::Type && Context.hasSameType(TX, TY))
+ return DeducedTemplateArgument(Context.getCommonSugaredType(TX, TY),
+ X.wasDeducedFromArrayBound() ||
+ Y.wasDeducedFromArrayBound());
// If one of the two arguments was deduced from an array bound, the other
// supersedes it.
@@ -248,6 +251,7 @@ checkDeducedTemplateArguments(ASTContext &Context,
// The arguments are not compatible.
return DeducedTemplateArgument();
+ }
case TemplateArgument::Integral:
// If we deduced a constant in one case and either a dependent expression or
@@ -325,7 +329,9 @@ checkDeducedTemplateArguments(ASTContext &Context,
// If we deduced a null pointer and a dependent expression, keep the
// null pointer.
if (Y.getKind() == TemplateArgument::Expression)
- return X;
+ return TemplateArgument(Context.getCommonSugaredType(
+ X.getNullPtrType(), Y.getAsExpr()->getType()),
+ true);
// If we deduced a null pointer and an integral constant, keep the
// integral constant.
@@ -334,7 +340,9 @@ checkDeducedTemplateArguments(ASTContext &Context,
// If we deduced two null pointers, they are the same.
if (Y.getKind() == TemplateArgument::NullPtr)
- return X;
+ return TemplateArgument(
+ Context.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()),
+ true);
// All other combinations are incompatible.
return DeducedTemplateArgument();
@@ -555,6 +563,12 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
// FIXME: Try to preserve type sugar here, which is hard
// because of the unresolved template arguments.
const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>();
+ TemplateName TNP = TP->getTemplateName();
+
+ // If the parameter is an alias template, there is nothing to deduce.
+ if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias())
+ return Sema::TDK_Success;
+
ArrayRef<TemplateArgument> PResolved = TP->template_arguments();
QualType UA = A;
@@ -566,10 +580,15 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams,
// FIXME: Should not lose sugar here.
if (const auto *SA =
dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) {
+ TemplateName TNA = SA->getTemplateName();
+
+ // If the argument is an alias template, there is nothing to deduce.
+ if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias())
+ return Sema::TDK_Success;
+
// Perform template argument deduction for the template name.
if (auto Result =
- DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(),
- SA->getTemplateName(), Info, Deduced))
+ DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced))
return Result;
// Perform template argument deduction on each template
// argument. Ignore any missing/extra arguments, since they could be
@@ -700,7 +719,7 @@ private:
// FIXME: What if we encounter multiple packs with different numbers of
// pre-expanded expansions? (This should already have been diagnosed
// during substitution.)
- if (Optional<unsigned> ExpandedPackExpansions =
+ if (std::optional<unsigned> ExpandedPackExpansions =
getExpandedPackSize(TemplateParams->getParam(Index)))
FixedNumExpansions = ExpandedPackExpansions;
@@ -737,8 +756,11 @@ private:
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- unsigned Depth, Index;
- std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+ UnexpandedParameterPack U = Unexpanded[I];
+ if (U.first.is<const SubstTemplateTypeParmPackType *>() ||
+ U.first.is<const SubstNonTypeTemplateParmPackExpr *>())
+ continue;
+ auto [Depth, Index] = getDepthAndIndex(U);
if (Depth == Info.getDeducedDepth())
AddPack(Index);
}
@@ -894,7 +916,7 @@ public:
new (S.Context) TemplateArgument[Pack.New.size()];
std::copy(Pack.New.begin(), Pack.New.end(), ArgumentPack);
NewPack = DeducedTemplateArgument(
- TemplateArgument(llvm::makeArrayRef(ArgumentPack, Pack.New.size())),
+ TemplateArgument(llvm::ArrayRef(ArgumentPack, Pack.New.size())),
// FIXME: This is wrong, it's possible that some pack elements are
// deduced from an array bound and others are not:
// template<typename ...T, T ...V> void g(const T (&...p)[V]);
@@ -939,7 +961,7 @@ public:
// If we have a pre-expanded pack and we didn't deduce enough elements
// for it, fail deduction.
- if (Optional<unsigned> Expansions = getExpandedPackSize(Param)) {
+ if (std::optional<unsigned> Expansions = getExpandedPackSize(Param)) {
if (*Expansions != PackElements) {
Info.Param = makeTemplateParameter(Param);
Info.FirstArg = Result;
@@ -961,7 +983,7 @@ private:
unsigned PackElements = 0;
bool IsPartiallyExpanded = false;
/// The number of expansions, if we have a fully-expanded pack in this scope.
- Optional<unsigned> FixedNumExpansions;
+ std::optional<unsigned> FixedNumExpansions;
SmallVector<DeducedPack, 2> Packs;
};
@@ -1086,7 +1108,7 @@ DeduceTemplateArguments(Sema &S,
// If the parameter type contains an explicitly-specified pack that we
// could not expand, skip the number of parameters notionally created
// by the expansion.
- Optional<unsigned> NumExpansions = Expansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions = Expansion->getNumExpansions();
if (NumExpansions && !PackScope.isPartiallyExpanded()) {
for (unsigned I = 0; I != *NumExpansions && ArgIdx < NumArgs;
++I, ++ArgIdx)
@@ -1100,6 +1122,16 @@ DeduceTemplateArguments(Sema &S,
return Result;
}
+ // DR692, DR1395
+ // C++0x [temp.deduct.type]p10:
+ // If the parameter-declaration corresponding to P_i ...
+ // During partial ordering, if Ai was originally a function parameter pack:
+ // - if P does not contain a function parameter type corresponding to Ai then
+ // Ai is ignored;
+ if (PartialOrdering && ArgIdx + 1 == NumArgs &&
+ isa<PackExpansionType>(Args[ArgIdx]))
+ return Sema::TDK_Success;
+
// Make sure we don't have any extra arguments.
if (ArgIdx < NumArgs)
return Sema::TDK_MiscellaneousDeductionFailure;
@@ -1587,7 +1619,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// FIXME: Implement deduction in dependent case.
if (P->isDependentType())
return Sema::TDK_Success;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::Builtin:
case Type::VariableArray:
case Type::Vector:
@@ -1755,7 +1787,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (auto Result = DeduceTemplateArguments(
S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(),
FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced,
- TDF & TDF_TopLevelParameterTypeList))
+ TDF & TDF_TopLevelParameterTypeList, PartialOrdering))
return Result;
if (TDF & TDF_AllowCompatibleFunctionType)
@@ -1775,7 +1807,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
switch (FPA->canThrow()) {
case CT_Cannot:
Noexcept = 1;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CT_Can:
// We give E in noexcept(E) the "deduced from array bound" treatment.
@@ -2049,7 +2081,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
const auto *ACM = dyn_cast<ConstantMatrixType>(A);
const auto *ADM = dyn_cast<DependentSizedMatrixType>(A);
if (!ParamExpr->isValueDependent()) {
- Optional<llvm::APSInt> ParamConst =
+ std::optional<llvm::APSInt> ParamConst =
ParamExpr->getIntegerConstantExpr(S.Context);
if (!ParamConst)
return Sema::TDK_NonDeducedMismatch;
@@ -2061,7 +2093,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
}
Expr *ArgExpr = (ADM->*GetArgDimensionExpr)();
- if (Optional<llvm::APSInt> ArgConst =
+ if (std::optional<llvm::APSInt> ArgConst =
ArgExpr->getIntegerConstantExpr(S.Context))
if (*ArgConst == *ParamConst)
return Sema::TDK_Success;
@@ -2422,6 +2454,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
static bool isSameTemplateArg(ASTContext &Context,
TemplateArgument X,
const TemplateArgument &Y,
+ bool PartialOrdering,
bool PackExpansionMatchesPack = false) {
// If we're checking deduced arguments (X) against original arguments (Y),
// we will have flattened packs to non-expansions in X.
@@ -2462,18 +2495,33 @@ static bool isSameTemplateArg(ASTContext &Context,
return XID == YID;
}
- case TemplateArgument::Pack:
- if (X.pack_size() != Y.pack_size())
- return false;
+ case TemplateArgument::Pack: {
+ unsigned PackIterationSize = X.pack_size();
+ if (X.pack_size() != Y.pack_size()) {
+ if (!PartialOrdering)
+ return false;
- for (TemplateArgument::pack_iterator XP = X.pack_begin(),
- XPEnd = X.pack_end(),
- YP = Y.pack_begin();
- XP != XPEnd; ++XP, ++YP)
- if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack))
+ // C++0x [temp.deduct.type]p9:
+ // During partial ordering, if Ai was originally a pack expansion:
+ // - if P does not contain a template argument corresponding to Ai
+ // then Ai is ignored;
+ bool XHasMoreArg = X.pack_size() > Y.pack_size();
+ if (!(XHasMoreArg && X.pack_elements().back().isPackExpansion()) &&
+ !(!XHasMoreArg && Y.pack_elements().back().isPackExpansion()))
return false;
+ if (XHasMoreArg)
+ PackIterationSize = Y.pack_size();
+ }
+
+ ArrayRef<TemplateArgument> XP = X.pack_elements();
+ ArrayRef<TemplateArgument> YP = Y.pack_elements();
+ for (unsigned i = 0; i < PackIterationSize; ++i)
+ if (!isSameTemplateArg(Context, XP[i], YP[i], PartialOrdering,
+ PackExpansionMatchesPack))
+ return false;
return true;
+ }
}
llvm_unreachable("Invalid TemplateArgument Kind!");
@@ -2563,13 +2611,11 @@ Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm,
/// Convert the given deduced template argument and add it to the set of
/// fully-converted template arguments.
-static bool
-ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
- DeducedTemplateArgument Arg,
- NamedDecl *Template,
- TemplateDeductionInfo &Info,
- bool IsDeduced,
- SmallVectorImpl<TemplateArgument> &Output) {
+static bool ConvertDeducedTemplateArgument(
+ Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template,
+ TemplateDeductionInfo &Info, bool IsDeduced,
+ SmallVectorImpl<TemplateArgument> &SugaredOutput,
+ SmallVectorImpl<TemplateArgument> &CanonicalOutput) {
auto ConvertArg = [&](DeducedTemplateArgument Arg,
unsigned ArgumentPackIndex) {
// Convert the deduced template argument into a template
@@ -2581,7 +2627,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
// Check the template argument, converting it as necessary.
return S.CheckTemplateArgument(
Param, ArgLoc, Template, Template->getLocation(),
- Template->getSourceRange().getEnd(), ArgumentPackIndex, Output,
+ Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput,
+ CanonicalOutput,
IsDeduced
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
: Sema::CTAK_Deduced)
@@ -2591,7 +2638,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
if (Arg.getKind() == TemplateArgument::Pack) {
// This is a template argument pack, so check each of its arguments against
// the template parameter.
- SmallVector<TemplateArgument, 2> PackedArgsBuilder;
+ SmallVector<TemplateArgument, 2> SugaredPackedArgsBuilder,
+ CanonicalPackedArgsBuilder;
for (const auto &P : Arg.pack_elements()) {
// When converting the deduced template argument, append it to the
// general output list. We need to do this so that the template argument
@@ -2610,23 +2658,24 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
<< Arg << Param;
return true;
}
- if (ConvertArg(InnerArg, PackedArgsBuilder.size()))
+ if (ConvertArg(InnerArg, SugaredPackedArgsBuilder.size()))
return true;
// Move the converted template argument into our argument pack.
- PackedArgsBuilder.push_back(Output.pop_back_val());
+ SugaredPackedArgsBuilder.push_back(SugaredOutput.pop_back_val());
+ CanonicalPackedArgsBuilder.push_back(CanonicalOutput.pop_back_val());
}
// If the pack is empty, we still need to substitute into the parameter
// itself, in case that substitution fails.
- if (PackedArgsBuilder.empty()) {
+ if (SugaredPackedArgsBuilder.empty()) {
LocalInstantiationScope Scope(S);
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output);
- MultiLevelTemplateArgumentList Args(TemplateArgs);
+ MultiLevelTemplateArgumentList Args(Template, SugaredOutput,
+ /*Final=*/true);
if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
- NTTP, Output,
+ NTTP, SugaredOutput,
Template->getSourceRange());
if (Inst.isInvalid() ||
S.SubstType(NTTP->getType(), Args, NTTP->getLocation(),
@@ -2634,7 +2683,7 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
return true;
} else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) {
Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
- TTP, Output,
+ TTP, SugaredOutput,
Template->getSourceRange());
if (Inst.isInvalid() || !S.SubstDecl(TTP, S.CurContext, Args))
return true;
@@ -2643,8 +2692,10 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
}
// Create the resulting argument pack.
- Output.push_back(
- TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder));
+ SugaredOutput.push_back(
+ TemplateArgument::CreatePackCopy(S.Context, SugaredPackedArgsBuilder));
+ CanonicalOutput.push_back(TemplateArgument::CreatePackCopy(
+ S.Context, CanonicalPackedArgsBuilder));
return false;
}
@@ -2654,11 +2705,13 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
// FIXME: This should not be a template, but
// ClassTemplatePartialSpecializationDecl sadly does not derive from
// TemplateDecl.
-template<typename TemplateDeclT>
+template <typename TemplateDeclT>
static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
Sema &S, TemplateDeclT *Template, bool IsDeduced,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- TemplateDeductionInfo &Info, SmallVectorImpl<TemplateArgument> &Builder,
+ TemplateDeductionInfo &Info,
+ SmallVectorImpl<TemplateArgument> &SugaredBuilder,
+ SmallVectorImpl<TemplateArgument> &CanonicalBuilder,
LocalInstantiationScope *CurrentInstantiationScope = nullptr,
unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) {
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
@@ -2692,7 +2745,9 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
// We have already fully type-checked and converted this
// argument, because it was explicitly-specified. Just record the
// presence of this argument.
- Builder.push_back(Deduced[I]);
+ SugaredBuilder.push_back(Deduced[I]);
+ CanonicalBuilder.push_back(
+ S.Context.getCanonicalTemplateArgument(Deduced[I]));
continue;
}
}
@@ -2700,10 +2755,13 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
// We may have deduced this argument, so it still needs to be
// checked and converted.
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info,
- IsDeduced, Builder)) {
+ IsDeduced, SugaredBuilder,
+ CanonicalBuilder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
+ Info.reset(
+ TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder),
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder));
return Sema::TDK_SubstitutionFailure;
}
@@ -2734,15 +2792,16 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
S.getLangOpts().CPlusPlus17);
DefArg = S.SubstDefaultTemplateArgumentIfAvailable(
- TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder,
- HasDefaultArg);
+ TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param,
+ SugaredBuilder, CanonicalBuilder, HasDefaultArg);
}
// If there was no default argument, deduction is incomplete.
if (DefArg.getArgument().isNull()) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder),
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder));
if (PartialOverloading) break;
return HasDefaultArg ? Sema::TDK_SubstitutionFailure
@@ -2750,13 +2809,14 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
}
// Check whether we can actually use the default argument.
- if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(),
- TD->getSourceRange().getEnd(), 0, Builder,
- Sema::CTAK_Specified)) {
+ if (S.CheckTemplateArgument(
+ Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(),
+ 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder),
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder));
return Sema::TDK_SubstitutionFailure;
}
@@ -2783,19 +2843,54 @@ template<>
struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
static constexpr bool value = true;
};
+template <typename TemplateDeclT>
+static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
+ return false;
+}
+template <>
+bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>(
+ VarTemplatePartialSpecializationDecl *Spec) {
+ return !Spec->isClassScopeExplicitSpecialization();
+}
+template <>
+bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
+ ClassTemplatePartialSpecializationDecl *Spec) {
+ return !Spec->isClassScopeExplicitSpecialization();
+}
-template<typename TemplateDeclT>
+template <typename TemplateDeclT>
static Sema::TemplateDeductionResult
-CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
- ArrayRef<TemplateArgument> DeducedArgs,
- TemplateDeductionInfo& Info) {
+CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
+ ArrayRef<TemplateArgument> SugaredDeducedArgs,
+ ArrayRef<TemplateArgument> CanonicalDeducedArgs,
+ TemplateDeductionInfo &Info) {
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
Template->getAssociatedConstraints(AssociatedConstraints);
- if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints,
- DeducedArgs, Info.getLocation(),
+
+ bool NeedsReplacement = DeducedArgsNeedReplacement(Template);
+ TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack,
+ CanonicalDeducedArgs};
+
+ MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
+ Template, /*Final=*/false,
+ /*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL,
+ /*RelativeToPrimary=*/true, /*Pattern=*/
+ nullptr, /*ForConstraintInstantiation=*/true);
+
+ // getTemplateInstantiationArgs picks up the non-deduced version of the
+ // template args when this is a variable template partial specialization and
+ // not class-scope explicit specialization, so replace with Deduced Args
+ // instead of adding to inner-most.
+ if (NeedsReplacement)
+ MLTAL.replaceInnermostTemplateArguments(CanonicalDeducedArgs);
+
+ if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
+ Info.getLocation(),
Info.AssociatedConstraintsSatisfaction) ||
!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
+ Info.reset(
+ TemplateArgumentList::CreateCopy(S.Context, SugaredDeducedArgs),
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalDeducedArgs));
return Sema::TDK_ConstraintsNotSatisfied;
}
return Sema::TDK_Success;
@@ -2820,16 +2915,19 @@ FinishTemplateArgumentDeduction(
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
- S, Partial, IsPartialOrdering, Deduced, Info, Builder))
+ S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder,
+ CanonicalBuilder))
return Result;
// Form the template argument list from the deduced template arguments.
- TemplateArgumentList *DeducedArgumentList
- = TemplateArgumentList::CreateCopy(S.Context, Builder);
+ TemplateArgumentList *SugaredDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder);
+ TemplateArgumentList *CanonicalDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder);
- Info.reset(DeducedArgumentList);
+ Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList);
// Substitute the deduced template arguments into the template
// arguments of the class template partial specialization, and
@@ -2844,9 +2942,11 @@ FinishTemplateArgumentDeduction(
TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc,
PartialTemplArgInfo->RAngleLoc);
- if (S.SubstTemplateArguments(
- PartialTemplArgInfo->arguments(),
- MultiLevelTemplateArgumentList(*DeducedArgumentList), InstArgs)) {
+ if (S.SubstTemplateArguments(PartialTemplArgInfo->arguments(),
+ MultiLevelTemplateArgumentList(Partial,
+ SugaredBuilder,
+ /*Final=*/true),
+ InstArgs)) {
unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx;
if (ParamIdx >= Partial->getTemplateParameters()->size())
ParamIdx = Partial->getTemplateParameters()->size() - 1;
@@ -2859,18 +2959,20 @@ FinishTemplateArgumentDeduction(
}
bool ConstraintsNotSatisfied;
- SmallVector<TemplateArgument, 4> ConvertedInstArgs;
- if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs,
- false, ConvertedInstArgs,
- /*UpdateArgsWithConversions=*/true,
- &ConstraintsNotSatisfied))
- return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied :
- Sema::TDK_SubstitutionFailure;
+ SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs,
+ CanonicalConvertedInstArgs;
+ if (S.CheckTemplateArgumentList(
+ Template, Partial->getLocation(), InstArgs, false,
+ SugaredConvertedInstArgs, CanonicalConvertedInstArgs,
+ /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied))
+ return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied
+ : Sema::TDK_SubstitutionFailure;
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
- TemplateArgument InstArg = ConvertedInstArgs.data()[I];
- if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) {
+ TemplateArgument InstArg = SugaredConvertedInstArgs.data()[I];
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg,
+ IsPartialOrdering)) {
Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
@@ -2881,7 +2983,8 @@ FinishTemplateArgumentDeduction(
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
- if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info))
+ if (auto Result = CheckDeducedArgumentConstraints(S, Partial, SugaredBuilder,
+ CanonicalBuilder, Info))
return Result;
return Sema::TDK_Success;
@@ -2905,17 +3008,20 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
- S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder))
+ S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info,
+ SugaredBuilder, CanonicalBuilder,
+ /*CurrentInstantiationScope=*/nullptr,
+ /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false))
return Result;
// Check that we produced the correct argument list.
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
- TemplateArgument InstArg = Builder[I];
- if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg,
- /*PackExpansionMatchesPack*/true)) {
+ TemplateArgument InstArg = CanonicalBuilder[I];
+ if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, PartialOrdering,
+ /*PackExpansionMatchesPack=*/true)) {
Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
Info.FirstArg = TemplateArgs[I];
Info.SecondArg = InstArg;
@@ -2926,8 +3032,8 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
- if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder,
- Info))
+ if (auto Result = CheckDeducedArgumentConstraints(S, Template, SugaredBuilder,
+ CanonicalBuilder, Info))
return Result;
return Sema::TDK_Success;
@@ -3079,14 +3185,12 @@ static bool isSimpleTemplateIdType(QualType T) {
///
/// \returns TDK_Success if substitution was successful, or some failure
/// condition.
-Sema::TemplateDeductionResult
-Sema::SubstituteExplicitTemplateArguments(
- FunctionTemplateDecl *FunctionTemplate,
- TemplateArgumentListInfo &ExplicitTemplateArgs,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- SmallVectorImpl<QualType> &ParamTypes,
- QualType *FunctionType,
- TemplateDeductionInfo &Info) {
+Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ TemplateArgumentListInfo &ExplicitTemplateArgs,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType,
+ TemplateDeductionInfo &Info) {
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
@@ -3094,7 +3198,7 @@ Sema::SubstituteExplicitTemplateArguments(
if (ExplicitTemplateArgs.size() == 0) {
// No arguments to substitute; just copy over the parameter types and
// fill in the function type.
- for (auto P : Function->parameters())
+ for (auto *P : Function->parameters())
ParamTypes.push_back(P->getType());
if (FunctionType)
@@ -3112,7 +3216,7 @@ Sema::SubstituteExplicitTemplateArguments(
// declaration order of their corresponding template-parameters. The
// template argument list shall not specify more template-arguments than
// there are corresponding template-parameters.
- SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
// Enter a new template instantiation context where we check the
// explicitly-specified template arguments against this function template,
@@ -3125,9 +3229,11 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_InstantiationDepth;
if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(),
- ExplicitTemplateArgs, true, Builder, false) ||
+ ExplicitTemplateArgs, true, SugaredBuilder,
+ CanonicalBuilder,
+ /*UpdateArgsWithConversions=*/false) ||
Trap.hasErrorOccurred()) {
- unsigned Index = Builder.size();
+ unsigned Index = SugaredBuilder.size();
if (Index >= TemplateParams->size())
return TDK_SubstitutionFailure;
Info.Param = makeTemplateParameter(TemplateParams->getParam(Index));
@@ -3136,9 +3242,12 @@ Sema::SubstituteExplicitTemplateArguments(
// Form the template argument list from the explicitly-specified
// template arguments.
- TemplateArgumentList *ExplicitArgumentList
- = TemplateArgumentList::CreateCopy(Context, Builder);
- Info.setExplicitArgs(ExplicitArgumentList);
+ TemplateArgumentList *SugaredExplicitArgumentList =
+ TemplateArgumentList::CreateCopy(Context, SugaredBuilder);
+ TemplateArgumentList *CanonicalExplicitArgumentList =
+ TemplateArgumentList::CreateCopy(Context, CanonicalBuilder);
+ Info.setExplicitArgs(SugaredExplicitArgumentList,
+ CanonicalExplicitArgumentList);
// Template argument deduction and the final substitution should be
// done in the context of the templated declaration. Explicit
@@ -3151,15 +3260,15 @@ Sema::SubstituteExplicitTemplateArguments(
// the explicit template arguments. They'll be used as part of deduction
// for this template parameter pack.
unsigned PartiallySubstitutedPackIndex = -1u;
- if (!Builder.empty()) {
- const TemplateArgument &Arg = Builder.back();
+ if (!CanonicalBuilder.empty()) {
+ const TemplateArgument &Arg = CanonicalBuilder.back();
if (Arg.getKind() == TemplateArgument::Pack) {
- auto *Param = TemplateParams->getParam(Builder.size() - 1);
+ auto *Param = TemplateParams->getParam(CanonicalBuilder.size() - 1);
// If this is a fully-saturated fixed-size pack, it should be
// fully-substituted, not partially-substituted.
- Optional<unsigned> Expansions = getExpandedPackSize(Param);
+ std::optional<unsigned> Expansions = getExpandedPackSize(Param);
if (!Expansions || Arg.pack_size() < *Expansions) {
- PartiallySubstitutedPackIndex = Builder.size() - 1;
+ PartiallySubstitutedPackIndex = CanonicalBuilder.size() - 1;
CurrentInstantiationScope->SetPartiallySubstitutedPack(
Param, Arg.pack_begin(), Arg.pack_size());
}
@@ -3175,15 +3284,18 @@ Sema::SubstituteExplicitTemplateArguments(
ExtParameterInfoBuilder ExtParamInfos;
+ MultiLevelTemplateArgumentList MLTAL(FunctionTemplate,
+ SugaredExplicitArgumentList->asArray(),
+ /*Final=*/true);
+
// Instantiate the types of each of the function parameters given the
// explicitly-specified template arguments. If the function has a trailing
// return type, substitute it after the arguments to ensure we substitute
// in lexical order.
if (Proto->hasTrailingReturn()) {
if (SubstParmTypes(Function->getLocation(), Function->parameters(),
- Proto->getExtParameterInfosOrNull(),
- MultiLevelTemplateArgumentList(*ExplicitArgumentList),
- ParamTypes, /*params*/ nullptr, ExtParamInfos))
+ Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes,
+ /*params=*/nullptr, ExtParamInfos))
return TDK_SubstitutionFailure;
}
@@ -3207,8 +3319,7 @@ Sema::SubstituteExplicitTemplateArguments(
getLangOpts().CPlusPlus11);
ResultType =
- SubstType(Proto->getReturnType(),
- MultiLevelTemplateArgumentList(*ExplicitArgumentList),
+ SubstType(Proto->getReturnType(), MLTAL,
Function->getTypeSpecStartLoc(), Function->getDeclName());
if (ResultType.isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
@@ -3225,9 +3336,8 @@ Sema::SubstituteExplicitTemplateArguments(
// explicitly-specified template arguments if we didn't do so earlier.
if (!Proto->hasTrailingReturn() &&
SubstParmTypes(Function->getLocation(), Function->parameters(),
- Proto->getExtParameterInfosOrNull(),
- MultiLevelTemplateArgumentList(*ExplicitArgumentList),
- ParamTypes, /*params*/ nullptr, ExtParamInfos))
+ Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes,
+ /*params*/ nullptr, ExtParamInfos))
return TDK_SubstitutionFailure;
if (FunctionType) {
@@ -3239,9 +3349,8 @@ Sema::SubstituteExplicitTemplateArguments(
// specification.
SmallVector<QualType, 4> ExceptionStorage;
if (getLangOpts().CPlusPlus17 &&
- SubstExceptionSpec(
- Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
- MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
+ SubstExceptionSpec(Function->getLocation(), EPI.ExceptionSpec,
+ ExceptionStorage, MLTAL))
return TDK_SubstitutionFailure;
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
@@ -3263,8 +3372,8 @@ Sema::SubstituteExplicitTemplateArguments(
// parameter pack, however, will be set to NULL since the deduction
// mechanism handles the partially-substituted argument pack directly.
Deduced.reserve(TemplateParams->size());
- for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) {
- const TemplateArgument &Arg = ExplicitArgumentList->get(I);
+ for (unsigned I = 0, N = SugaredExplicitArgumentList->size(); I != N; ++I) {
+ const TemplateArgument &Arg = SugaredExplicitArgumentList->get(I);
if (I == PartiallySubstitutedPackIndex)
Deduced.push_back(DeducedTemplateArgument());
else
@@ -3452,11 +3561,11 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
- SmallVector<TemplateArgument, 4> Builder;
+ SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder;
if (auto Result = ConvertDeducedTemplateArguments(
- *this, FunctionTemplate, /*IsDeduced*/true, Deduced, Info, Builder,
- CurrentInstantiationScope, NumExplicitlySpecified,
- PartialOverloading))
+ *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info,
+ SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope,
+ NumExplicitlySpecified, PartialOverloading))
return Result;
// C++ [temp.deduct.call]p10: [DR1391]
@@ -3472,16 +3581,20 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
return TDK_NonDependentConversionFailure;
// Form the template argument list from the deduced template arguments.
- TemplateArgumentList *DeducedArgumentList
- = TemplateArgumentList::CreateCopy(Context, Builder);
- Info.reset(DeducedArgumentList);
+ TemplateArgumentList *SugaredDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(Context, SugaredBuilder);
+ TemplateArgumentList *CanonicalDeducedArgumentList =
+ TemplateArgumentList::CreateCopy(Context, CanonicalBuilder);
+ Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList);
// Substitute the deduced template arguments into the function template
// declaration to produce the function template specialization.
DeclContext *Owner = FunctionTemplate->getDeclContext();
if (FunctionTemplate->getFriendObjectKind())
Owner = FunctionTemplate->getLexicalDeclContext();
- MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList);
+ MultiLevelTemplateArgumentList SubstArgs(
+ FunctionTemplate, CanonicalDeducedArgumentList->asArray(),
+ /*Final=*/false);
Specialization = cast_or_null<FunctionDecl>(
SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs));
if (!Specialization || Specialization->isInvalidDecl())
@@ -3492,9 +3605,10 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// If the template argument list is owned by the function template
// specialization, release it.
- if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList &&
+ if (Specialization->getTemplateSpecializationArgs() ==
+ CanonicalDeducedArgumentList &&
!Trap.hasErrorOccurred())
- Info.take();
+ Info.takeCanonical();
// There may have been an error that did not prevent us from constructing a
// declaration. Mark the declaration invalid and return with a substitution
@@ -3513,13 +3627,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// ([temp.constr.constr]). If the constraints are not satisfied, type
// deduction fails.
if (!PartialOverloading ||
- (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) {
- if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(),
- Specialization, Builder, Info.AssociatedConstraintsSatisfaction))
+ (CanonicalBuilder.size() ==
+ FunctionTemplate->getTemplateParameters()->size())) {
+ if (CheckInstantiatedFunctionTemplateConstraints(
+ Info.getLocation(), Specialization, CanonicalBuilder,
+ Info.AssociatedConstraintsSatisfaction))
return TDK_MiscellaneousDeductionFailure;
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
- Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
+ Info.reset(Info.takeSugared(),
+ TemplateArgumentList::CreateCopy(Context, CanonicalBuilder));
return TDK_ConstraintsNotSatisfied;
}
}
@@ -3765,13 +3882,11 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(
// - If A is an array type, the pointer type produced by the
// array-to-pointer standard conversion (4.2) is used in place of
// A for type deduction; otherwise,
- if (ArgType->isArrayType())
- ArgType = S.Context.getArrayDecayedType(ArgType);
// - If A is a function type, the pointer type produced by the
// function-to-pointer standard conversion (4.3) is used in place
// of A for type deduction; otherwise,
- else if (ArgType->isFunctionType())
- ArgType = S.Context.getPointerType(ArgType);
+ if (ArgType->canDecayToPointerType())
+ ArgType = S.Context.getDecayedType(ArgType);
else {
// - If A is a cv-qualified type, the top level cv-qualifiers of A's
// type are ignored for type deduction.
@@ -4068,7 +4183,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// If the parameter type contains an explicitly-specified pack that we
// could not expand, skip the number of parameters notionally created
// by the expansion.
- Optional<unsigned> NumExpansions = ParamExpansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions =
+ ParamExpansion->getNumExpansions();
if (NumExpansions && !PackScope.isPartiallyExpanded()) {
for (unsigned I = 0; I != *NumExpansions && ArgIdx < Args.size();
++I, ++ArgIdx) {
@@ -4521,42 +4637,9 @@ namespace {
} // namespace
-Sema::DeduceAutoResult
-Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth,
- bool IgnoreConstraints) {
- return DeduceAutoType(Type->getTypeLoc(), Init, Result,
- DependentDeductionDepth, IgnoreConstraints);
-}
-
-/// Attempt to produce an informative diagostic explaining why auto deduction
-/// failed.
-/// \return \c true if diagnosed, \c false if not.
-static bool diagnoseAutoDeductionFailure(Sema &S,
- Sema::TemplateDeductionResult TDK,
- TemplateDeductionInfo &Info,
- ArrayRef<SourceRange> Ranges) {
- switch (TDK) {
- case Sema::TDK_Inconsistent: {
- // Inconsistent deduction means we were deducing from an initializer list.
- auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction);
- D << Info.FirstArg << Info.SecondArg;
- for (auto R : Ranges)
- D << R;
- return true;
- }
-
- // FIXME: Are there other cases for which a custom diagnostic is more useful
- // than the basic "types don't match" diagnostic?
-
- default:
- return false;
- }
-}
-
-static Sema::DeduceAutoResult
-CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
- AutoTypeLoc TypeLoc, QualType Deduced) {
+static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
+ AutoTypeLoc TypeLoc,
+ QualType Deduced) {
ConstraintSatisfaction Satisfaction;
ConceptDecl *Concept = Type.getTypeConstraintConcept();
TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
@@ -4568,14 +4651,17 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I)
TemplateArgs.addArgument(TypeLoc.getArgLoc(I));
- llvm::SmallVector<TemplateArgument, 4> Converted;
+ llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
- /*PartialTemplateArgs=*/false, Converted))
- return Sema::DAR_FailedAlreadyDiagnosed;
+ /*PartialTemplateArgs=*/false,
+ SugaredConverted, CanonicalConverted))
+ return true;
+ MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted,
+ /*Final=*/false);
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
- Converted, TypeLoc.getLocalSourceRange(),
+ MLTAL, TypeLoc.getLocalSourceRange(),
Satisfaction))
- return Sema::DAR_FailedAlreadyDiagnosed;
+ return true;
if (!Satisfaction.IsSatisfied) {
std::string Buf;
llvm::raw_string_ostream OS(Buf);
@@ -4589,11 +4675,11 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
OS.flush();
S.Diag(TypeLoc.getConceptNameLoc(),
diag::err_placeholder_constraints_not_satisfied)
- << Deduced << Buf << TypeLoc.getLocalSourceRange();
+ << Deduced << Buf << TypeLoc.getLocalSourceRange();
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
- return Sema::DAR_FailedAlreadyDiagnosed;
+ return true;
}
- return Sema::DAR_Succeeded;
+ return false;
}
/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
@@ -4606,184 +4692,165 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
/// \param Init the initializer for the variable whose type is to be deduced.
/// \param Result if type deduction was successful, this will be set to the
/// deduced type.
-/// \param DependentDeductionDepth Set if we should permit deduction in
+/// \param Info the argument will be updated to provide additional information
+/// about template argument deduction.
+/// \param DependentDeduction Set if we should permit deduction in
/// dependent cases. This is necessary for template partial ordering with
-/// 'auto' template parameters. The value specified is the template
-/// parameter depth at which we should perform 'auto' deduction.
+/// 'auto' template parameters. The template parameter depth to be used
+/// should be specified in the 'Info' parameter.
/// \param IgnoreConstraints Set if we should not fail if the deduced type does
/// not satisfy the type-constraint in the auto type.
-Sema::DeduceAutoResult
-Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth,
- bool IgnoreConstraints) {
+Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init,
+ QualType &Result,
+ TemplateDeductionInfo &Info,
+ bool DependentDeduction,
+ bool IgnoreConstraints) {
+ assert(DependentDeduction || Info.getDeducedDepth() == 0);
if (Init->containsErrors())
- return DAR_FailedAlreadyDiagnosed;
- if (Init->getType()->isNonOverloadPlaceholderType()) {
+ return TDK_AlreadyDiagnosed;
+
+ const AutoType *AT = Type.getType()->getContainedAutoType();
+ assert(AT);
+
+ if (Init->getType()->isNonOverloadPlaceholderType() || AT->isDecltypeAuto()) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
- return DAR_FailedAlreadyDiagnosed;
+ return TDK_AlreadyDiagnosed;
Init = NonPlaceholder.get();
}
DependentAuto DependentResult = {
/*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()};
- if (!DependentDeductionDepth &&
+ if (!DependentDeduction &&
(Type.getType()->isDependentType() || Init->isTypeDependent() ||
Init->containsUnexpandedParameterPack())) {
Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
- return DAR_Succeeded;
+ return TDK_Success;
}
- // Find the depth of template parameter to synthesize.
- unsigned Depth = DependentDeductionDepth.value_or(0);
-
- // If this is a 'decltype(auto)' specifier, do the decltype dance.
- // Since 'decltype(auto)' can only occur at the top of the type, we
- // don't need to go digging for it.
- if (const AutoType *AT = Type.getType()->getAs<AutoType>()) {
- if (AT->isDecltypeAuto()) {
- if (isa<InitListExpr>(Init)) {
- Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
- return DAR_FailedAlreadyDiagnosed;
- }
-
- ExprResult ER = CheckPlaceholderExpr(Init);
- if (ER.isInvalid())
- return DAR_FailedAlreadyDiagnosed;
- QualType Deduced = getDecltypeForExpr(ER.get());
- assert(!Deduced.isNull());
- if (AT->isConstrained() && !IgnoreConstraints) {
- auto ConstraintsResult =
- CheckDeducedPlaceholderConstraints(*this, *AT,
- Type.getContainedAutoTypeLoc(),
- Deduced);
- if (ConstraintsResult != DAR_Succeeded)
- return ConstraintsResult;
- }
- Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
- if (Result.isNull())
- return DAR_FailedAlreadyDiagnosed;
- return DAR_Succeeded;
- } else if (!getLangOpts().CPlusPlus) {
- if (isa<InitListExpr>(Init)) {
- Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
- return DAR_FailedAlreadyDiagnosed;
- }
- }
+ auto *InitList = dyn_cast<InitListExpr>(Init);
+ if (!getLangOpts().CPlusPlus && InitList) {
+ Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c);
+ return TDK_AlreadyDiagnosed;
}
- SourceLocation Loc = Init->getExprLoc();
-
- LocalInstantiationScope InstScope(*this);
-
- // Build template<class TemplParam> void Func(FuncParam);
- TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
- Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false,
- false);
- QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
- NamedDecl *TemplParamPtr = TemplParam;
- FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
- Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
-
- QualType FuncParam =
- SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true)
- .Apply(Type);
- assert(!FuncParam.isNull() &&
- "substituting template parameter for 'auto' failed");
-
// Deduce type of TemplParam in Func(Init)
SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);
- TemplateDeductionInfo Info(Loc, Depth);
-
// If deduction failed, don't diagnose if the initializer is dependent; it
// might acquire a matching type in the instantiation.
- auto DeductionFailed = [&](TemplateDeductionResult TDK,
- ArrayRef<SourceRange> Ranges) -> DeduceAutoResult {
+ auto DeductionFailed = [&](TemplateDeductionResult TDK) {
if (Init->isTypeDependent()) {
Result =
SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
assert(!Result.isNull() && "substituting DependentTy can't fail");
- return DAR_Succeeded;
+ return TDK_Success;
}
- if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges))
- return DAR_FailedAlreadyDiagnosed;
- return DAR_Failed;
+ return TDK;
};
SmallVector<OriginalCallArg, 4> OriginalCallArgs;
- InitListExpr *InitList = dyn_cast<InitListExpr>(Init);
- if (InitList) {
- // Notionally, we substitute std::initializer_list<T> for 'auto' and deduce
- // against that. Such deduction only succeeds if removing cv-qualifiers and
- // references results in std::initializer_list<T>.
- 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;
+ QualType DeducedType;
+ // If this is a 'decltype(auto)' specifier, do the decltype dance.
+ if (AT->isDecltypeAuto()) {
+ if (InitList) {
+ Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list);
+ return TDK_AlreadyDiagnosed;
+ }
- SourceRange DeducedFromInitRange;
- for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
- Expr *Init = InitList->getInit(i);
+ DeducedType = getDecltypeForExpr(Init);
+ assert(!DeducedType.isNull());
+ } else {
+ LocalInstantiationScope InstScope(*this);
+
+ // Build template<class TemplParam> void Func(FuncParam);
+ SourceLocation Loc = Init->getExprLoc();
+ TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create(
+ Context, nullptr, SourceLocation(), Loc, Info.getDeducedDepth(), 0,
+ nullptr, false, false, false);
+ QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
+ NamedDecl *TemplParamPtr = TemplParam;
+ FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
+ Context, Loc, Loc, TemplParamPtr, Loc, nullptr);
+
+ if (InitList) {
+ // Notionally, we substitute std::initializer_list<T> for 'auto' and
+ // deduce against that. Such deduction only succeeds if removing
+ // cv-qualifiers and references results in std::initializer_list<T>.
+ if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
+ return TDK_Invalid;
+
+ SourceRange DeducedFromInitRange;
+ for (Expr *Init : InitList->inits()) {
+ // Resolving a core issue: a braced-init-list containing any designators
+ // is a non-deduced context.
+ if (isa<DesignatedInitExpr>(Init))
+ return TDK_Invalid;
+ if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
+ *this, TemplateParamsSt.get(), 0, TemplArg, Init, Info, Deduced,
+ OriginalCallArgs, /*Decomposed=*/true,
+ /*ArgIdx=*/0, /*TDF=*/0)) {
+ if (TDK == TDK_Inconsistent) {
+ Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction)
+ << Info.FirstArg << Info.SecondArg << DeducedFromInitRange
+ << Init->getSourceRange();
+ return DeductionFailed(TDK_AlreadyDiagnosed);
+ }
+ return DeductionFailed(TDK);
+ }
+ if (DeducedFromInitRange.isInvalid() &&
+ Deduced[0].getKind() != TemplateArgument::Null)
+ DeducedFromInitRange = Init->getSourceRange();
+ }
+ } else {
+ if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
+ Diag(Loc, diag::err_auto_bitfield);
+ return TDK_AlreadyDiagnosed;
+ }
+ QualType FuncParam =
+ SubstituteDeducedTypeTransform(*this, TemplArg).Apply(Type);
+ assert(!FuncParam.isNull() &&
+ "substituting template parameter for 'auto' failed");
if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, TemplArg, Init,
- Info, Deduced, OriginalCallArgs, /*Decomposed*/ true,
- /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed(TDK, {DeducedFromInitRange,
- Init->getSourceRange()});
-
- if (DeducedFromInitRange.isInvalid() &&
- Deduced[0].getKind() != TemplateArgument::Null)
- DeducedFromInitRange = Init->getSourceRange();
- }
- } else {
- if (!getLangOpts().CPlusPlus && Init->refersToBitField()) {
- Diag(Loc, diag::err_auto_bitfield);
- return DAR_FailedAlreadyDiagnosed;
+ *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
+ OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0))
+ return DeductionFailed(TDK);
}
- if (auto TDK = DeduceTemplateArgumentsFromCallArgument(
- *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced,
- OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0))
- return DeductionFailed(TDK, {});
- }
-
- // Could be null if somehow 'auto' appears in a non-deduced context.
- if (Deduced[0].getKind() != TemplateArgument::Type)
- return DeductionFailed(TDK_Incomplete, {});
-
- QualType DeducedType = Deduced[0].getAsType();
+ // Could be null if somehow 'auto' appears in a non-deduced context.
+ if (Deduced[0].getKind() != TemplateArgument::Type)
+ return DeductionFailed(TDK_Incomplete);
+ DeducedType = Deduced[0].getAsType();
- if (InitList) {
- DeducedType = BuildStdInitializerList(DeducedType, Loc);
- if (DeducedType.isNull())
- return DAR_FailedAlreadyDiagnosed;
+ if (InitList) {
+ DeducedType = BuildStdInitializerList(DeducedType, Loc);
+ if (DeducedType.isNull())
+ return TDK_AlreadyDiagnosed;
+ }
}
- QualType MaybeAuto = Type.getType().getNonReferenceType();
- while (MaybeAuto->isPointerType())
- MaybeAuto = MaybeAuto->getPointeeType();
- if (const auto *AT = MaybeAuto->getAs<AutoType>()) {
- if (AT->isConstrained() && !IgnoreConstraints) {
- auto ConstraintsResult = CheckDeducedPlaceholderConstraints(
- *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType);
- if (ConstraintsResult != DAR_Succeeded)
- return ConstraintsResult;
+ if (!Result.isNull()) {
+ if (!Context.hasSameType(DeducedType, Result)) {
+ Info.FirstArg = Result;
+ Info.SecondArg = DeducedType;
+ return DeductionFailed(TDK_Inconsistent);
}
+ DeducedType = Context.getCommonSugaredType(Result, DeducedType);
}
+ if (AT->isConstrained() && !IgnoreConstraints &&
+ CheckDeducedPlaceholderConstraints(
+ *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType))
+ return TDK_AlreadyDiagnosed;
+
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
- return DAR_FailedAlreadyDiagnosed;
+ return TDK_AlreadyDiagnosed;
// Check that the deduced argument type is compatible with the original
// argument type per C++ [temp.deduct.call]p4.
@@ -4794,11 +4861,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (auto TDK =
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) {
Result = QualType();
- return DeductionFailed(TDK, {});
+ return DeductionFailed(TDK);
}
}
- return DAR_Succeeded;
+ return TDK_Success;
}
QualType Sema::SubstAutoType(QualType TypeWithAuto,
@@ -5102,27 +5169,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
return true;
}
-/// Determine whether this a function template whose parameter-type-list
-/// ends with a function parameter pack.
-static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
- FunctionDecl *Function = FunTmpl->getTemplatedDecl();
- unsigned NumParams = Function->getNumParams();
- if (NumParams == 0)
- return false;
-
- ParmVarDecl *Last = Function->getParamDecl(NumParams - 1);
- if (!Last->isParameterPack())
- return false;
-
- // Make sure that no previous parameter is a parameter pack.
- while (--NumParams > 0) {
- if (Function->getParamDecl(NumParams - 1)->isParameterPack())
- return false;
- }
-
- return true;
-}
-
/// Returns the more specialized function template according
/// to the rules of function template partial ordering (C++ [temp.func.order]).
///
@@ -5143,53 +5189,128 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) {
/// candidate with a reversed parameter order. In this case, the corresponding
/// P/A pairs between FT1 and FT2 are reversed.
///
-/// \param AllowOrderingByConstraints If \c is false, don't check whether one
-/// of the templates is more constrained than the other. Default is true.
-///
/// \returns the more specialized function template. If neither
/// template is more specialized, returns NULL.
FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
- unsigned NumCallArguments2, bool Reversed,
- bool AllowOrderingByConstraints) {
-
- auto JudgeByConstraints = [&]() -> FunctionTemplateDecl * {
- if (!AllowOrderingByConstraints)
- return nullptr;
- llvm::SmallVector<const Expr *, 3> AC1, AC2;
- FT1->getAssociatedConstraints(AC1);
- FT2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1))
- return nullptr;
- if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2))
- return nullptr;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return nullptr;
- return AtLeastAsConstrained1 ? FT1 : FT2;
- };
+ unsigned NumCallArguments2, bool Reversed) {
bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC,
NumCallArguments1, Reversed);
bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC,
NumCallArguments2, Reversed);
+ // C++ [temp.deduct.partial]p10:
+ // F is more specialized than G if F is at least as specialized as G and G
+ // is not at least as specialized as F.
if (Better1 != Better2) // We have a clear winner
return Better1 ? FT1 : FT2;
if (!Better1 && !Better2) // Neither is better than the other
- return JudgeByConstraints();
+ return nullptr;
- // FIXME: This mimics what GCC implements, but doesn't match up with the
- // proposed resolution for core issue 692. This area needs to be sorted out,
- // but for now we attempt to maintain compatibility.
- bool Variadic1 = isVariadicFunctionTemplate(FT1);
- bool Variadic2 = isVariadicFunctionTemplate(FT2);
- if (Variadic1 != Variadic2)
- return Variadic1? FT2 : FT1;
+ // C++ [temp.deduct.partial]p11:
+ // ... and if G has a trailing function parameter pack for which F does not
+ // have a corresponding parameter, and if F does not have a trailing
+ // function parameter pack, then F is more specialized than G.
+ FunctionDecl *FD1 = FT1->getTemplatedDecl();
+ FunctionDecl *FD2 = FT2->getTemplatedDecl();
+ unsigned NumParams1 = FD1->getNumParams();
+ unsigned NumParams2 = FD2->getNumParams();
+ bool Variadic1 = NumParams1 && FD1->parameters().back()->isParameterPack();
+ bool Variadic2 = NumParams2 && FD2->parameters().back()->isParameterPack();
+ if (Variadic1 != Variadic2) {
+ if (Variadic1 && NumParams1 > NumParams2)
+ return FT2;
+ if (Variadic2 && NumParams2 > NumParams1)
+ return FT1;
+ }
+
+ // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
+ // there is no wording or even resolution for this issue.
+ for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) {
+ QualType T1 = FD1->getParamDecl(i)->getType().getCanonicalType();
+ QualType T2 = FD2->getParamDecl(i)->getType().getCanonicalType();
+ auto *TST1 = dyn_cast<TemplateSpecializationType>(T1);
+ auto *TST2 = dyn_cast<TemplateSpecializationType>(T2);
+ if (!TST1 || !TST2)
+ continue;
+ const TemplateArgument &TA1 = TST1->template_arguments().back();
+ if (TA1.getKind() == TemplateArgument::Pack) {
+ assert(TST1->template_arguments().size() ==
+ TST2->template_arguments().size());
+ const TemplateArgument &TA2 = TST2->template_arguments().back();
+ assert(TA2.getKind() == TemplateArgument::Pack);
+ unsigned PackSize1 = TA1.pack_size();
+ unsigned PackSize2 = TA2.pack_size();
+ bool IsPackExpansion1 =
+ PackSize1 && TA1.pack_elements().back().isPackExpansion();
+ bool IsPackExpansion2 =
+ PackSize2 && TA2.pack_elements().back().isPackExpansion();
+ if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) {
+ if (PackSize1 > PackSize2 && IsPackExpansion1)
+ return FT2;
+ if (PackSize1 < PackSize2 && IsPackExpansion2)
+ return FT1;
+ }
+ }
+ }
+
+ if (!Context.getLangOpts().CPlusPlus20)
+ return nullptr;
+
+ // Match GCC on not implementing [temp.func.order]p6.2.1.
+
+ // C++20 [temp.func.order]p6:
+ // If deduction against the other template succeeds for both transformed
+ // templates, constraints can be considered as follows:
+
+ // C++20 [temp.func.order]p6.1:
+ // If their template-parameter-lists (possibly including template-parameters
+ // invented for an abbreviated function template ([dcl.fct])) or function
+ // parameter lists differ in length, neither template is more specialized
+ // than the other.
+ TemplateParameterList *TPL1 = FT1->getTemplateParameters();
+ TemplateParameterList *TPL2 = FT2->getTemplateParameters();
+ if (TPL1->size() != TPL2->size() || NumParams1 != NumParams2)
+ return nullptr;
+
+ // C++20 [temp.func.order]p6.2.2:
+ // Otherwise, if the corresponding template-parameters of the
+ // template-parameter-lists are not equivalent ([temp.over.link]) or if the
+ // function parameters that positionally correspond between the two
+ // templates are not of the same type, neither template is more specialized
+ // than the other.
+ if (!TemplateParameterListsAreEqual(
+ TPL1, TPL2, false, Sema::TPL_TemplateMatch, SourceLocation(), true))
+ return nullptr;
+
+ for (unsigned i = 0; i < NumParams1; ++i)
+ if (!Context.hasSameType(FD1->getParamDecl(i)->getType(),
+ FD2->getParamDecl(i)->getType()))
+ return nullptr;
+
+ // C++20 [temp.func.order]p6.3:
+ // Otherwise, if the context in which the partial ordering is done is
+ // that of a call to a conversion function and the return types of the
+ // templates are not the same, then neither template is more specialized
+ // than the other.
+ if (TPOC == TPOC_Conversion &&
+ !Context.hasSameType(FD1->getReturnType(), FD2->getReturnType()))
+ return nullptr;
- return JudgeByConstraints();
+ llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ FT1->getAssociatedConstraints(AC1);
+ FT2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1))
+ return nullptr;
+ if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2))
+ return nullptr;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return nullptr;
+ return AtLeastAsConstrained1 ? FT1 : FT2;
}
/// Determine if the two templates are equivalent.
@@ -5354,7 +5475,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
if (Inst.isInvalid())
return false;
- auto *TST1 = T1->castAs<TemplateSpecializationType>();
+ const auto *TST1 = cast<TemplateSpecializationType>(T1);
bool AtLeastAsSpecialized;
S.runWithSufficientStackSpace(Info.getLocation(), [&] {
AtLeastAsSpecialized = !FinishTemplateArgumentDeduction(
@@ -5366,6 +5487,180 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
return AtLeastAsSpecialized;
}
+namespace {
+// A dummy class to return nullptr instead of P2 when performing "more
+// specialized than primary" check.
+struct GetP2 {
+ template <typename T1, typename T2,
+ std::enable_if_t<std::is_same_v<T1, T2>, bool> = true>
+ T2 *operator()(T1 *, T2 *P2) {
+ return P2;
+ }
+ template <typename T1, typename T2,
+ std::enable_if_t<!std::is_same_v<T1, T2>, bool> = true>
+ T1 *operator()(T1 *, T2 *) {
+ return nullptr;
+ }
+};
+
+// The assumption is that two template argument lists have the same size.
+struct TemplateArgumentListAreEqual {
+ ASTContext &Ctx;
+ TemplateArgumentListAreEqual(ASTContext &Ctx) : Ctx(Ctx) {}
+
+ template <typename T1, typename T2,
+ std::enable_if_t<std::is_same_v<T1, T2>, bool> = true>
+ bool operator()(T1 *PS1, T2 *PS2) {
+ ArrayRef<TemplateArgument> Args1 = PS1->getTemplateArgs().asArray(),
+ Args2 = PS2->getTemplateArgs().asArray();
+
+ for (unsigned I = 0, E = Args1.size(); I < E; ++I) {
+ // We use profile, instead of structural comparison of the arguments,
+ // because canonicalization can't do the right thing for dependent
+ // expressions.
+ llvm::FoldingSetNodeID IDA, IDB;
+ Args1[I].Profile(IDA, Ctx);
+ Args2[I].Profile(IDB, Ctx);
+ if (IDA != IDB)
+ return false;
+ }
+ return true;
+ }
+
+ template <typename T1, typename T2,
+ std::enable_if_t<!std::is_same_v<T1, T2>, bool> = true>
+ bool operator()(T1 *Spec, T2 *Primary) {
+ ArrayRef<TemplateArgument> Args1 = Spec->getTemplateArgs().asArray(),
+ Args2 = Primary->getInjectedTemplateArgs();
+
+ for (unsigned I = 0, E = Args1.size(); I < E; ++I) {
+ // We use profile, instead of structural comparison of the arguments,
+ // because canonicalization can't do the right thing for dependent
+ // expressions.
+ llvm::FoldingSetNodeID IDA, IDB;
+ Args1[I].Profile(IDA, Ctx);
+ // Unlike the specialization arguments, the injected arguments are not
+ // always canonical.
+ Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx);
+ if (IDA != IDB)
+ return false;
+ }
+ return true;
+ }
+};
+} // namespace
+
+/// Returns the more specialized template specialization between T1/P1 and
+/// T2/P2.
+/// - If IsMoreSpecialThanPrimaryCheck is true, T1/P1 is the partial
+/// specialization and T2/P2 is the primary template.
+/// - otherwise, both T1/P1 and T2/P2 are the partial specialization.
+///
+/// \param T1 the type of the first template partial specialization
+///
+/// \param T2 if IsMoreSpecialThanPrimaryCheck is true, the type of the second
+/// template partial specialization; otherwise, the type of the
+/// primary template.
+///
+/// \param P1 the first template partial specialization
+///
+/// \param P2 if IsMoreSpecialThanPrimaryCheck is true, the second template
+/// partial specialization; otherwise, the primary template.
+///
+/// \returns - If IsMoreSpecialThanPrimaryCheck is true, returns P1 if P1 is
+/// more specialized, returns nullptr if P1 is not more specialized.
+/// - otherwise, returns the more specialized template partial
+/// specialization. If neither partial specialization is more
+/// specialized, returns NULL.
+template <typename TemplateLikeDecl, typename PrimaryDel>
+static TemplateLikeDecl *
+getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1,
+ PrimaryDel *P2, TemplateDeductionInfo &Info) {
+ constexpr bool IsMoreSpecialThanPrimaryCheck =
+ !std::is_same_v<TemplateLikeDecl, PrimaryDel>;
+
+ bool Better1 = isAtLeastAsSpecializedAs(S, T1, T2, P2, Info);
+ if (IsMoreSpecialThanPrimaryCheck && !Better1)
+ return nullptr;
+
+ bool Better2 = isAtLeastAsSpecializedAs(S, T2, T1, P1, Info);
+ if (IsMoreSpecialThanPrimaryCheck && !Better2)
+ return P1;
+
+ // C++ [temp.deduct.partial]p10:
+ // F is more specialized than G if F is at least as specialized as G and G
+ // is not at least as specialized as F.
+ if (Better1 != Better2) // We have a clear winner
+ return Better1 ? P1 : GetP2()(P1, P2);
+
+ if (!Better1 && !Better2)
+ return nullptr;
+
+ // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
+ // there is no wording or even resolution for this issue.
+ auto *TST1 = cast<TemplateSpecializationType>(T1);
+ auto *TST2 = cast<TemplateSpecializationType>(T2);
+ const TemplateArgument &TA1 = TST1->template_arguments().back();
+ if (TA1.getKind() == TemplateArgument::Pack) {
+ assert(TST1->template_arguments().size() ==
+ TST2->template_arguments().size());
+ const TemplateArgument &TA2 = TST2->template_arguments().back();
+ assert(TA2.getKind() == TemplateArgument::Pack);
+ unsigned PackSize1 = TA1.pack_size();
+ unsigned PackSize2 = TA2.pack_size();
+ bool IsPackExpansion1 =
+ PackSize1 && TA1.pack_elements().back().isPackExpansion();
+ bool IsPackExpansion2 =
+ PackSize2 && TA2.pack_elements().back().isPackExpansion();
+ if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) {
+ if (PackSize1 > PackSize2 && IsPackExpansion1)
+ return GetP2()(P1, P2);
+ if (PackSize1 < PackSize2 && IsPackExpansion2)
+ return P1;
+ }
+ }
+
+ if (!S.Context.getLangOpts().CPlusPlus20)
+ return nullptr;
+
+ // Match GCC on not implementing [temp.func.order]p6.2.1.
+
+ // C++20 [temp.func.order]p6:
+ // If deduction against the other template succeeds for both transformed
+ // templates, constraints can be considered as follows:
+
+ TemplateParameterList *TPL1 = P1->getTemplateParameters();
+ TemplateParameterList *TPL2 = P2->getTemplateParameters();
+ if (TPL1->size() != TPL2->size())
+ return nullptr;
+
+ // C++20 [temp.func.order]p6.2.2:
+ // Otherwise, if the corresponding template-parameters of the
+ // template-parameter-lists are not equivalent ([temp.over.link]) or if the
+ // function parameters that positionally correspond between the two
+ // templates are not of the same type, neither template is more specialized
+ // than the other.
+ if (!S.TemplateParameterListsAreEqual(
+ TPL1, TPL2, false, Sema::TPL_TemplateMatch, SourceLocation(), true))
+ return nullptr;
+
+ if (!TemplateArgumentListAreEqual(S.getASTContext())(P1, P2))
+ return nullptr;
+
+ llvm::SmallVector<const Expr *, 3> AC1, AC2;
+ P1->getAssociatedConstraints(AC1);
+ P2->getAssociatedConstraints(AC2);
+ bool AtLeastAsConstrained1, AtLeastAsConstrained2;
+ if (S.IsAtLeastAsConstrained(P1, AC1, P2, AC2, AtLeastAsConstrained1) ||
+ (IsMoreSpecialThanPrimaryCheck && !AtLeastAsConstrained1))
+ return nullptr;
+ if (S.IsAtLeastAsConstrained(P2, AC2, P1, AC1, AtLeastAsConstrained2))
+ return nullptr;
+ if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
+ return nullptr;
+ return AtLeastAsConstrained1 ? P1 : GetP2()(P1, P2);
+}
+
/// Returns the more specialized class template partial specialization
/// according to the rules of partial ordering of class template partial
/// specializations (C++ [temp.class.order]).
@@ -5385,26 +5680,7 @@ Sema::getMoreSpecializedPartialSpecialization(
QualType PT2 = PS2->getInjectedSpecializationType();
TemplateDeductionInfo Info(Loc);
- bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
- bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
-
- if (!Better1 && !Better2)
- return nullptr;
- if (Better1 && Better2) {
- llvm::SmallVector<const Expr *, 3> AC1, AC2;
- PS1->getAssociatedConstraints(AC1);
- PS2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1))
- return nullptr;
- if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2))
- return nullptr;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return nullptr;
- return AtLeastAsConstrained1 ? PS1 : PS2;
- }
-
- return Better1 ? PS1 : PS2;
+ return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
}
bool Sema::isMoreSpecializedThanPrimary(
@@ -5412,24 +5688,12 @@ bool Sema::isMoreSpecializedThanPrimary(
ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
QualType PartialT = Spec->getInjectedSpecializationType();
- if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
- return false;
- if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info))
- return true;
- Info.clearSFINAEDiagnostic();
- llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
- Primary->getAssociatedConstraints(PrimaryAC);
- Spec->getAssociatedConstraints(SpecAC);
- bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec;
- if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC,
- AtLeastAsConstrainedSpec))
- return false;
- if (!AtLeastAsConstrainedSpec)
- return false;
- if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
- AtLeastAsConstrainedPrimary))
- return false;
- return !AtLeastAsConstrainedPrimary;
+
+ ClassTemplatePartialSpecializationDecl *MaybeSpec =
+ getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
+ if (MaybeSpec)
+ Info.clearSFINAEDiagnostic();
+ return MaybeSpec;
}
VarTemplatePartialSpecializationDecl *
@@ -5449,62 +5713,24 @@ Sema::getMoreSpecializedPartialSpecialization(
CanonTemplate, PS2->getTemplateArgs().asArray());
TemplateDeductionInfo Info(Loc);
- bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
- bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
-
- if (!Better1 && !Better2)
- return nullptr;
- if (Better1 && Better2) {
- llvm::SmallVector<const Expr *, 3> AC1, AC2;
- PS1->getAssociatedConstraints(AC1);
- PS2->getAssociatedConstraints(AC2);
- bool AtLeastAsConstrained1, AtLeastAsConstrained2;
- if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1))
- return nullptr;
- if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2))
- return nullptr;
- if (AtLeastAsConstrained1 == AtLeastAsConstrained2)
- return nullptr;
- return AtLeastAsConstrained1 ? PS1 : PS2;
- }
-
- return Better1 ? PS1 : PS2;
+ return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
}
bool Sema::isMoreSpecializedThanPrimary(
VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
- TemplateDecl *Primary = Spec->getSpecializedTemplate();
- // FIXME: Cache the injected template arguments rather than recomputing
- // them for each partial specialization.
- SmallVector<TemplateArgument, 8> PrimaryArgs;
- Context.getInjectedTemplateArgs(Primary->getTemplateParameters(),
- PrimaryArgs);
-
+ VarTemplateDecl *Primary = Spec->getSpecializedTemplate();
TemplateName CanonTemplate =
Context.getCanonicalTemplateName(TemplateName(Primary));
QualType PrimaryT = Context.getTemplateSpecializationType(
- CanonTemplate, PrimaryArgs);
+ CanonTemplate, Primary->getInjectedTemplateArgs());
QualType PartialT = Context.getTemplateSpecializationType(
CanonTemplate, Spec->getTemplateArgs().asArray());
- if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
- return false;
- if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info))
- return true;
- Info.clearSFINAEDiagnostic();
- llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC;
- Primary->getAssociatedConstraints(PrimaryAC);
- Spec->getAssociatedConstraints(SpecAC);
- bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec;
- if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC,
- AtLeastAsConstrainedSpec))
- return false;
- if (!AtLeastAsConstrainedSpec)
- return false;
- if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC,
- AtLeastAsConstrainedPrimary))
- return false;
- return !AtLeastAsConstrainedPrimary;
+ VarTemplatePartialSpecializationDecl *MaybeSpec =
+ getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
+ if (MaybeSpec)
+ Info.clearSFINAEDiagnostic();
+ return MaybeSpec;
}
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
@@ -5556,13 +5782,15 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
// C++1z [temp.arg.template]p3:
// If the rewrite produces an invalid type, then P is not at least as
// specialized as A.
- if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, PArgs) ||
+ SmallVector<TemplateArgument, 4> SugaredPArgs;
+ if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, SugaredPArgs,
+ PArgs) ||
Trap.hasErrorOccurred())
return false;
}
- QualType AType = Context.getTemplateSpecializationType(X, AArgs);
- QualType PType = Context.getTemplateSpecializationType(X, PArgs);
+ QualType AType = Context.getCanonicalTemplateSpecializationType(X, AArgs);
+ QualType PType = Context.getCanonicalTemplateSpecializationType(X, PArgs);
// ... the function template corresponding to P is at least as specialized
// as the function template corresponding to A according to the partial
@@ -5588,8 +5816,8 @@ struct MarkUsedTemplateParameterVisitor :
}
bool TraverseTemplateName(TemplateName Template) {
- if (auto *TTP =
- dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl()))
+ if (auto *TTP = llvm::dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Template.getAsTemplateDecl()))
if (TTP->getDepth() == Depth)
Used[TTP->getIndex()] = true;
RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>::
@@ -5734,7 +5962,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
cast<DependentSizedArrayType>(T)->getSizeExpr(),
OnlyDeduced, Depth, Used);
// Fall through to check the element type
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::ConstantArray:
case Type::IncompleteArray:
@@ -5834,9 +6062,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
case Type::SubstTemplateTypeParmPack: {
const SubstTemplateTypeParmPackType *Subst
= cast<SubstTemplateTypeParmPackType>(T);
- MarkUsedTemplateParameters(Ctx,
- QualType(Subst->getReplacedParameter(), 0),
- OnlyDeduced, Depth, Used);
+ if (Subst->getReplacedParameter()->getDepth() == Depth)
+ Used[Subst->getIndex()] = true;
MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(),
OnlyDeduced, Depth, Used);
break;
@@ -5844,7 +6071,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
case Type::InjectedClassName:
T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
@@ -5860,9 +6087,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
hasPackExpansionBeforeEnd(Spec->template_arguments()))
break;
- for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
- Used);
+ for (const auto &Arg : Spec->template_arguments())
+ MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used);
break;
}
@@ -5906,16 +6132,14 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
MarkUsedTemplateParameters(Ctx, Spec->getQualifier(),
OnlyDeduced, Depth, Used);
- for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth,
- Used);
+ for (const auto &Arg : Spec->template_arguments())
+ MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used);
break;
}
case Type::TypeOf:
if (!OnlyDeduced)
- MarkUsedTemplateParameters(Ctx,
- cast<TypeOfType>(T)->getUnderlyingType(),
+ MarkUsedTemplateParameters(Ctx, cast<TypeOfType>(T)->getUnmodifiedType(),
OnlyDeduced, Depth, Used);
break;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index f09b3473c074..2790e78aa53a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -15,10 +15,12 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/PrettyDeclStackTrace.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Stack.h"
@@ -26,12 +28,15 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaConcept.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
+#include <optional>
using namespace clang;
using namespace sema;
@@ -40,13 +45,231 @@ using namespace sema;
// Template Instantiation Support
//===----------------------------------------------------------------------===/
+namespace {
+namespace TemplateInstArgsHelpers {
+struct Response {
+ const Decl *NextDecl = nullptr;
+ bool IsDone = false;
+ bool ClearRelativeToPrimary = true;
+ static Response Done() {
+ Response R;
+ R.IsDone = true;
+ return R;
+ }
+ static Response ChangeDecl(const Decl *ND) {
+ Response R;
+ R.NextDecl = ND;
+ return R;
+ }
+ static Response ChangeDecl(const DeclContext *Ctx) {
+ Response R;
+ R.NextDecl = Decl::castFromDeclContext(Ctx);
+ return R;
+ }
+
+ static Response UseNextDecl(const Decl *CurDecl) {
+ return ChangeDecl(CurDecl->getDeclContext());
+ }
+
+ static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) {
+ Response R = Response::UseNextDecl(CurDecl);
+ R.ClearRelativeToPrimary = false;
+ return R;
+ }
+};
+// Add template arguments from a variable template instantiation.
+Response
+HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
+ MultiLevelTemplateArgumentList &Result,
+ bool SkipForSpecialization) {
+ // For a class-scope explicit specialization, there are no template arguments
+ // at this level, but there may be enclosing template arguments.
+ if (VarTemplSpec->isClassScopeExplicitSpecialization())
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+
+ // We're done when we hit an explicit specialization.
+ if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<VarTemplatePartialSpecializationDecl>(VarTemplSpec))
+ return Response::Done();
+
+ // If this variable template specialization was instantiated from a
+ // specialized member that is a variable template, we're done.
+ assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?");
+ llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
+ Specialized = VarTemplSpec->getSpecializedTemplateOrPartial();
+ if (VarTemplatePartialSpecializationDecl *Partial =
+ Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+ if (Partial->isMemberSpecialization())
+ return Response::Done();
+ } else {
+ VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+ if (Tmpl->isMemberSpecialization())
+ return Response::Done();
+ }
+ return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
+}
+
+// If we have a template template parameter with translation unit context,
+// then we're performing substitution into a default template argument of
+// this template template parameter before we've constructed the template
+// that will own this template template parameter. In this case, we
+// use empty template parameter lists for all of the outer templates
+// to avoid performing any substitutions.
+Response
+HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP,
+ MultiLevelTemplateArgumentList &Result) {
+ for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
+ Result.addOuterTemplateArguments(std::nullopt);
+ return Response::Done();
+}
+
+// Add template arguments from a class template instantiation.
+Response
+HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
+ MultiLevelTemplateArgumentList &Result,
+ bool SkipForSpecialization) {
+ if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) {
+ // We're done when we hit an explicit specialization.
+ if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
+ !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
+ return Response::Done();
+
+ if (!SkipForSpecialization)
+ Result.addOuterTemplateArguments(
+ const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
+ ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
+ /*Final=*/false);
+
+ // If this class template specialization was instantiated from a
+ // specialized member that is a class template, we're done.
+ assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?");
+ if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization())
+ return Response::Done();
+ }
+ return Response::UseNextDecl(ClassTemplSpec);
+}
+
+Response HandleFunction(const FunctionDecl *Function,
+ MultiLevelTemplateArgumentList &Result,
+ const FunctionDecl *Pattern, bool RelativeToPrimary,
+ bool ForConstraintInstantiation) {
+ // Add template arguments from a function template specialization.
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKindForInstantiation() ==
+ TSK_ExplicitSpecialization)
+ return Response::Done();
+
+ if (!RelativeToPrimary &&
+ Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ // This is an implicit instantiation of an explicit specialization. We
+ // don't get any template arguments from this function but might get
+ // some from an enclosing template.
+ return Response::UseNextDecl(Function);
+ } else if (const TemplateArgumentList *TemplateArgs =
+ Function->getTemplateSpecializationArgs()) {
+ // Add the template arguments for this specialization.
+ Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function),
+ TemplateArgs->asArray(),
+ /*Final=*/false);
+
+ // If this function was instantiated from a specialized member that is
+ // a function template, we're done.
+ assert(Function->getPrimaryTemplate() && "No function template?");
+ if (Function->getPrimaryTemplate()->isMemberSpecialization())
+ return Response::Done();
+
+ // If this function is a generic lambda specialization, we are done.
+ if (!ForConstraintInstantiation &&
+ isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
+ return Response::Done();
+
+ } else if (Function->getDescribedFunctionTemplate()) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "Outer template not instantiated?");
+ }
+ // If this is a friend or local declaration and it declares an entity at
+ // namespace scope, take arguments from its lexical parent
+ // instead of its semantic parent, unless of course the pattern we're
+ // instantiating actually comes from the file's context!
+ if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) &&
+ Function->getNonTransparentDeclContext()->isFileContext() &&
+ (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
+ return Response::ChangeDecl(Function->getLexicalDeclContext());
+ }
+ return Response::UseNextDecl(Function);
+}
+
+Response HandleRecordDecl(const CXXRecordDecl *Rec,
+ MultiLevelTemplateArgumentList &Result,
+ ASTContext &Context,
+ bool ForConstraintInstantiation) {
+ if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
+ assert(
+ (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
+ "Outer template not instantiated?");
+ if (ClassTemplate->isMemberSpecialization())
+ return Response::Done();
+ if (ForConstraintInstantiation) {
+ QualType RecordType = Context.getTypeDeclType(Rec);
+ QualType Injected = cast<InjectedClassNameType>(RecordType)
+ ->getInjectedSpecializationType();
+ const auto *InjectedType = cast<TemplateSpecializationType>(Injected);
+ Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec),
+ InjectedType->template_arguments(),
+ /*Final=*/false);
+ }
+ }
+
+ bool IsFriend = Rec->getFriendObjectKind() ||
+ (Rec->getDescribedClassTemplate() &&
+ Rec->getDescribedClassTemplate()->getFriendObjectKind());
+ if (ForConstraintInstantiation && IsFriend &&
+ Rec->getNonTransparentDeclContext()->isFileContext()) {
+ return Response::ChangeDecl(Rec->getLexicalDeclContext());
+ }
+
+ // This is to make sure we pick up the VarTemplateSpecializationDecl that this
+ // lambda is defined inside of.
+ if (Rec->isLambda())
+ if (const Decl *LCD = Rec->getLambdaContextDecl())
+ return Response::ChangeDecl(LCD);
+
+ return Response::UseNextDecl(Rec);
+}
+
+Response HandleImplicitConceptSpecializationDecl(
+ const ImplicitConceptSpecializationDecl *CSD,
+ MultiLevelTemplateArgumentList &Result) {
+ Result.addOuterTemplateArguments(
+ const_cast<ImplicitConceptSpecializationDecl *>(CSD),
+ CSD->getTemplateArguments(),
+ /*Final=*/false);
+ return Response::UseNextDecl(CSD);
+}
+
+Response HandleGenericDeclContext(const Decl *CurDecl) {
+ return Response::UseNextDecl(CurDecl);
+}
+} // namespace TemplateInstArgsHelpers
+} // namespace
+
/// Retrieve the template argument list(s) that should be used to
/// instantiate the definition of the given declaration.
///
-/// \param D the declaration for which we are computing template instantiation
+/// \param ND the declaration for which we are computing template instantiation
/// arguments.
///
-/// \param Innermost if non-NULL, the innermost template argument list.
+/// \param Innermost if non-NULL, specifies a template argument list for the
+/// template declaration passed as ND.
///
/// \param RelativeToPrimary true if we should get the template
/// arguments relative to the primary template, even when we're
@@ -54,137 +277,64 @@ using namespace sema;
/// template specializations.
///
/// \param Pattern If non-NULL, indicates the pattern from which we will be
-/// instantiating the definition of the given declaration, \p D. This is
+/// instantiating the definition of the given declaration, \p ND. This is
/// used to determine the proper set of template instantiation arguments for
/// friend function template specializations.
+///
+/// \param ForConstraintInstantiation when collecting arguments,
+/// ForConstraintInstantiation indicates we should continue looking when
+/// encountering a lambda generic call operator, and continue looking for
+/// arguments on an enclosing class template.
+
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
- const NamedDecl *D, const TemplateArgumentList *Innermost,
- bool RelativeToPrimary, const FunctionDecl *Pattern) {
+ const NamedDecl *ND, bool Final, const TemplateArgumentList *Innermost,
+ bool RelativeToPrimary, const FunctionDecl *Pattern,
+ bool ForConstraintInstantiation, bool SkipForSpecialization) {
+ assert(ND && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
if (Innermost)
- Result.addOuterTemplateArguments(Innermost);
-
- const auto *Ctx = dyn_cast<DeclContext>(D);
- if (!Ctx) {
- Ctx = D->getDeclContext();
-
- // Add template arguments from a variable template instantiation. For a
- // class-scope explicit specialization, there are no template arguments
- // at this level, but there may be enclosing template arguments.
- const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(D);
- if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
- // We're done when we hit an explicit specialization.
- if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
- !isa<VarTemplatePartialSpecializationDecl>(Spec))
- return Result;
-
- Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
-
- // If this variable template specialization was instantiated from a
- // specialized member that is a variable template, we're done.
- assert(Spec->getSpecializedTemplate() && "No variable template?");
- llvm::PointerUnion<VarTemplateDecl*,
- VarTemplatePartialSpecializationDecl*> Specialized
- = Spec->getSpecializedTemplateOrPartial();
- if (VarTemplatePartialSpecializationDecl *Partial =
- Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
- if (Partial->isMemberSpecialization())
- return Result;
- } else {
- VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
- if (Tmpl->isMemberSpecialization())
- return Result;
- }
- }
-
- // If we have a template template parameter with translation unit context,
- // then we're performing substitution into a default template argument of
- // this template template parameter before we've constructed the template
- // that will own this template template parameter. In this case, we
- // use empty template parameter lists for all of the outer templates
- // to avoid performing any substitutions.
- if (Ctx->isTranslationUnit()) {
- if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
- for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
- Result.addOuterTemplateArguments(None);
- return Result;
- }
- }
- }
-
- while (!Ctx->isFileContext()) {
- // Add template arguments from a class template instantiation.
- const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx);
- if (Spec && !Spec->isClassScopeExplicitSpecialization()) {
- // We're done when we hit an explicit specialization.
- if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization &&
- !isa<ClassTemplatePartialSpecializationDecl>(Spec))
- break;
-
- Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
-
- // If this class template specialization was instantiated from a
- // specialized member that is a class template, we're done.
- assert(Spec->getSpecializedTemplate() && "No class template?");
- if (Spec->getSpecializedTemplate()->isMemberSpecialization())
- break;
- }
- // Add template arguments from a function template specialization.
- else if (const auto *Function = dyn_cast<FunctionDecl>(Ctx)) {
- if (!RelativeToPrimary &&
- Function->getTemplateSpecializationKindForInstantiation() ==
- TSK_ExplicitSpecialization)
- break;
-
- if (!RelativeToPrimary && Function->getTemplateSpecializationKind() ==
- TSK_ExplicitSpecialization) {
- // This is an implicit instantiation of an explicit specialization. We
- // don't get any template arguments from this function but might get
- // some from an enclosing template.
- } else if (const TemplateArgumentList *TemplateArgs
- = Function->getTemplateSpecializationArgs()) {
- // Add the template arguments for this specialization.
- Result.addOuterTemplateArguments(TemplateArgs);
-
- // If this function was instantiated from a specialized member that is
- // a function template, we're done.
- assert(Function->getPrimaryTemplate() && "No function template?");
- if (Function->getPrimaryTemplate()->isMemberSpecialization())
- break;
-
- // If this function is a generic lambda specialization, we are done.
- if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
- break;
-
- } else if (Function->getDescribedFunctionTemplate()) {
- assert(Result.getNumSubstitutedLevels() == 0 &&
- "Outer template not instantiated?");
- }
-
- // If this is a friend declaration and it declares an entity at
- // namespace scope, take arguments from its lexical parent
- // instead of its semantic parent, unless of course the pattern we're
- // instantiating actually comes from the file's context!
- if (Function->getFriendObjectKind() &&
- Function->getDeclContext()->isFileContext() &&
- (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
- Ctx = Function->getLexicalDeclContext();
- RelativeToPrimary = false;
- continue;
- }
- } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) {
- if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
- assert(Result.getNumSubstitutedLevels() == 0 &&
- "Outer template not instantiated?");
- if (ClassTemplate->isMemberSpecialization())
- break;
+ Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND),
+ Innermost->asArray(), Final);
+
+ const Decl *CurDecl = ND;
+
+ while (!CurDecl->isFileContextDecl()) {
+ using namespace TemplateInstArgsHelpers;
+ Response R;
+ if (const auto *VarTemplSpec =
+ dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization);
+ } else if (const auto *ClassTemplSpec =
+ dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) {
+ R = HandleClassTemplateSpec(ClassTemplSpec, Result,
+ SkipForSpecialization);
+ } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
+ R = HandleFunction(Function, Result, Pattern, RelativeToPrimary,
+ ForConstraintInstantiation);
+ } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
+ R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation);
+ } else if (const auto *CSD =
+ dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
+ R = HandleImplicitConceptSpecializationDecl(CSD, Result);
+ } else if (!isa<DeclContext>(CurDecl)) {
+ R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
+ if (CurDecl->getDeclContext()->isTranslationUnit()) {
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
+ R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
+ }
}
+ } else {
+ R = HandleGenericDeclContext(CurDecl);
}
- Ctx = Ctx->getParent();
- RelativeToPrimary = false;
+ if (R.IsDone)
+ return Result;
+ if (R.ClearRelativeToPrimary)
+ RelativeToPrimary = false;
+ assert(R.NextDecl);
+ CurDecl = R.NextDecl;
}
return Result;
@@ -204,6 +354,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
return true;
case RequirementInstantiation:
+ case RequirementParameterInstantiation:
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
case DeclaringImplicitEqualityComparison:
@@ -377,8 +528,8 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::RequirementInstantiation,
PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
- /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {}
-
+ /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) {
+}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -387,8 +538,16 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
: InstantiatingTemplate(
SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck,
PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
- /*Template=*/nullptr, /*TemplateArgs=*/None) {}
+ /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation, const RequiresExpr *RE,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::RequirementParameterInstantiation,
+ PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr,
+ /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) {
+}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -424,6 +583,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
SemaRef, CodeSynthesisContext::ParameterMappingSubstitution,
PointOfInstantiation, InstantiationRange, Template) {}
+
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
@@ -593,7 +753,7 @@ void Sema::PrintInstantiationStack() {
TemplateDecl *Template = cast<TemplateDecl>(Active->Template);
SmallString<128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
- Template->printName(OS);
+ Template->printName(OS, getPrintingPolicy());
printTemplateArgumentList(OS, Active->template_arguments(),
getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
@@ -659,7 +819,7 @@ void Sema::PrintInstantiationStack() {
SmallString<128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
- FD->printName(OS);
+ FD->printName(OS, getPrintingPolicy());
printTemplateArgumentList(OS, Active->template_arguments(),
getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
@@ -729,6 +889,11 @@ void Sema::PrintInstantiationStack() {
diag::note_template_requirement_instantiation_here)
<< Active->InstantiationRange;
break;
+ case CodeSynthesisContext::RequirementParameterInstantiation:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_template_requirement_params_instantiation_here)
+ << Active->InstantiationRange;
+ break;
case CodeSynthesisContext::NestedRequirementConstraintsCheck:
Diags.Report(Active->PointOfInstantiation,
@@ -790,8 +955,7 @@ void Sema::PrintInstantiationStack() {
Diags.Report(Active->PointOfInstantiation,
diag::note_building_builtin_dump_struct_call)
<< convertCallArgsToString(
- *this,
- llvm::makeArrayRef(Active->CallArgs, Active->NumCallArgs));
+ *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs));
break;
case CodeSynthesisContext::Memoization:
@@ -819,7 +983,7 @@ void Sema::PrintInstantiationStack() {
}
SmallString<128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
- cast<NamedDecl>(Active->Entity)->printName(OS);
+ cast<NamedDecl>(Active->Entity)->printName(OS, getPrintingPolicy());
if (!isa<FunctionDecl>(Active->Entity)) {
printTemplateArgumentList(OS, Active->template_arguments(),
getPrintingPolicy());
@@ -848,9 +1012,9 @@ void Sema::PrintInstantiationStack() {
}
}
-Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
+std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
if (InNonInstantiationSFINAEContext)
- return Optional<TemplateDeductionInfo *>(nullptr);
+ return std::optional<TemplateDeductionInfo *>(nullptr);
for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator
Active = CodeSynthesisContexts.rbegin(),
@@ -864,7 +1028,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
// context, depending on what else is on the stack.
if (isa<TypeAliasTemplateDecl>(Active->Entity))
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
case CodeSynthesisContext::ExceptionSpecInstantiation:
case CodeSynthesisContext::ConstraintsCheck:
@@ -872,7 +1036,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ConstraintNormalization:
case CodeSynthesisContext::NestedRequirementConstraintsCheck:
// This is a template instantiation, so there is no SFINAE.
- return None;
+ return std::nullopt;
case CodeSynthesisContext::DefaultTemplateArgumentInstantiation:
case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
@@ -887,6 +1051,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
case CodeSynthesisContext::ConstraintSubstitution:
case CodeSynthesisContext::RequirementInstantiation:
+ case CodeSynthesisContext::RequirementParameterInstantiation:
// We're either substituting explicitly-specified template arguments,
// deduced template arguments, a constraint expression or a requirement
// in a requires expression, so SFINAE applies.
@@ -901,7 +1066,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
- return None;
+ return std::nullopt;
case CodeSynthesisContext::ExceptionSpecEvaluation:
// FIXME: This should not be treated as a SFINAE context, because
@@ -916,10 +1081,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
// The inner context was transparent for SFINAE. If it occurred within a
// non-instantiation SFINAE context, then SFINAE applies.
if (Active->SavedInNonInstantiationSFINAEContext)
- return Optional<TemplateDeductionInfo *>(nullptr);
+ return std::optional<TemplateDeductionInfo *>(nullptr);
}
- return None;
+ return std::nullopt;
}
//===----------------------------------------------------------------------===/
@@ -930,16 +1095,23 @@ namespace {
const MultiLevelTemplateArgumentList &TemplateArgs;
SourceLocation Loc;
DeclarationName Entity;
+ bool EvaluateConstraints = true;
public:
typedef TreeTransform<TemplateInstantiator> inherited;
TemplateInstantiator(Sema &SemaRef,
const MultiLevelTemplateArgumentList &TemplateArgs,
- SourceLocation Loc,
- DeclarationName Entity)
- : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
- Entity(Entity) { }
+ SourceLocation Loc, DeclarationName Entity)
+ : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+ Entity(Entity) {}
+
+ void setEvaluateConstraints(bool B) {
+ EvaluateConstraints = B;
+ }
+ bool getEvaluateConstraints() {
+ return EvaluateConstraints;
+ }
/// Determine whether the given type \p T has already been
/// transformed.
@@ -965,11 +1137,18 @@ namespace {
return TemplateArgs.getNewDepth(Depth);
}
+ std::optional<unsigned> getPackIndex(TemplateArgument Pack) {
+ int Index = getSema().ArgumentPackSubstitutionIndex;
+ if (Index == -1)
+ return std::nullopt;
+ return Pack.pack_size() - 1 - Index;
+ }
+
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand, bool &RetainExpansion,
- Optional<unsigned> &NumExpansions) {
+ std::optional<unsigned> &NumExpansions) {
return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
PatternRange, Unexpanded,
TemplateArgs,
@@ -1052,7 +1231,7 @@ namespace {
// We recreated a local declaration, but not by instantiating it. There
// may be pending dependent diagnostics to produce.
- if (auto *DC = dyn_cast<DeclContext>(Old))
+ if (auto *DC = dyn_cast<DeclContext>(Old); DC && DC->isDependentContext())
SemaRef.PerformDependentDiagnostics(DC, TemplateArgs);
}
@@ -1128,30 +1307,79 @@ namespace {
Qualifiers ThisTypeQuals,
Fn TransformExceptionSpec);
- ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
- int indexAdjustment,
- Optional<unsigned> NumExpansions,
- bool ExpectParameterPack);
+ ParmVarDecl *
+ TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment,
+ std::optional<unsigned> NumExpansions,
+ bool ExpectParameterPack);
+ using inherited::TransformTemplateTypeParmType;
/// Transforms a template type parameter type by performing
/// substitution of the corresponding template type argument.
QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL);
+ TemplateTypeParmTypeLoc TL,
+ bool SuppressObjCLifetime);
+
+ QualType BuildSubstTemplateTypeParmType(
+ TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final,
+ Decl *AssociatedDecl, unsigned Index, std::optional<unsigned> PackIndex,
+ TemplateArgument Arg, SourceLocation NameLoc);
/// Transforms an already-substituted template type parameter pack
/// into either itself (if we aren't substituting into its pack expansion)
/// or the appropriate substituted argument.
- QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
- SubstTemplateTypeParmPackTypeLoc TL);
+ using inherited::TransformSubstTemplateTypeParmPackType;
+ QualType
+ TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
+ SubstTemplateTypeParmPackTypeLoc TL,
+ bool SuppressObjCLifetime);
ExprResult TransformLambdaExpr(LambdaExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- return inherited::TransformLambdaExpr(E);
+ Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
+ ExprResult Result = inherited::TransformLambdaExpr(E);
+ if (Result.isInvalid())
+ return Result;
+
+ CXXMethodDecl *MD = Result.getAs<LambdaExpr>()->getCallOperator();
+ for (ParmVarDecl *PVD : MD->parameters()) {
+ if (!PVD->hasDefaultArg())
+ continue;
+ Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+ // FIXME: Obtain the source location for the '=' token.
+ SourceLocation EqualLoc = UninstExpr->getBeginLoc();
+ if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) {
+ // If substitution fails, the default argument is set to a
+ // RecoveryExpr that wraps the uninstantiated default argument so
+ // that downstream diagnostics are omitted.
+ ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+ UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+ { UninstExpr }, UninstExpr->getType());
+ if (ErrorResult.isUsable())
+ PVD->setDefaultArg(ErrorResult.get());
+ }
+ }
+
+ return Result;
}
ExprResult TransformRequiresExpr(RequiresExpr *E) {
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
- return inherited::TransformRequiresExpr(E);
+ ExprResult TransReq = inherited::TransformRequiresExpr(E);
+ if (TransReq.isInvalid())
+ return TransReq;
+ assert(TransReq.get() != E &&
+ "Do not change value of isSatisfied for the existing expression. "
+ "Create a new expression instead.");
+ if (E->getBody()->isDependentContext()) {
+ Sema::SFINAETrap Trap(SemaRef);
+ // We recreate the RequiresExpr body, but not by instantiating it.
+ // Produce pending diagnostics for dependent access check.
+ SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs);
+ // FIXME: Store SFINAE diagnostics in RequiresExpr for diagnosis.
+ if (Trap.hasErrorOccurred())
+ TransReq.getAs<RequiresExpr>()->setSatisfied(false);
+ }
+ return TransReq;
}
bool TransformRequiresExprRequirements(
@@ -1191,6 +1419,7 @@ namespace {
DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
TemplateDeclInstantiator DeclInstantiator(getSema(),
/* DeclContext *Owner */ Owner, TemplateArgs);
+ DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
return DeclInstantiator.SubstTemplateParams(OrigTPL);
}
@@ -1200,11 +1429,19 @@ namespace {
TransformExprRequirement(concepts::ExprRequirement *Req);
concepts::NestedRequirement *
TransformNestedRequirement(concepts::NestedRequirement *Req);
+ ExprResult TransformRequiresTypeParams(
+ SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
+ RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
+ SmallVectorImpl<QualType> &PTypes,
+ SmallVectorImpl<ParmVarDecl *> &TransParams,
+ Sema::ExtParameterInfoBuilder &PInfos);
private:
- ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
- SourceLocation loc,
- TemplateArgument arg);
+ ExprResult
+ transformNonTypeTemplateParmRef(Decl *AssociatedDecl,
+ const NonTypeTemplateParmDecl *parm,
+ SourceLocation loc, TemplateArgument arg,
+ std::optional<unsigned> PackIndex);
};
}
@@ -1394,6 +1631,9 @@ TemplateName TemplateInstantiator::TransformTemplateName(
return Arg.getAsTemplate();
}
+ auto [AssociatedDecl, Final] =
+ TemplateArgs.getAssociatedDecl(TTP->getDepth());
+ std::optional<unsigned> PackIndex;
if (TTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1402,9 +1642,11 @@ TemplateName TemplateInstantiator::TransformTemplateName(
// We have the template argument pack to substitute, but we're not
// actually expanding the enclosing pack expansion yet. So, just
// keep the entire argument pack.
- return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg);
+ return getSema().Context.getSubstTemplateTemplateParmPack(
+ Arg, AssociatedDecl, TTP->getIndex(), Final);
}
+ PackIndex = getPackIndex(Arg);
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
@@ -1413,8 +1655,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(
assert(!Template.getAsQualifiedTemplateName() &&
"template decl to substitute is qualified?");
- Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template);
- return Template;
+ if (Final)
+ return Template;
+ return getSema().Context.getSubstTemplateTemplateParm(
+ Template, AssociatedDecl, TTP->getIndex(), PackIndex);
}
}
@@ -1423,9 +1667,14 @@ TemplateName TemplateInstantiator::TransformTemplateName(
if (getSema().ArgumentPackSubstitutionIndex == -1)
return Name;
- TemplateArgument Arg = SubstPack->getArgumentPack();
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- return Arg.getAsTemplate().getNameToSubstitute();
+ TemplateArgument Pack = SubstPack->getArgumentPack();
+ TemplateName Template =
+ getPackSubstitutedTemplateArgument(getSema(), Pack).getAsTemplate();
+ if (SubstPack->getFinal())
+ return Template;
+ return getSema().Context.getSubstTemplateTemplateParm(
+ Template.getNameToSubstitute(), SubstPack->getAssociatedDecl(),
+ SubstPack->getIndex(), getPackIndex(Pack));
}
return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType,
@@ -1469,6 +1718,8 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
return Arg.getAsExpr();
}
+ auto [AssociatedDecl, _] = TemplateArgs.getAssociatedDecl(NTTP->getDepth());
+ std::optional<unsigned> PackIndex;
if (NTTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1486,16 +1737,17 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
QualType ExprType = TargetType.getNonLValueExprType(SemaRef.Context);
if (TargetType->isRecordType())
ExprType.addConst();
-
+ // FIXME: Pass in Final.
return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr(
ExprType, TargetType->isReferenceType() ? VK_LValue : VK_PRValue,
- NTTP, E->getLocation(), Arg);
+ E->getLocation(), Arg, AssociatedDecl, NTTP->getPosition());
}
-
+ PackIndex = getPackIndex(Arg);
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
-
- return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg);
+ // FIXME: Don't put subst node on Final replacement.
+ return transformNonTypeTemplateParmRef(AssociatedDecl, NTTP, E->getLocation(),
+ Arg, PackIndex);
}
const LoopHintAttr *
@@ -1516,9 +1768,9 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
}
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
- NonTypeTemplateParmDecl *parm,
- SourceLocation loc,
- TemplateArgument arg) {
+ Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm,
+ SourceLocation loc, TemplateArgument arg,
+ std::optional<unsigned> PackIndex) {
ExprResult result;
// Determine the substituted parameter type. We can usually infer this from
@@ -1586,9 +1838,10 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
return ExprError();
Expr *resultExpr = result.get();
+ // FIXME: Don't put subst node on final replacement.
return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
- resultExpr->getType(), resultExpr->getValueKind(), loc, parm, refParam,
- resultExpr);
+ resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr,
+ AssociatedDecl, parm->getIndex(), PackIndex, refParam);
}
ExprResult
@@ -1599,11 +1852,12 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
return E;
}
- TemplateArgument Arg = E->getArgumentPack();
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- return transformNonTypeTemplateParmRef(E->getParameterPack(),
- E->getParameterPackLocation(),
- Arg);
+ TemplateArgument Pack = E->getArgumentPack();
+ TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack);
+ // FIXME: Don't put subst node on final replacement.
+ return transformNonTypeTemplateParmRef(
+ E->getAssociatedDecl(), E->getParameterPack(),
+ E->getParameterPackLocation(), Arg, getPackIndex(Pack));
}
ExprResult
@@ -1637,13 +1891,16 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
// Type=char)),
// Type=decltype(2)))
// The call to CheckTemplateArgument here produces the ImpCast.
- TemplateArgument Converted;
- if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType,
- SubstReplacement.get(),
- Converted).isInvalid())
+ TemplateArgument SugaredConverted, CanonicalConverted;
+ if (SemaRef
+ .CheckTemplateArgument(E->getParameter(), SubstType,
+ SubstReplacement.get(), SugaredConverted,
+ CanonicalConverted, Sema::CTAK_Specified)
+ .isInvalid())
return true;
- return transformNonTypeTemplateParmRef(E->getParameter(),
- E->getExprLoc(), Converted);
+ return transformNonTypeTemplateParmRef(E->getAssociatedDecl(),
+ E->getParameter(), E->getExprLoc(),
+ SugaredConverted, E->getPackIndex());
}
ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD,
@@ -1744,9 +2001,9 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())->
getDescribedFunctionTemplate() &&
"Default arg expressions are never formed in dependent cases.");
- return SemaRef.BuildCXXDefaultArgExpr(E->getUsedLocation(),
- cast<FunctionDecl>(E->getParam()->getDeclContext()),
- E->getParam());
+ return SemaRef.BuildCXXDefaultArgExpr(
+ E->getUsedLocation(), cast<FunctionDecl>(E->getParam()->getDeclContext()),
+ E->getParam());
}
template<typename Fn>
@@ -1761,22 +2018,50 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec);
}
-ParmVarDecl *
-TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
- int indexAdjustment,
- Optional<unsigned> NumExpansions,
- bool ExpectParameterPack) {
- auto NewParm =
- SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
- NumExpansions, ExpectParameterPack);
+ParmVarDecl *TemplateInstantiator::TransformFunctionTypeParam(
+ ParmVarDecl *OldParm, int indexAdjustment,
+ std::optional<unsigned> NumExpansions, bool ExpectParameterPack) {
+ auto NewParm = SemaRef.SubstParmVarDecl(
+ OldParm, TemplateArgs, indexAdjustment, NumExpansions,
+ ExpectParameterPack, EvaluateConstraints);
if (NewParm && SemaRef.getLangOpts().OpenCL)
SemaRef.deduceOpenCLAddressSpace(NewParm);
return NewParm;
}
+QualType TemplateInstantiator::BuildSubstTemplateTypeParmType(
+ TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final,
+ Decl *AssociatedDecl, unsigned Index, std::optional<unsigned> PackIndex,
+ TemplateArgument Arg, SourceLocation NameLoc) {
+ QualType Replacement = Arg.getAsType();
+
+ // If the template parameter had ObjC lifetime qualifiers,
+ // then any such qualifiers on the replacement type are ignored.
+ if (SuppressObjCLifetime) {
+ Qualifiers RQs;
+ RQs = Replacement.getQualifiers();
+ RQs.removeObjCLifetime();
+ Replacement =
+ SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(), RQs);
+ }
+
+ if (Final) {
+ TLB.pushTrivial(SemaRef.Context, Replacement, NameLoc);
+ return Replacement;
+ }
+ // TODO: only do this uniquing once, at the start of instantiation.
+ QualType Result = getSema().Context.getSubstTemplateTypeParmType(
+ Replacement, AssociatedDecl, Index, PackIndex);
+ SubstTemplateTypeParmTypeLoc NewTL =
+ TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
+ NewTL.setNameLoc(NameLoc);
+ return Result;
+}
+
QualType
TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
- TemplateTypeParmTypeLoc TL) {
+ TemplateTypeParmTypeLoc TL,
+ bool SuppressObjCLifetime) {
const TemplateTypeParmType *T = TL.getTypePtr();
if (T->getDepth() < TemplateArgs.getNumLevels()) {
// Replace the template type parameter with its corresponding
@@ -1813,6 +2098,9 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return NewT;
}
+ auto [AssociatedDecl, Final] =
+ TemplateArgs.getAssociatedDecl(T->getDepth());
+ std::optional<unsigned> PackIndex;
if (T->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1821,29 +2109,25 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
// We have the template argument pack, but we're not expanding the
// enclosing pack expansion yet. Just save the template argument
// pack for later substitution.
- QualType Result
- = getSema().Context.getSubstTemplateTypeParmPackType(T, Arg);
+ QualType Result = getSema().Context.getSubstTemplateTypeParmPackType(
+ AssociatedDecl, T->getIndex(), Final, Arg);
SubstTemplateTypeParmPackTypeLoc NewTL
= TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
}
+ // PackIndex starts from last element.
+ PackIndex = getPackIndex(Arg);
Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
}
assert(Arg.getKind() == TemplateArgument::Type &&
"Template argument kind mismatch");
- QualType Replacement = Arg.getAsType();
-
- // TODO: only do this uniquing once, at the start of instantiation.
- QualType Result
- = getSema().Context.getSubstTemplateTypeParmType(T, Replacement);
- SubstTemplateTypeParmTypeLoc NewTL
- = TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
- return Result;
+ return BuildSubstTemplateTypeParmType(TLB, SuppressObjCLifetime, Final,
+ AssociatedDecl, T->getIndex(),
+ PackIndex, Arg, TL.getNameLoc());
}
// The template type parameter comes from an inner template (e.g.,
@@ -1853,8 +2137,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
TemplateTypeParmDecl *NewTTPDecl = nullptr;
if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl())
NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
- TransformDecl(TL.getNameLoc(), OldTTPDecl));
-
+ TransformDecl(TL.getNameLoc(), OldTTPDecl));
QualType Result = getSema().Context.getTemplateTypeParmType(
T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(),
T->isParameterPack(), NewTTPDecl);
@@ -1863,29 +2146,30 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return Result;
}
-QualType
-TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
- TypeLocBuilder &TLB,
- SubstTemplateTypeParmPackTypeLoc TL) {
+QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
+ TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL,
+ bool SuppressObjCLifetime) {
+ const SubstTemplateTypeParmPackType *T = TL.getTypePtr();
+
+ Decl *NewReplaced = TransformDecl(TL.getNameLoc(), T->getAssociatedDecl());
+
if (getSema().ArgumentPackSubstitutionIndex == -1) {
// We aren't expanding the parameter pack, so just return ourselves.
- SubstTemplateTypeParmPackTypeLoc NewTL
- = TLB.push<SubstTemplateTypeParmPackTypeLoc>(TL.getType());
+ QualType Result = TL.getType();
+ if (NewReplaced != T->getAssociatedDecl())
+ Result = getSema().Context.getSubstTemplateTypeParmPackType(
+ NewReplaced, T->getIndex(), T->getFinal(), T->getArgumentPack());
+ SubstTemplateTypeParmPackTypeLoc NewTL =
+ TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
- return TL.getType();
+ return Result;
}
- TemplateArgument Arg = TL.getTypePtr()->getArgumentPack();
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
- QualType Result = Arg.getAsType();
-
- Result = getSema().Context.getSubstTemplateTypeParmType(
- TL.getTypePtr()->getReplacedParameter(),
- Result);
- SubstTemplateTypeParmTypeLoc NewTL
- = TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
- return Result;
+ TemplateArgument Pack = T->getArgumentPack();
+ TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack);
+ return BuildSubstTemplateTypeParmType(
+ TLB, SuppressObjCLifetime, T->getFinal(), NewReplaced, T->getIndex(),
+ getPackIndex(Pack), Arg, TL.getNameLoc());
}
template<typename EntityPrinter>
@@ -1914,6 +2198,37 @@ createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
StringRef(MessageBuf, Message.size())};
}
+ExprResult TemplateInstantiator::TransformRequiresTypeParams(
+ SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
+ RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
+ SmallVectorImpl<QualType> &PTypes,
+ SmallVectorImpl<ParmVarDecl *> &TransParams,
+ Sema::ExtParameterInfoBuilder &PInfos) {
+
+ TemplateDeductionInfo Info(KWLoc);
+ Sema::InstantiatingTemplate TypeInst(SemaRef, KWLoc,
+ RE, Info,
+ SourceRange{KWLoc, RBraceLoc});
+ Sema::SFINAETrap Trap(SemaRef);
+
+ unsigned ErrorIdx;
+ if (getDerived().TransformFunctionTypeParams(
+ KWLoc, Params, /*ParamTypes=*/nullptr, /*ParamInfos=*/nullptr, PTypes,
+ &TransParams, PInfos, &ErrorIdx) ||
+ Trap.hasErrorOccurred()) {
+ SmallVector<concepts::Requirement *, 4> TransReqs;
+ ParmVarDecl *FailedDecl = Params[ErrorIdx];
+ // Add a 'failed' Requirement to contain the error that caused the failure
+ // here.
+ TransReqs.push_back(RebuildTypeRequirement(createSubstDiag(
+ SemaRef, Info, [&](llvm::raw_ostream &OS) { OS << *FailedDecl; })));
+ return getDerived().RebuildRequiresExpr(KWLoc, Body, TransParams, TransReqs,
+ RBraceLoc);
+ }
+
+ return ExprResult{};
+}
+
concepts::TypeRequirement *
TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) {
if (!Req->isDependent() && !AlwaysRebuild())
@@ -1971,7 +2286,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
TransExpr = TransExprRes.get();
}
- llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
+ std::optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
const auto &RetReq = Req->getReturnTypeRequirement();
if (RetReq.isEmpty())
TransRetReq.emplace();
@@ -1985,8 +2300,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
Req, Info, OrigTPL->getSourceRange());
if (TPLInst.isInvalid())
return nullptr;
- TemplateParameterList *TPL =
- TransformTemplateParameterList(OrigTPL);
+ TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL);
if (!TPL)
TransRetReq.emplace(createSubstDiag(SemaRef, Info,
[&] (llvm::raw_ostream& OS) {
@@ -2012,10 +2326,10 @@ TemplateInstantiator::TransformNestedRequirement(
concepts::NestedRequirement *Req) {
if (!Req->isDependent() && !AlwaysRebuild())
return Req;
- if (Req->isSubstitutionFailure()) {
+ if (Req->hasInvalidConstraint()) {
if (AlwaysRebuild())
- return RebuildNestedRequirement(
- Req->getSubstitutionDiagnostic());
+ return RebuildNestedRequirement(Req->getInvalidConstraintEntity(),
+ Req->getConstraintSatisfaction());
return Req;
}
Sema::InstantiatingTemplate ReqInst(SemaRef,
@@ -2035,36 +2349,30 @@ TemplateInstantiator::TransformNestedRequirement(
Req->getConstraintExpr()->getSourceRange());
if (ConstrInst.isInvalid())
return nullptr;
- TransConstraint = TransformExpr(Req->getConstraintExpr());
- if (!TransConstraint.isInvalid()) {
- bool CheckSucceeded =
- SemaRef.CheckConstraintExpression(TransConstraint.get());
- (void)CheckSucceeded;
- assert((CheckSucceeded || Trap.hasErrorOccurred()) &&
- "CheckConstraintExpression failed, but "
- "did not produce a SFINAE error");
- }
- // Use version of CheckConstraintSatisfaction that does no substitutions.
- if (!TransConstraint.isInvalid() &&
- !TransConstraint.get()->isInstantiationDependent() &&
- !Trap.hasErrorOccurred()) {
- bool CheckFailed = SemaRef.CheckConstraintSatisfaction(
- TransConstraint.get(), Satisfaction);
- (void)CheckFailed;
- assert((!CheckFailed || Trap.hasErrorOccurred()) &&
- "CheckConstraintSatisfaction failed, "
- "but did not produce a SFINAE error");
- }
- if (TransConstraint.isInvalid() || Trap.hasErrorOccurred())
- return RebuildNestedRequirement(createSubstDiag(SemaRef, Info,
- [&] (llvm::raw_ostream& OS) {
- Req->getConstraintExpr()->printPretty(OS, nullptr,
- SemaRef.getPrintingPolicy());
- }));
+ llvm::SmallVector<Expr *> Result;
+ if (!SemaRef.CheckConstraintSatisfaction(
+ nullptr, {Req->getConstraintExpr()}, Result, TemplateArgs,
+ Req->getConstraintExpr()->getSourceRange(), Satisfaction) &&
+ !Result.empty())
+ TransConstraint = Result[0];
+ assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled "
+ "by CheckConstraintSatisfaction.");
}
- if (TransConstraint.get()->isInstantiationDependent())
+ if (TransConstraint.isUsable() &&
+ TransConstraint.get()->isInstantiationDependent())
return new (SemaRef.Context)
concepts::NestedRequirement(TransConstraint.get());
+ if (TransConstraint.isInvalid() || !TransConstraint.get() ||
+ Satisfaction.HasSubstitutionFailure()) {
+ SmallString<128> Entity;
+ llvm::raw_svector_ostream OS(Entity);
+ Req->getConstraintExpr()->printPretty(OS, nullptr,
+ SemaRef.getPrintingPolicy());
+ char *EntityBuf = new (SemaRef.Context) char[Entity.size()];
+ std::copy(Entity.begin(), Entity.end(), EntityBuf);
+ return new (SemaRef.Context) concepts::NestedRequirement(
+ SemaRef.Context, StringRef(EntityBuf, Entity.size()), Satisfaction);
+ }
return new (SemaRef.Context) concepts::NestedRequirement(
SemaRef.Context, TransConstraint.get(), Satisfaction);
}
@@ -2196,7 +2504,8 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
SourceLocation Loc,
DeclarationName Entity,
CXXRecordDecl *ThisContext,
- Qualifiers ThisTypeQuals) {
+ Qualifiers ThisTypeQuals,
+ bool EvaluateConstraints) {
assert(!CodeSynthesisContexts.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
@@ -2205,6 +2514,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
return T;
TemplateInstantiator Instantiator(*this, Args, Loc, Entity);
+ Instantiator.setEvaluateConstraints(EvaluateConstraints);
TypeLocBuilder TLB;
@@ -2349,9 +2659,19 @@ namespace {
bool Sema::SubstTypeConstraint(
TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool EvaluateConstraints) {
const ASTTemplateArgumentListInfo *TemplArgInfo =
TC->getTemplateArgsAsWritten();
+
+ if (!EvaluateConstraints) {
+ Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(),
+ TC->getConceptNameInfo(), TC->getNamedConcept(),
+ TC->getNamedConcept(), TemplArgInfo,
+ TC->getImmediatelyDeclaredConstraint());
+ return false;
+ }
+
TemplateArgumentListInfo InstArgs;
if (TemplArgInfo) {
@@ -2370,11 +2690,10 @@ bool Sema::SubstTypeConstraint(
: SourceLocation());
}
-ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- int indexAdjustment,
- Optional<unsigned> NumExpansions,
- bool ExpectParameterPack) {
+ParmVarDecl *Sema::SubstParmVarDecl(
+ ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs,
+ int indexAdjustment, std::optional<unsigned> NumExpansions,
+ bool ExpectParameterPack, bool EvaluateConstraint) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = nullptr;
@@ -2432,9 +2751,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
// template's described function, but we might also get here later.
// Make sure we do not instantiate the TypeConstraint more than once.
if (Inst && !Inst->getTypeConstraint()) {
- // TODO: Concepts: do not instantiate the constraint (delayed constraint
- // substitution)
- if (SubstTypeConstraint(Inst, TC, TemplateArgs))
+ if (SubstTypeConstraint(Inst, TC, TemplateArgs, EvaluateConstraint))
return nullptr;
}
}
@@ -2457,29 +2774,17 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewParm->setUnparsedDefaultArg();
UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm);
} else if (Expr *Arg = OldParm->getDefaultArg()) {
- FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext());
- if (OwningFunc->isInLocalScopeForInstantiation()) {
- // Instantiate default arguments for methods of local classes (DR1484)
- // and non-defining declarations.
- Sema::ContextRAII SavedContext(*this, OwningFunc);
- LocalInstantiationScope Local(*this, true);
- ExprResult NewArg = SubstExpr(Arg, TemplateArgs);
- if (NewArg.isUsable()) {
- // It would be nice if we still had this.
- SourceLocation EqualLoc = NewArg.get()->getBeginLoc();
- ExprResult Result =
- ConvertParamDefaultArgument(NewParm, NewArg.get(), EqualLoc);
- if (Result.isInvalid())
- return nullptr;
-
- SetParamDefaultArgument(NewParm, Result.getAs<Expr>(), EqualLoc);
- }
- } else {
- // FIXME: if we non-lazily instantiated non-dependent default args for
- // non-dependent parameter types we could remove a bunch of duplicate
- // conversion warnings for such arguments.
- NewParm->setUninstantiatedDefaultArg(Arg);
- }
+ // Default arguments cannot be substituted until the declaration context
+ // for the associated function or lambda capture class is available.
+ // This is necessary for cases like the following where construction of
+ // the lambda capture class for the outer lambda is dependent on the
+ // parameter types but where the default argument is dependent on the
+ // outer lambda's declaration context.
+ // template <typename T>
+ // auto f() {
+ // return [](T = []{ return T{}; }()) { return 0; };
+ // }
+ NewParm->setUninstantiatedDefaultArg(Arg);
}
NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
@@ -2524,6 +2829,88 @@ bool Sema::SubstParmTypes(
Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos);
}
+/// Substitute the given template arguments into the default argument.
+bool Sema::SubstDefaultArgument(
+ SourceLocation Loc,
+ ParmVarDecl *Param,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool ForCallExpr) {
+ FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext());
+ Expr *PatternExpr = Param->getUninstantiatedDefaultArg();
+
+ EnterExpressionEvaluationContext EvalContext(
+ *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
+
+ InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost());
+ if (Inst.isInvalid())
+ return true;
+ if (Inst.isAlreadyInstantiating()) {
+ Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
+ Param->setInvalidDecl();
+ return true;
+ }
+
+ ExprResult Result;
+ {
+ // C++ [dcl.fct.default]p5:
+ // The names in the [default argument] expression are bound, and
+ // the semantic constraints are checked, at the point where the
+ // default argument expression appears.
+ ContextRAII SavedContext(*this, FD);
+ std::unique_ptr<LocalInstantiationScope> LIS;
+
+ if (ForCallExpr) {
+ // When instantiating a default argument due to use in a call expression,
+ // an instantiation scope that includes the parameters of the callee is
+ // required to satisfy references from the default argument. For example:
+ // template<typename T> void f(T a, int = decltype(a)());
+ // void g() { f(0); }
+ LIS = std::make_unique<LocalInstantiationScope>(*this);
+ FunctionDecl *PatternFD = FD->getTemplateInstantiationPattern(
+ /*ForDefinition*/ false);
+ if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs))
+ return true;
+ }
+
+ runWithSufficientStackSpace(Loc, [&] {
+ Result = SubstInitializer(PatternExpr, TemplateArgs,
+ /*DirectInit*/false);
+ });
+ }
+ if (Result.isInvalid())
+ return true;
+
+ if (ForCallExpr) {
+ // Check the expression as an initializer for the parameter.
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(Context, Param);
+ InitializationKind Kind = InitializationKind::CreateCopy(
+ Param->getLocation(),
+ /*FIXME:EqualLoc*/ PatternExpr->getBeginLoc());
+ Expr *ResultE = Result.getAs<Expr>();
+
+ InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
+ Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
+ if (Result.isInvalid())
+ return true;
+
+ Result =
+ ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(),
+ /*DiscardedValue*/ false);
+ } else {
+ // FIXME: Obtain the source location for the '=' token.
+ SourceLocation EqualLoc = PatternExpr->getBeginLoc();
+ Result = ConvertParamDefaultArgument(Param, Result.getAs<Expr>(), EqualLoc);
+ }
+ if (Result.isInvalid())
+ return true;
+
+ // Remember the instantiated default argument.
+ Param->setDefaultArg(Result.getAs<Expr>());
+
+ return false;
+}
+
/// Perform substitution on the base class specifiers of the
/// given class template specialization.
///
@@ -2556,7 +2943,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Base.getEllipsisLoc(),
Base.getSourceRange(),
Unexpanded,
@@ -2743,6 +3130,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
Instantiation->setInvalidDecl();
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
+ Instantiator.setEvaluateConstraints(false);
SmallVector<Decl*, 4> Fields;
// Delay instantiation of late parsed attributes.
LateInstantiatedAttrVec LateAttrs;
@@ -3033,6 +3421,8 @@ bool Sema::InstantiateInClassInitializer(
ContextRAII SavedContext(*this, Instantiation->getParent());
EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ ExprEvalContexts.back().DelayedDefaultInitializationContext = {
+ PointOfInstantiation, Instantiation, CurContext};
LocalInstantiationScope Scope(*this, true);
@@ -3130,7 +3520,7 @@ getPatternForClassTemplateSpecialization(
} else {
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
- Matched.back().Args = Info.take();
+ Matched.back().Args = Info.takeCanonical();
}
}
@@ -3521,11 +3911,9 @@ bool Sema::SubstTemplateArguments(
ArrayRef<TemplateArgumentLoc> Args,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentListInfo &Out) {
- TemplateInstantiator Instantiator(*this, TemplateArgs,
- SourceLocation(),
+ TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
DeclarationName());
- return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(),
- Out);
+ return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out);
}
ExprResult
@@ -3539,11 +3927,23 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformExpr(E);
}
+ExprResult
+Sema::SubstConstraintExpr(Expr *E,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (!E)
+ return E;
+
+ // This is where we need to make sure we 'know' constraint checking needs to
+ // happen.
+ TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformExpr(E);
+}
+
ExprResult Sema::SubstInitializer(Expr *Init,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool CXXDirectInit) {
- TemplateInstantiator Instantiator(*this, TemplateArgs,
- SourceLocation(),
+ TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(),
DeclarationName());
return Instantiator.TransformInitializer(Init, CXXDirectInit);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9bf6ca1f8084..7a0da8d08333 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -29,6 +29,7 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/Support/TimeProfiler.h"
+#include <optional>
using namespace clang;
@@ -120,7 +121,7 @@ static void instantiateDependentAlignedAttr(
// Determine whether we can expand this attribute pack yet.
bool Expand = true, RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
// FIXME: Use the actual location of the ellipsis.
SourceLocation EllipsisLoc = Aligned->getLocation();
if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(),
@@ -461,7 +462,7 @@ static void instantiateOMPDeclareVariantAttr(
// Check function/variant ref for `omp declare variant` but not for `omp
// begin declare variant` (which use implicit attributes).
- Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
+ std::optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), E, TI,
Attr.appendArgs_size(),
Attr.getRange());
@@ -469,8 +470,8 @@ static void instantiateOMPDeclareVariantAttr(
if (!DeclVarData)
return;
- E = DeclVarData.value().second;
- FD = DeclVarData.value().first;
+ E = DeclVarData->second;
+ FD = DeclVarData->first;
if (auto *VariantDRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) {
if (auto *VariantFD = dyn_cast<FunctionDecl>(VariantDRE->getDecl())) {
@@ -506,7 +507,7 @@ static void instantiateOMPDeclareVariantAttr(
SmallVector<Expr *, 8> NothingExprs;
SmallVector<Expr *, 8> NeedDevicePtrExprs;
- SmallVector<OMPDeclareVariantAttr::InteropType, 8> AppendArgs;
+ SmallVector<OMPInteropInfo, 4> AppendArgs;
for (Expr *E : Attr.adjustArgsNothing()) {
ExprResult ER = Subst(E);
@@ -520,7 +521,10 @@ static void instantiateOMPDeclareVariantAttr(
continue;
NeedDevicePtrExprs.push_back(ER.get());
}
- llvm::append_range(AppendArgs, Attr.appendArgs());
+ for (OMPInteropInfo &II : Attr.appendArgs()) {
+ // When prefer_type is implemented for append_args handle them here too.
+ AppendArgs.emplace_back(II.IsTarget, II.IsTargetSync);
+ }
S.ActOnOpenMPDeclareVariantDirective(
FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(),
@@ -633,7 +637,7 @@ static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) {
FD->getReturnType()->isLValueReferenceType()) {
return false;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
// HACK: Super-old versions of libc++ (3.1 and earlier) provide
@@ -873,6 +877,10 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
llvm_unreachable("Translation units cannot be instantiated");
}
+Decl *TemplateDeclInstantiator::VisitHLSLBufferDecl(HLSLBufferDecl *Decl) {
+ llvm_unreachable("HLSL buffer declarations cannot be instantiated");
+}
+
Decl *
TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) {
llvm_unreachable("pragma comment cannot be instantiated");
@@ -1172,6 +1180,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
if (Var->isStaticLocal())
SemaRef.CheckStaticLocalForDllExport(Var);
+ if (Var->getTLSKind())
+ SemaRef.CheckThreadLocalForLargeAlignment(Var);
+
return Var;
}
@@ -1628,12 +1639,16 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
}
if (PrevClassTemplate) {
- TemplateParameterList *PrevParams
- = PrevClassTemplate->getMostRecentDecl()->getTemplateParameters();
+ const ClassTemplateDecl *MostRecentPrevCT =
+ PrevClassTemplate->getMostRecentDecl();
+ TemplateParameterList *PrevParams =
+ MostRecentPrevCT->getTemplateParameters();
// Make sure the parameter lists match.
- if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, true,
- Sema::TPL_TemplateMatch))
+ if (!SemaRef.TemplateParameterListsAreEqual(
+ D->getTemplatedDecl(), InstParams,
+ MostRecentPrevCT->getTemplatedDecl(), PrevParams, true,
+ Sema::TPL_TemplateMatch))
return nullptr;
// Do some additional validation, then merge default arguments
@@ -1823,6 +1838,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
// merged with the local instantiation scope for the function template
// itself.
LocalInstantiationScope Scope(SemaRef);
+ Sema::ConstraintEvalRAII<TemplateDeclInstantiator> RAII(*this);
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
@@ -1991,7 +2007,7 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
/// Normal class members are of more specific types and therefore
/// don't make it here. This function serves three purposes:
/// 1) instantiating function templates
-/// 2) substituting friend declarations
+/// 2) substituting friend and local function declarations
/// 3) substituting deduction guide declarations for nested class templates
Decl *TemplateDeclInstantiator::VisitFunctionDecl(
FunctionDecl *D, TemplateParameterList *TemplateParams,
@@ -2062,19 +2078,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
return nullptr;
}
- // FIXME: Concepts: Do not substitute into constraint expressions
Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
- if (TrailingRequiresClause) {
- EnterExpressionEvaluationContext ConstantEvaluated(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
- ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
- TemplateArgs);
- if (SubstRC.isInvalid())
- return nullptr;
- TrailingRequiresClause = SubstRC.get();
- if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
- return nullptr;
- }
// If we're instantiating a local function declaration, put the result
// in the enclosing namespace; otherwise we need to find the instantiated
@@ -2114,6 +2118,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(),
D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(),
TrailingRequiresClause);
+ Function->setFriendConstraintRefersToEnclosingTemplate(
+ D->FriendConstraintRefersToEnclosingTemplate());
Function->setRangeEnd(D->getSourceRange().getEnd());
}
@@ -2131,6 +2137,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
assert(D->getDeclContext()->isFileContext());
LexicalDC = D->getDeclContext();
}
+ else if (D->isLocalExternDecl()) {
+ LexicalDC = SemaRef.CurContext;
+ }
Function->setLexicalDeclContext(LexicalDC);
@@ -2260,7 +2269,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
- // tag type. Note that this does does not apply if we're declaring a
+ // tag type. Note that this does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
if (Previous.isSingleTagDecl())
Previous.clear();
@@ -2268,9 +2277,42 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
// Filter out previous declarations that don't match the scope. The only
// effect this has is to remove declarations found in inline namespaces
// for friend declarations with unqualified names.
- SemaRef.FilterLookupForScope(Previous, DC, /*Scope*/ nullptr,
- /*ConsiderLinkage*/ true,
- QualifierLoc.hasQualifier());
+ if (isFriend && !QualifierLoc && !FunctionTemplate) {
+ SemaRef.FilterLookupForScope(Previous, DC, /*Scope=*/ nullptr,
+ /*ConsiderLinkage=*/ true,
+ QualifierLoc.hasQualifier());
+ }
+ }
+
+ // Per [temp.inst], default arguments in function declarations at local scope
+ // are instantiated along with the enclosing declaration. For example:
+ //
+ // template<typename T>
+ // void ft() {
+ // void f(int = []{ return T::value; }());
+ // }
+ // template void ft<int>(); // error: type 'int' cannot be used prior
+ // to '::' because it has no members
+ //
+ // The error is issued during instantiation of ft<int>() because substitution
+ // into the default argument fails; the default argument is instantiated even
+ // though it is never used.
+ if (Function->isLocalExternDecl()) {
+ for (ParmVarDecl *PVD : Function->parameters()) {
+ if (!PVD->hasDefaultArg())
+ continue;
+ if (SemaRef.SubstDefaultArgument(D->getInnerLocStart(), PVD, TemplateArgs)) {
+ // If substitution fails, the default argument is set to a
+ // RecoveryExpr that wraps the uninstantiated default argument so
+ // that downstream diagnostics are omitted.
+ Expr *UninstExpr = PVD->getUninstantiatedDefaultArg();
+ ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+ UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+ { UninstExpr }, UninstExpr->getType());
+ if (ErrorResult.isUsable())
+ PVD->setDefaultArg(ErrorResult.get());
+ }
+ }
}
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
@@ -2331,7 +2373,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
CXXMethodDecl *D, TemplateParameterList *TemplateParams,
- Optional<const ASTTemplateArgumentListInfo *> ClassScopeSpecializationArgs,
+ std::optional<const ASTTemplateArgumentListInfo *>
+ ClassScopeSpecializationArgs,
RewriteKind FunctionRewriteKind) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
if (FunctionTemplate && !TemplateParams) {
@@ -2425,23 +2468,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
return nullptr;
}
- // FIXME: Concepts: Do not substitute into constraint expressions
- Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
- if (TrailingRequiresClause) {
- EnterExpressionEvaluationContext ConstantEvaluated(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
- auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner);
- Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext,
- D->getMethodQualifiers(), ThisContext);
- ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause,
- TemplateArgs);
- if (SubstRC.isInvalid())
- return nullptr;
- TrailingRequiresClause = SubstRC.get();
- if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause))
- return nullptr;
- }
-
DeclContext *DC = Owner;
if (isFriend) {
if (QualifierLoc) {
@@ -2459,6 +2485,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (!DC) return nullptr;
}
+ CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+ Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
@@ -2466,7 +2495,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo);
// Build the instantiated method declaration.
- CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
CXXMethodDecl *Method = nullptr;
SourceLocation StartLoc = D->getInnerLocStart();
@@ -2478,6 +2506,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
Constructor->getConstexprKind(), InheritedConstructor(),
TrailingRequiresClause);
Method->setRangeEnd(Constructor->getEndLoc());
+ if (Constructor->isDefaultConstructor() ||
+ Constructor->isCopyOrMoveConstructor())
+ Method->setIneligibleOrNotSelected(true);
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
@@ -2500,6 +2531,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, SC,
D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(),
D->getEndLoc(), TrailingRequiresClause);
+ if (D->isMoveAssignmentOperator() || D->isCopyAssignmentOperator())
+ Method->setIneligibleOrNotSelected(true);
}
if (D->isInlined())
@@ -2551,7 +2584,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
if (NumTempParamLists)
Method->setTemplateParameterListsInfo(
SemaRef.Context,
- llvm::makeArrayRef(TempParamLists.data(), NumTempParamLists));
+ llvm::ArrayRef(TempParamLists.data(), NumTempParamLists));
Method->setLexicalDeclContext(Owner);
Method->setObjectOfFriendDecl();
@@ -2630,12 +2663,45 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
- // tag type. Note that this does does not apply if we're declaring a
+ // tag type. Note that this does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
if (Previous.isSingleTagDecl())
Previous.clear();
}
+ // Per [temp.inst], default arguments in member functions of local classes
+ // are instantiated along with the member function declaration. For example:
+ //
+ // template<typename T>
+ // void ft() {
+ // struct lc {
+ // int operator()(int p = []{ return T::value; }());
+ // };
+ // }
+ // template void ft<int>(); // error: type 'int' cannot be used prior
+ // to '::'because it has no members
+ //
+ // The error is issued during instantiation of ft<int>()::lc::operator()
+ // because substitution into the default argument fails; the default argument
+ // is instantiated even though it is never used.
+ if (D->isInLocalScopeForInstantiation()) {
+ for (unsigned P = 0; P < Params.size(); ++P) {
+ if (!Params[P]->hasDefaultArg())
+ continue;
+ if (SemaRef.SubstDefaultArgument(StartLoc, Params[P], TemplateArgs)) {
+ // If substitution fails, the default argument is set to a
+ // RecoveryExpr that wraps the uninstantiated default argument so
+ // that downstream diagnostics are omitted.
+ Expr *UninstExpr = Params[P]->getUninstantiatedDefaultArg();
+ ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
+ UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
+ { UninstExpr }, UninstExpr->getType());
+ if (ErrorResult.isUsable())
+ Params[P]->setDefaultArg(ErrorResult.get());
+ }
+ }
+ }
+
SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
IsExplicitSpecialization,
Method->isThisDeclarationADefinition());
@@ -2723,15 +2789,16 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
}
Decl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, None,
- /*ExpectParameterPack=*/ false);
+ return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0,
+ std::nullopt,
+ /*ExpectParameterPack=*/false);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
TemplateTypeParmDecl *D) {
assert(D->getTypeForDecl()->isTemplateTypeParmType());
- Optional<unsigned> NumExpanded;
+ std::optional<unsigned> NumExpanded;
if (const TypeConstraint *TC = D->getTypeConstraint()) {
if (D->isPackExpansion() && !D->isExpandedParameterPack()) {
@@ -2771,13 +2838,11 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
Inst->setImplicit(D->isImplicit());
if (auto *TC = D->getTypeConstraint()) {
if (!D->isImplicit()) {
- // Invented template parameter type constraints will be instantiated with
- // the corresponding auto-typed parameter as it might reference other
- // parameters.
-
- // TODO: Concepts: do not instantiate the constraint (delayed constraint
- // substitution)
- if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs))
+ // Invented template parameter type constraints will be instantiated
+ // with the corresponding auto-typed parameter as it might reference
+ // other parameters.
+ if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs,
+ EvaluateConstraints))
return nullptr;
}
}
@@ -2844,9 +2909,9 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions
- = Expansion.getTypePtr()->getNumExpansions();
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions =
+ Expansion.getTypePtr()->getNumExpansions();
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(),
Pattern.getSourceRange(),
Unexpanded,
@@ -3009,7 +3074,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
TempParams->getSourceRange(),
Unexpanded,
@@ -3235,9 +3300,11 @@ Decl *TemplateDeclInstantiator::VisitUsingEnumDecl(UsingEnumDecl *D) {
if (SemaRef.RequireCompleteEnumDecl(EnumD, EnumD->getLocation()))
return nullptr;
+ TypeSourceInfo *TSI = SemaRef.SubstType(D->getEnumType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
UsingEnumDecl *NewUD =
UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(),
- D->getEnumLoc(), D->getLocation(), EnumD);
+ D->getEnumLoc(), D->getLocation(), TSI);
SemaRef.Context.setInstantiatedFromUsingEnumDecl(NewUD, D);
NewUD->setAccess(D->getAccess());
@@ -3278,7 +3345,7 @@ Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(
D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs,
Expand, RetainExpansion, NumExpansions))
@@ -3617,9 +3684,10 @@ TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
OMPVarListLocTy Locs(OldC->getBeginLoc(), OldC->getLParenLoc(),
OldC->getEndLoc());
OMPClause *NewC = SemaRef.ActOnOpenMPMapClause(
- OldC->getMapTypeModifiers(), OldC->getMapTypeModifiersLoc(), SS,
- NewNameInfo, OldC->getMapType(), OldC->isImplicitMapType(),
- OldC->getMapLoc(), OldC->getColonLoc(), NewVars, Locs);
+ OldC->getIteratorModifier(), OldC->getMapTypeModifiers(),
+ OldC->getMapTypeModifiersLoc(), SS, NewNameInfo, OldC->getMapType(),
+ OldC->isImplicitMapType(), OldC->getMapLoc(), OldC->getColonLoc(),
+ NewVars, Locs);
Clauses.push_back(NewC);
}
SemaRef.EndOpenMPDSABlock(nullptr);
@@ -3691,12 +3759,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Check that the template argument list is well-formed for this
// class template.
- SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(InstClassTemplate,
- D->getLocation(),
- InstTemplateArgs,
- false,
- Converted,
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, D->getLocation(),
+ InstTemplateArgs, false,
+ SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return nullptr;
@@ -3704,7 +3770,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// in the member template's set of class template explicit specializations.
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl =
- InstClassTemplate->findSpecialization(Converted, InsertPos);
+ InstClassTemplate->findSpecialization(CanonicalConverted, InsertPos);
// Check whether we've already seen a conflicting instantiation of this
// declaration (for instance, if there was a prior implicit instantiation).
@@ -3742,7 +3808,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *InstD =
ClassTemplateSpecializationDecl::Create(
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
- D->getLocation(), InstClassTemplate, Converted, PrevDecl);
+ D->getLocation(), InstClassTemplate, CanonicalConverted, PrevDecl);
// Add this partial specialization to the set of class template partial
// specializations.
@@ -3756,7 +3822,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Build the canonical type that describes the converted template
// arguments of the class template explicit specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
- TemplateName(InstClassTemplate), Converted,
+ TemplateName(InstClassTemplate), CanonicalConverted,
SemaRef.Context.getRecordType(InstD));
// Build the fully-sugared type for this class template
@@ -3818,16 +3884,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
}
// Check that the template argument list is well-formed for this template.
- SmallVector<TemplateArgument, 4> Converted;
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(),
- VarTemplateArgsInfo, false, Converted,
+ VarTemplateArgsInfo, false,
+ SugaredConverted, CanonicalConverted,
/*UpdateArgsWithConversions=*/true))
return nullptr;
// Check whether we've already seen a declaration of this specialization.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
- InstVarTemplate->findSpecialization(Converted, InsertPos);
+ InstVarTemplate->findSpecialization(CanonicalConverted, InsertPos);
// Check whether we've already seen a conflicting instantiation of this
// declaration (for instance, if there was a prior implicit instantiation).
@@ -3839,7 +3906,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
return nullptr;
return VisitVarTemplateSpecializationDecl(
- InstVarTemplate, D, VarTemplateArgsInfo, Converted, PrevDecl);
+ InstVarTemplate, D, VarTemplateArgsInfo, CanonicalConverted, PrevDecl);
}
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
@@ -3904,6 +3971,11 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
llvm_unreachable("Concept definitions cannot reside inside a template");
}
+Decl *TemplateDeclInstantiator::VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D) {
+ llvm_unreachable("Concept specializations cannot reside inside a template");
+}
+
Decl *
TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(),
@@ -3975,7 +4047,7 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD,
Decl *R;
if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) {
R = Instantiator.VisitCXXMethodDecl(
- MD, nullptr, None,
+ MD, nullptr, std::nullopt,
TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
} else {
assert(Spaceship->getFriendObjectKind() &&
@@ -4021,18 +4093,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
if (Invalid)
return nullptr;
- // FIXME: Concepts: Substitution into requires clause should only happen when
- // checking satisfaction.
- Expr *InstRequiresClause = nullptr;
- if (Expr *E = L->getRequiresClause()) {
- EnterExpressionEvaluationContext ConstantEvaluated(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
- ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);
- if (Res.isInvalid() || !Res.isUsable()) {
- return nullptr;
- }
- InstRequiresClause = Res.get();
- }
+ Expr *InstRequiresClause = L->getRequiresClause();
TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
@@ -4043,8 +4104,10 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
TemplateParameterList *
Sema::SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool EvaluateConstraints) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
+ Instantiator.setEvaluateConstraints(EvaluateConstraints);
return Instantiator.SubstTemplateParams(Params);
}
@@ -4087,32 +4150,29 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// Check that the template argument list is well-formed for this
// class template.
- SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(ClassTemplate,
- PartialSpec->getLocation(),
- InstTemplateArgs,
- false,
- Converted))
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (SemaRef.CheckTemplateArgumentList(
+ ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs,
+ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted))
return nullptr;
// Check these arguments are valid for a template partial specialization.
if (SemaRef.CheckTemplatePartialSpecializationArgs(
PartialSpec->getLocation(), ClassTemplate, InstTemplateArgs.size(),
- Converted))
+ CanonicalConverted))
return nullptr;
// Figure out where to insert this class template partial specialization
// in the member template's set of class template partial specializations.
void *InsertPos = nullptr;
- ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->findPartialSpecialization(Converted, InstParams,
+ ClassTemplateSpecializationDecl *PrevDecl =
+ ClassTemplate->findPartialSpecialization(CanonicalConverted, InstParams,
InsertPos);
// Build the canonical type that describes the converted template
// arguments of the class template partial specialization.
- QualType CanonType
- = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
- Converted);
+ QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
+ TemplateName(ClassTemplate), CanonicalConverted);
// Build the fully-sugared type for this class template
// specialization as the user wrote in the specialization
@@ -4157,7 +4217,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
ClassTemplatePartialSpecializationDecl::Create(
SemaRef.Context, PartialSpec->getTagKind(), Owner,
PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams,
- ClassTemplate, Converted, InstTemplateArgs, CanonType, nullptr);
+ ClassTemplate, CanonicalConverted, InstTemplateArgs, CanonType,
+ nullptr);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
return nullptr;
@@ -4214,27 +4275,29 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
// Check that the template argument list is well-formed for this
// class template.
- SmallVector<TemplateArgument, 4> Converted;
- if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(),
- InstTemplateArgs, false, Converted))
+ SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
+ if (SemaRef.CheckTemplateArgumentList(
+ VarTemplate, PartialSpec->getLocation(), InstTemplateArgs,
+ /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted))
return nullptr;
// Check these arguments are valid for a template partial specialization.
if (SemaRef.CheckTemplatePartialSpecializationArgs(
PartialSpec->getLocation(), VarTemplate, InstTemplateArgs.size(),
- Converted))
+ CanonicalConverted))
return nullptr;
// Figure out where to insert this variable template partial specialization
// in the member template's set of variable template partial specializations.
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
- VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos);
+ VarTemplate->findPartialSpecialization(CanonicalConverted, InstParams,
+ InsertPos);
// Build the canonical type that describes the converted template
// arguments of the variable template partial specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
- TemplateName(VarTemplate), Converted);
+ TemplateName(VarTemplate), CanonicalConverted);
// Build the fully-sugared type for this variable template
// specialization as the user wrote in the specialization
@@ -4290,7 +4353,8 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplatePartialSpecializationDecl::Create(
SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(),
- DI, PartialSpec->getStorageClass(), Converted, InstTemplateArgs);
+ DI, PartialSpec->getStorageClass(), CanonicalConverted,
+ InstTemplateArgs);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
@@ -4326,11 +4390,9 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
ThisTypeQuals = Method->getMethodQualifiers();
}
- TypeSourceInfo *NewTInfo
- = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs,
- D->getTypeSpecStartLoc(),
- D->getDeclName(),
- ThisContext, ThisTypeQuals);
+ TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType(
+ OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName(),
+ ThisContext, ThisTypeQuals, EvaluateConstraints);
if (!NewTInfo)
return nullptr;
@@ -4349,7 +4411,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
- Optional<unsigned> NumArgumentsInExpansion;
+ std::optional<unsigned> NumArgumentsInExpansion;
if (OldParam->isParameterPack())
NumArgumentsInExpansion =
SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
@@ -4451,7 +4513,7 @@ bool Sema::addInstantiatedParametersToScope(
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
- Optional<unsigned> NumArgumentsInExpansion =
+ std::optional<unsigned> NumArgumentsInExpansion =
getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
if (NumArgumentsInExpansion) {
QualType PatternType =
@@ -4481,10 +4543,6 @@ bool Sema::addInstantiatedParametersToScope(
bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
assert(Param->hasUninstantiatedDefaultArg());
- Expr *UninstExpr = Param->getUninstantiatedDefaultArg();
-
- EnterExpressionEvaluationContext EvalContext(
- *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param);
// Instantiate the expression.
//
@@ -4503,62 +4561,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
- MultiLevelTemplateArgumentList TemplateArgs
- = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ FD, /*Final=*/false, nullptr, /*RelativeToPrimary=*/true);
- InstantiatingTemplate Inst(*this, CallLoc, Param,
- TemplateArgs.getInnermost());
- if (Inst.isInvalid())
+ if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
- if (Inst.isAlreadyInstantiating()) {
- Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD;
- Param->setInvalidDecl();
- return true;
- }
- ExprResult Result;
- {
- // C++ [dcl.fct.default]p5:
- // The names in the [default argument] expression are bound, and
- // the semantic constraints are checked, at the point where the
- // default argument expression appears.
- ContextRAII SavedContext(*this, FD);
- LocalInstantiationScope Local(*this);
-
- FunctionDecl *Pattern = FD->getTemplateInstantiationPattern(
- /*ForDefinition*/ false);
- if (addInstantiatedParametersToScope(FD, Pattern, Local, TemplateArgs))
- return true;
-
- runWithSufficientStackSpace(CallLoc, [&] {
- Result = SubstInitializer(UninstExpr, TemplateArgs,
- /*DirectInit*/false);
- });
- }
- if (Result.isInvalid())
- return true;
-
- // Check the expression as an initializer for the parameter.
- InitializedEntity Entity
- = InitializedEntity::InitializeParameter(Context, Param);
- InitializationKind Kind = InitializationKind::CreateCopy(
- Param->getLocation(),
- /*FIXME:EqualLoc*/ UninstExpr->getBeginLoc());
- Expr *ResultE = Result.getAs<Expr>();
-
- InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
- Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
- if (Result.isInvalid())
- return true;
-
- Result =
- ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(),
- /*DiscardedValue*/ false);
- if (Result.isInvalid())
- return true;
-
- // Remember the instantiated default argument.
- Param->setDefaultArg(Result.getAs<Expr>());
if (ASTMutationListener *L = getASTMutationListener())
L->DefaultArgumentInstantiated(Param);
@@ -4592,8 +4600,8 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
Sema::ContextRAII savedContext(*this, Decl);
LocalInstantiationScope Scope(*this);
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ Decl, /*Final=*/false, nullptr, /*RelativeToPrimary*/ true);
// FIXME: We can't use getTemplateInstantiationPattern(false) in general
// here, because for a non-defining friend declaration in a class template,
@@ -4767,7 +4775,8 @@ Sema::InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
return nullptr;
ContextRAII SavedContext(*this, FD);
- MultiLevelTemplateArgumentList MArgs(*Args);
+ MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(),
+ /*Final=*/false);
return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs));
}
@@ -5033,8 +5042,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
RebuildTypeSourceInfoForDefaultSpecialMembers();
SetDeclDefaulted(Function, PatternDecl->getLocation());
} else {
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ Function, /*Final=*/false, nullptr, false, PatternDecl);
// Substitute into the qualifier; we can get a substitution failure here
// through evil use of alias templates.
@@ -5103,8 +5112,7 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
const TemplateArgumentList &TemplateArgList,
const TemplateArgumentListInfo &TemplateArgsInfo,
SmallVectorImpl<TemplateArgument> &Converted,
- SourceLocation PointOfInstantiation,
- LateInstantiatedAttrVec *LateAttrs,
+ SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *StartingScope) {
if (FromVar->isInvalidDecl())
return nullptr;
@@ -5113,9 +5121,6 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
if (Inst.isInvalid())
return nullptr;
- MultiLevelTemplateArgumentList TemplateArgLists;
- TemplateArgLists.addOuterTemplateArguments(&TemplateArgList);
-
// Instantiate the first declaration of the variable template: for a partial
// specialization of a static data member template, the first declaration may
// or may not be the declaration in the class; if it's in the class, we want
@@ -5126,15 +5131,21 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
// partial specialization, don't do this. The member specialization completely
// replaces the original declaration in this case.
bool IsMemberSpec = false;
- if (VarTemplatePartialSpecializationDecl *PartialSpec =
- dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar))
+ MultiLevelTemplateArgumentList MultiLevelList;
+ if (auto *PartialSpec =
+ dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar)) {
IsMemberSpec = PartialSpec->isMemberSpecialization();
- else if (VarTemplateDecl *FromTemplate = FromVar->getDescribedVarTemplate())
- IsMemberSpec = FromTemplate->isMemberSpecialization();
+ MultiLevelList.addOuterTemplateArguments(
+ PartialSpec, TemplateArgList.asArray(), /*Final=*/false);
+ } else {
+ assert(VarTemplate == FromVar->getDescribedVarTemplate());
+ IsMemberSpec = VarTemplate->isMemberSpecialization();
+ MultiLevelList.addOuterTemplateArguments(
+ VarTemplate, TemplateArgList.asArray(), /*Final=*/false);
+ }
if (!IsMemberSpec)
FromVar = FromVar->getFirstDecl();
- MultiLevelTemplateArgumentList MultiLevelList(TemplateArgList);
TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(),
MultiLevelList);
@@ -5633,7 +5644,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
collectUnexpandedParameterPacks(Init->getInit(), Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
BaseTL.getSourceRange(),
Unexpanded,
@@ -6147,7 +6158,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// Move to the outer template scope.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) {
- if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){
+ if (FD->getFriendObjectKind() &&
+ FD->getNonTransparentDeclContext()->isFileContext()) {
DC = FD->getLexicalDeclContext();
continue;
}
@@ -6388,7 +6400,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
void Sema::PerformDependentDiagnostics(const DeclContext *Pattern,
const MultiLevelTemplateArgumentList &TemplateArgs) {
- for (auto DD : Pattern->ddiags()) {
+ for (auto *DD : Pattern->ddiags()) {
switch (DD->getKind()) {
case DependentDiagnostic::Access:
HandleDependentAccessCheck(*DD, TemplateArgs);
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 790792f77b24..01a435668d88 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -18,6 +18,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
+#include <optional>
using namespace clang;
@@ -88,6 +89,23 @@ namespace {
return true;
}
+ bool
+ VisitSubstTemplateTypeParmPackTypeLoc(SubstTemplateTypeParmPackTypeLoc TL) {
+ Unexpanded.push_back({TL.getTypePtr(), TL.getNameLoc()});
+ return true;
+ }
+
+ bool VisitSubstTemplateTypeParmPackType(SubstTemplateTypeParmPackType *T) {
+ Unexpanded.push_back({T, SourceLocation()});
+ return true;
+ }
+
+ bool
+ VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E) {
+ Unexpanded.push_back({E, E->getParameterPackLocation()});
+ return true;
+ }
+
/// Record occurrences of function and non-type template
/// parameter packs in an expression.
bool VisitDeclRefExpr(DeclRefExpr *E) {
@@ -306,7 +324,8 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack);
return TTPD && TTPD->getTypeForDecl() == TTPT;
}
- return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
+ return declaresSameEntity(Pack.first.get<const NamedDecl *>(),
+ LocalPack);
};
if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack))
LambdaParamPackReferences.push_back(Pack);
@@ -358,7 +377,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>())
Name = TTP->getIdentifier();
else
- Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier();
+ Name = Unexpanded[I].first.get<const NamedDecl *>()->getIdentifier();
if (Name && NamesKnown.insert(Name).second)
Names.push_back(Name);
@@ -421,7 +440,7 @@ bool Sema::DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE) {
llvm::SmallPtrSet<NamedDecl*, 8> ParmSet(Parms.begin(), Parms.end());
SmallVector<UnexpandedParameterPack, 2> UnexpandedParms;
for (auto Parm : Unexpanded)
- if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl*>()))
+ if (ParmSet.contains(Parm.first.dyn_cast<const NamedDecl *>()))
UnexpandedParms.push_back(Parm);
if (UnexpandedParms.empty())
return false;
@@ -594,7 +613,8 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type,
if (!TSInfo)
return true;
- TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc, None);
+ TypeSourceInfo *TSResult =
+ CheckPackExpansion(TSInfo, EllipsisLoc, std::nullopt);
if (!TSResult)
return true;
@@ -603,7 +623,7 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type,
TypeSourceInfo *
Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
// Create the pack expansion type and source-location information.
QualType Result = CheckPackExpansion(Pattern->getType(),
Pattern->getTypeLoc().getSourceRange(),
@@ -621,7 +641,7 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
// C++11 [temp.variadic]p5:
// The pattern of a pack expansion shall name one or more
// parameter packs that are not expanded by a nested pack
@@ -641,11 +661,11 @@ QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
}
ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) {
- return CheckPackExpansion(Pattern, EllipsisLoc, None);
+ return CheckPackExpansion(Pattern, EllipsisLoc, std::nullopt);
}
ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
if (!Pattern)
return ExprError();
@@ -669,112 +689,98 @@ bool Sema::CheckParameterPacksForExpansion(
SourceLocation EllipsisLoc, SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
- bool &RetainExpansion, Optional<unsigned> &NumExpansions) {
+ bool &RetainExpansion, std::optional<unsigned> &NumExpansions) {
ShouldExpand = true;
RetainExpansion = false;
- std::pair<IdentifierInfo *, SourceLocation> FirstPack;
- bool HaveFirstPack = false;
- Optional<unsigned> NumPartialExpansions;
- SourceLocation PartiallySubstitutedPackLoc;
+ std::pair<const IdentifierInfo *, SourceLocation> FirstPack;
+ std::optional<std::pair<unsigned, SourceLocation>> PartialExpansion;
+ std::optional<unsigned> CurNumExpansions;
- for (UnexpandedParameterPack ParmPack : Unexpanded) {
+ for (auto [P, Loc] : Unexpanded) {
// Compute the depth and index for this parameter pack.
- unsigned Depth = 0, Index = 0;
- IdentifierInfo *Name;
- bool IsVarDeclPack = false;
-
- if (const TemplateTypeParmType *TTP =
- ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
- Depth = TTP->getDepth();
- Index = TTP->getIndex();
- Name = TTP->getIdentifier();
- } else {
- NamedDecl *ND = ParmPack.first.get<NamedDecl *>();
- if (isa<VarDecl>(ND))
- IsVarDeclPack = true;
- else
- std::tie(Depth, Index) = getDepthAndIndex(ND);
-
- Name = ND->getIdentifier();
- }
-
- // Determine the size of this argument pack.
+ std::optional<std::pair<unsigned, unsigned>> Pos;
unsigned NewPackSize;
- if (IsVarDeclPack) {
- // Figure out whether we're instantiating to an argument pack or not.
- typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
-
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
- CurrentInstantiationScope->findInstantiationOf(
- ParmPack.first.get<NamedDecl *>());
- if (Instantiation->is<DeclArgumentPack *>()) {
- // We could expand this function parameter pack.
- NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
- } else {
+ const auto *ND = P.dyn_cast<const NamedDecl *>();
+ if (ND && isa<VarDecl>(ND)) {
+ const auto *DAP =
+ CurrentInstantiationScope->findInstantiationOf(ND)
+ ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>();
+ if (!DAP) {
// We can't expand this function parameter pack, so we can't expand
// the pack expansion.
ShouldExpand = false;
continue;
}
+ NewPackSize = DAP->size();
+ } else if (ND) {
+ Pos = getDepthAndIndex(ND);
+ } else if (const auto *TTP = P.dyn_cast<const TemplateTypeParmType *>()) {
+ Pos = {TTP->getDepth(), TTP->getIndex()};
+ ND = TTP->getDecl();
+ // FIXME: We either should have some fallback for canonical TTP, or
+ // never have canonical TTP here.
+ } else if (const auto *STP =
+ P.dyn_cast<const SubstTemplateTypeParmPackType *>()) {
+ NewPackSize = STP->getNumArgs();
+ ND = STP->getReplacedParameter();
} else {
+ const auto *SEP = P.get<const SubstNonTypeTemplateParmPackExpr *>();
+ NewPackSize = SEP->getArgumentPack().pack_size();
+ ND = SEP->getParameterPack();
+ }
+
+ if (Pos) {
// If we don't have a template argument at this depth/index, then we
// cannot expand the pack expansion. Make a note of this, but we still
// want to check any parameter packs we *do* have arguments for.
- if (Depth >= TemplateArgs.getNumLevels() ||
- !TemplateArgs.hasTemplateArgument(Depth, Index)) {
+ if (Pos->first >= TemplateArgs.getNumLevels() ||
+ !TemplateArgs.hasTemplateArgument(Pos->first, Pos->second)) {
ShouldExpand = false;
continue;
}
-
// Determine the size of the argument pack.
- NewPackSize = TemplateArgs(Depth, Index).pack_size();
- }
-
- // C++0x [temp.arg.explicit]p9:
- // Template argument deduction can extend the sequence of template
- // arguments corresponding to a template parameter pack, even when the
- // sequence contains explicitly specified template arguments.
- if (!IsVarDeclPack && CurrentInstantiationScope) {
- if (NamedDecl *PartialPack
- = CurrentInstantiationScope->getPartiallySubstitutedPack()){
- unsigned PartialDepth, PartialIndex;
- std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
- if (PartialDepth == Depth && PartialIndex == Index) {
+ NewPackSize = TemplateArgs(Pos->first, Pos->second).pack_size();
+ // C++0x [temp.arg.explicit]p9:
+ // Template argument deduction can extend the sequence of template
+ // arguments corresponding to a template parameter pack, even when the
+ // sequence contains explicitly specified template arguments.
+ if (CurrentInstantiationScope)
+ if (const NamedDecl *PartialPack =
+ CurrentInstantiationScope->getPartiallySubstitutedPack();
+ PartialPack && getDepthAndIndex(PartialPack) == *Pos) {
RetainExpansion = true;
// We don't actually know the new pack size yet.
- NumPartialExpansions = NewPackSize;
- PartiallySubstitutedPackLoc = ParmPack.second;
+ PartialExpansion = {NewPackSize, Loc};
continue;
}
- }
}
- if (!NumExpansions) {
+ // FIXME: Workaround for Canonical TTP.
+ const IdentifierInfo *Name = ND ? ND->getIdentifier() : nullptr;
+ if (!CurNumExpansions) {
// The is the first pack we've seen for which we have an argument.
// Record it.
- NumExpansions = NewPackSize;
- FirstPack.first = Name;
- FirstPack.second = ParmPack.second;
- HaveFirstPack = true;
- continue;
- }
-
- if (NewPackSize != *NumExpansions) {
+ CurNumExpansions = NewPackSize;
+ FirstPack = {Name, Loc};
+ } else if (NewPackSize != *CurNumExpansions) {
// C++0x [temp.variadic]p5:
// All of the parameter packs expanded by a pack expansion shall have
// the same number of arguments specified.
- if (HaveFirstPack)
- Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
- << FirstPack.first << Name << *NumExpansions << NewPackSize
- << SourceRange(FirstPack.second) << SourceRange(ParmPack.second);
- else
- Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
- << Name << *NumExpansions << NewPackSize
- << SourceRange(ParmPack.second);
+ Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
+ << FirstPack.first << Name << *CurNumExpansions << NewPackSize
+ << SourceRange(FirstPack.second) << SourceRange(Loc);
return true;
}
}
+ if (NumExpansions && CurNumExpansions &&
+ *NumExpansions != *CurNumExpansions) {
+ Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
+ << FirstPack.first << *CurNumExpansions << *NumExpansions
+ << SourceRange(FirstPack.second);
+ return true;
+ }
+
// If we're performing a partial expansion but we also have a full expansion,
// expand to the number of common arguments. For example, given:
//
@@ -784,70 +790,72 @@ bool Sema::CheckParameterPacksForExpansion(
//
// ... a call to 'A<int, int>().f<int>' should expand the pack once and
// retain an expansion.
- if (NumPartialExpansions) {
- if (NumExpansions && *NumExpansions < *NumPartialExpansions) {
+ if (PartialExpansion) {
+ if (CurNumExpansions && *CurNumExpansions < PartialExpansion->first) {
NamedDecl *PartialPack =
CurrentInstantiationScope->getPartiallySubstitutedPack();
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial)
- << PartialPack << *NumPartialExpansions << *NumExpansions
- << SourceRange(PartiallySubstitutedPackLoc);
+ << PartialPack << PartialExpansion->first << *CurNumExpansions
+ << SourceRange(PartialExpansion->second);
return true;
}
-
- NumExpansions = NumPartialExpansions;
+ NumExpansions = PartialExpansion->first;
+ } else {
+ NumExpansions = CurNumExpansions;
}
return false;
}
-Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
- const MultiLevelTemplateArgumentList &TemplateArgs) {
+std::optional<unsigned> Sema::getNumArgumentsInExpansion(
+ QualType T, const MultiLevelTemplateArgumentList &TemplateArgs) {
QualType Pattern = cast<PackExpansionType>(T)->getPattern();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
- Optional<unsigned> Result;
- for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
- // Compute the depth and index for this parameter pack.
- unsigned Depth;
- unsigned Index;
+ std::optional<unsigned> Result;
+ auto setResultSz = [&Result](unsigned Size) {
+ assert((!Result || *Result == Size) && "inconsistent pack sizes");
+ Result = Size;
+ };
+ auto setResultPos = [&](const std::pair<unsigned, unsigned> &Pos) -> bool {
+ unsigned Depth = Pos.first, Index = Pos.second;
+ if (Depth >= TemplateArgs.getNumLevels() ||
+ !TemplateArgs.hasTemplateArgument(Depth, Index))
+ // The pattern refers to an unknown template argument. We're not ready to
+ // expand this pack yet.
+ return true;
+ // Determine the size of the argument pack.
+ setResultSz(TemplateArgs(Depth, Index).pack_size());
+ return false;
+ };
- if (const TemplateTypeParmType *TTP
- = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
- Depth = TTP->getDepth();
- Index = TTP->getIndex();
+ for (auto [I, _] : Unexpanded) {
+ if (const auto *TTP = I.dyn_cast<const TemplateTypeParmType *>()) {
+ if (setResultPos({TTP->getDepth(), TTP->getIndex()}))
+ return std::nullopt;
+ } else if (const auto *STP =
+ I.dyn_cast<const SubstTemplateTypeParmPackType *>()) {
+ setResultSz(STP->getNumArgs());
+ } else if (const auto *SEP =
+ I.dyn_cast<const SubstNonTypeTemplateParmPackExpr *>()) {
+ setResultSz(SEP->getArgumentPack().pack_size());
} else {
- NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
+ const auto *ND = I.get<const NamedDecl *>();
+ // Function parameter pack or init-capture pack.
if (isa<VarDecl>(ND)) {
- // Function parameter pack or init-capture pack.
- typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
-
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
- = CurrentInstantiationScope->findInstantiationOf(
- Unexpanded[I].first.get<NamedDecl *>());
- if (Instantiation->is<Decl*>())
+ const auto *DAP =
+ CurrentInstantiationScope->findInstantiationOf(ND)
+ ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>();
+ if (!DAP)
// The pattern refers to an unexpanded pack. We're not ready to expand
// this pack yet.
- return None;
-
- unsigned Size = Instantiation->get<DeclArgumentPack *>()->size();
- assert((!Result || *Result == Size) && "inconsistent pack sizes");
- Result = Size;
- continue;
+ return std::nullopt;
+ setResultSz(DAP->size());
+ } else if (setResultPos(getDepthAndIndex(ND))) {
+ return std::nullopt;
}
-
- std::tie(Depth, Index) = getDepthAndIndex(ND);
}
- if (Depth >= TemplateArgs.getNumLevels() ||
- !TemplateArgs.hasTemplateArgument(Depth, Index))
- // The pattern refers to an unknown template argument. We're not ready to
- // expand this pack yet.
- return None;
-
- // Determine the size of the argument pack.
- unsigned Size = TemplateArgs(Depth, Index).pack_size();
- assert((!Result || *Result == Size) && "inconsistent pack sizes");
- Result = Size;
}
return Result;
@@ -857,8 +865,10 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
const DeclSpec &DS = D.getDeclSpec();
switch (DS.getTypeSpecType()) {
case TST_typename:
+ case TST_typeof_unqualType:
case TST_typeofType:
- case TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
case TST_atomic: {
QualType T = DS.getRepAsType().get();
if (!T.isNull() && T->containsUnexpandedParameterPack())
@@ -866,6 +876,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
break;
}
+ case TST_typeof_unqualExpr:
case TST_typeofExpr:
case TST_decltype:
case TST_bitint:
@@ -1049,10 +1060,9 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
RParenLoc);
}
-TemplateArgumentLoc
-Sema::getTemplateArgumentPackExpansionPattern(
- TemplateArgumentLoc OrigLoc,
- SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions) const {
+TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern(
+ TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis,
+ std::optional<unsigned> &NumExpansions) const {
const TemplateArgument &Argument = OrigLoc.getArgument();
assert(Argument.isPackExpansion());
switch (Argument.getKind()) {
@@ -1109,7 +1119,7 @@ Sema::getTemplateArgumentPackExpansionPattern(
llvm_unreachable("Invalid TemplateArgument Kind!");
}
-Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
+std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
assert(Arg.containsUnexpandedParameterPack());
// If this is a substituted pack, grab that pack. If not, we don't know
@@ -1123,7 +1133,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>())
Pack = Subst->getArgumentPack();
else
- return None;
+ return std::nullopt;
break;
case TemplateArgument::Expression:
@@ -1133,10 +1143,10 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) {
for (VarDecl *PD : *Subst)
if (PD->isParameterPack())
- return None;
+ return std::nullopt;
return Subst->getNumExpansions();
} else
- return None;
+ return std::nullopt;
break;
case TemplateArgument::Template:
@@ -1144,7 +1154,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack())
Pack = Subst->getArgumentPack();
else
- return None;
+ return std::nullopt;
break;
case TemplateArgument::Declaration:
@@ -1153,7 +1163,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
case TemplateArgument::Integral:
case TemplateArgument::Pack:
case TemplateArgument::Null:
- return None;
+ return std::nullopt;
}
// Check that no argument in the pack is itself a pack expansion.
@@ -1161,7 +1171,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
// There's no point recursing in this case; we would have already
// expanded this pack expansion into the enclosing pack if we could.
if (Elem.isPackExpansion())
- return None;
+ return std::nullopt;
}
return Pack.pack_size();
}
@@ -1242,7 +1252,7 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
}
return BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc,
- None);
+ std::nullopt);
}
ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,
@@ -1250,7 +1260,7 @@ ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee,
BinaryOperatorKind Operator,
SourceLocation EllipsisLoc, Expr *RHS,
SourceLocation RParenLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
return new (Context)
CXXFoldExpr(Context.DependentTy, Callee, LParenLoc, LHS, Operator,
EllipsisLoc, RHS, RParenLoc, NumExpansions);
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 3ab5d26a9a75..89d819a77dcb 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -19,9 +19,11 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -33,12 +35,13 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include <bitset>
+#include <optional>
using namespace clang;
@@ -430,7 +433,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator,
if (onlyBlockPointers)
continue;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorChunk::BlockPointer:
result = &ptrChunk;
@@ -759,7 +762,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
/*NumExceptions=*/0,
/*NoexceptExpr=*/nullptr,
/*ExceptionSpecTokens=*/nullptr,
- /*DeclsInPrototype=*/None, loc, loc, declarator));
+ /*DeclsInPrototype=*/std::nullopt, loc, loc, declarator));
// For consistency, make sure the state still has us as processing
// the decl spec.
@@ -827,8 +830,8 @@ static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator,
/// Apply Objective-C type arguments to the given type.
static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
ArrayRef<TypeSourceInfo *> typeArgs,
- SourceRange typeArgsRange,
- bool failOnError = false) {
+ SourceRange typeArgsRange, bool failOnError,
+ bool rebuilding) {
// We can only apply type arguments to an Objective-C class type.
const auto *objcObjectType = type->getAs<ObjCObjectType>();
if (!objcObjectType || !objcObjectType->getInterface()) {
@@ -892,7 +895,9 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
}
}
- if (!diagnosed) {
+ // When rebuilding, qualifiers might have gotten here through a
+ // final substitution.
+ if (!rebuilding && !diagnosed) {
S.Diag(qual.getBeginLoc(), diag::err_objc_type_arg_qualified)
<< typeArg << typeArg.getQualifiers().getAsString()
<< FixItHint::CreateRemoval(rangeToRemove);
@@ -1054,22 +1059,18 @@ QualType Sema::BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl,
return Result;
}
-QualType Sema::BuildObjCObjectType(QualType BaseType,
- SourceLocation Loc,
- SourceLocation TypeArgsLAngleLoc,
- ArrayRef<TypeSourceInfo *> TypeArgs,
- SourceLocation TypeArgsRAngleLoc,
- SourceLocation ProtocolLAngleLoc,
- ArrayRef<ObjCProtocolDecl *> Protocols,
- ArrayRef<SourceLocation> ProtocolLocs,
- SourceLocation ProtocolRAngleLoc,
- bool FailOnError) {
+QualType Sema::BuildObjCObjectType(
+ QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc,
+ ArrayRef<TypeSourceInfo *> TypeArgs, SourceLocation TypeArgsRAngleLoc,
+ SourceLocation ProtocolLAngleLoc, ArrayRef<ObjCProtocolDecl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc,
+ bool FailOnError, bool Rebuilding) {
QualType Result = BaseType;
if (!TypeArgs.empty()) {
- Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs,
- SourceRange(TypeArgsLAngleLoc,
- TypeArgsRAngleLoc),
- FailOnError);
+ Result =
+ applyObjCTypeArgs(*this, Loc, Result, TypeArgs,
+ SourceRange(TypeArgsLAngleLoc, TypeArgsRAngleLoc),
+ FailOnError, Rebuilding);
if (FailOnError && Result.isNull())
return QualType();
}
@@ -1097,11 +1098,10 @@ TypeResult Sema::actOnObjCProtocolQualifierType(
SourceLocation rAngleLoc) {
// Form id<protocol-list>.
QualType Result = Context.getObjCObjectType(
- Context.ObjCBuiltinIdTy, { },
- llvm::makeArrayRef(
- (ObjCProtocolDecl * const *)protocols.data(),
- protocols.size()),
- false);
+ Context.ObjCBuiltinIdTy, {},
+ llvm::ArrayRef((ObjCProtocolDecl *const *)protocols.data(),
+ protocols.size()),
+ false);
Result = Context.getObjCObjectPointerType(Result);
TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
@@ -1168,10 +1168,11 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
T, BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(),
TypeArgsLAngleLoc, ActualTypeArgInfos, TypeArgsRAngleLoc,
ProtocolLAngleLoc,
- llvm::makeArrayRef((ObjCProtocolDecl * const *)Protocols.data(),
- Protocols.size()),
+ llvm::ArrayRef((ObjCProtocolDecl *const *)Protocols.data(),
+ Protocols.size()),
ProtocolLocs, ProtocolRAngleLoc,
- /*FailOnError=*/false);
+ /*FailOnError=*/false,
+ /*Rebuilding=*/false);
if (Result == T)
return BaseType;
@@ -1247,6 +1248,18 @@ getImageAccess(const ParsedAttributesView &Attrs) {
return OpenCLAccessAttr::Keyword_read_only;
}
+static UnaryTransformType::UTTKind
+TSTToUnaryTransformType(DeclSpec::TST SwitchTST) {
+ switch (SwitchTST) {
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ case TST_##Trait: \
+ return UnaryTransformType::Enum;
+#include "clang/Basic/TransformTypeTraits.def"
+ default:
+ llvm_unreachable("attempted to parse a non-unary transform builtin");
+ }
+}
+
/// Convert the specified declspec to the appropriate type
/// object.
/// \param state Specifies the declarator containing the declaration specifier
@@ -1369,7 +1382,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclSpec::TST_int: {
if (DS.getTypeSpecSign() != TypeSpecifierSign::Unsigned) {
switch (DS.getTypeSpecWidth()) {
@@ -1575,6 +1588,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// TypeQuals handled by caller.
Result = Context.getTypeDeclType(D);
+ if (const auto *Using =
+ dyn_cast_or_null<UsingShadowDecl>(DS.getRepAsFoundDecl()))
+ Result = Context.getUsingType(Using, Result);
// In both C and C++, make an ElaboratedType.
ElaboratedTypeKeyword Keyword
@@ -1596,6 +1612,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// TypeQuals handled by caller.
break;
}
+ case DeclSpec::TST_typeof_unqualType:
case DeclSpec::TST_typeofType:
// FIXME: Preserve type source info.
Result = S.GetTypeFromParser(DS.getRepAsType());
@@ -1604,13 +1621,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (const TagType *TT = Result->getAs<TagType>())
S.DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc());
// TypeQuals handled by caller.
- Result = Context.getTypeOfType(Result);
+ Result = Context.getTypeOfType(
+ Result, DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualType
+ ? TypeOfKind::Unqualified
+ : TypeOfKind::Qualified);
break;
+ case DeclSpec::TST_typeof_unqualExpr:
case DeclSpec::TST_typeofExpr: {
Expr *E = DS.getRepAsExpr();
assert(E && "Didn't get an expression for typeof?");
// TypeQuals handled by caller.
- Result = S.BuildTypeofExprType(E);
+ Result = S.BuildTypeofExprType(E, DS.getTypeSpecType() ==
+ DeclSpec::TST_typeof_unqualExpr
+ ? TypeOfKind::Unqualified
+ : TypeOfKind::Qualified);
if (Result.isNull()) {
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -1628,12 +1652,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
}
- case DeclSpec::TST_underlyingType:
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
Result = S.GetTypeFromParser(DS.getRepAsType());
- assert(!Result.isNull() && "Didn't get a type for __underlying_type?");
- Result = S.BuildUnaryTransformType(Result,
- UnaryTransformType::EnumUnderlyingType,
- DS.getTypeSpecTypeLoc());
+ assert(!Result.isNull() && "Didn't get a type for the transformation?");
+ Result = S.BuildUnaryTransformType(
+ Result, TSTToUnaryTransformType(DS.getTypeSpecType()),
+ DS.getTypeSpecTypeLoc());
if (Result.isNull()) {
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -2158,7 +2183,7 @@ QualType Sema::BuildPointerType(QualType T,
return QualType();
}
- if (getLangOpts().HLSL) {
+ if (getLangOpts().HLSL && Loc.isValid()) {
Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0;
return QualType();
}
@@ -2228,7 +2253,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return QualType();
}
- if (getLangOpts().HLSL) {
+ if (getLangOpts().HLSL && Loc.isValid()) {
Diag(Loc, diag::err_hlsl_pointers_unsupported) << 1;
return QualType();
}
@@ -2379,6 +2404,23 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize,
return R;
}
+bool Sema::checkArrayElementAlignment(QualType EltTy, SourceLocation Loc) {
+ EltTy = Context.getBaseElementType(EltTy);
+ if (EltTy->isIncompleteType() || EltTy->isDependentType() ||
+ EltTy->isUndeducedType())
+ return true;
+
+ CharUnits Size = Context.getTypeSizeInChars(EltTy);
+ CharUnits Alignment = Context.getTypeAlignInChars(EltTy);
+
+ if (Size.isMultipleOf(Alignment))
+ return true;
+
+ Diag(Loc, diag::err_array_element_alignment)
+ << EltTy << Size.getQuantity() << Alignment.getQuantity();
+ return false;
+}
+
/// Build an array type.
///
/// \param T The type of each element in the array.
@@ -2462,6 +2504,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
return QualType();
}
+ if (!checkArrayElementAlignment(T, Loc))
+ return QualType();
+
// Do placeholder conversions on the array size expression.
if (ArraySize && ArraySize->hasPlaceholderType()) {
ExprResult Result = CheckPlaceholderExpr(ArraySize);
@@ -2584,12 +2629,10 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) {
// CUDA device code and some other targets don't support VLAs.
- targetDiag(Loc, (getLangOpts().CUDA && getLangOpts().CUDAIsDevice)
- ? diag::err_cuda_vla
- : diag::err_vla_unsupported)
- << ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice)
- ? CurrentCUDATarget()
- : CFT_InvalidTarget);
+ bool IsCUDADevice = (getLangOpts().CUDA && getLangOpts().CUDAIsDevice);
+ targetDiag(Loc,
+ IsCUDADevice ? diag::err_cuda_vla : diag::err_vla_unsupported)
+ << (IsCUDADevice ? CurrentCUDATarget() : 0);
}
// If this is not C99, diagnose array size modifiers on non-VLAs.
@@ -2621,17 +2664,28 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr,
// can't already be a vector.
if ((!CurType->isDependentType() &&
(!CurType->isBuiltinType() || CurType->isBooleanType() ||
- (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) ||
+ (!CurType->isIntegerType() && !CurType->isRealFloatingType())) &&
+ !CurType->isBitIntType()) ||
CurType->isArrayType()) {
Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType;
return QualType();
}
+ // Only support _BitInt elements with byte-sized power of 2 NumBits.
+ if (CurType->isBitIntType()) {
+ unsigned NumBits = CurType->getAs<BitIntType>()->getNumBits();
+ if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) {
+ Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type)
+ << (NumBits < 8);
+ return QualType();
+ }
+ }
if (SizeExpr->isTypeDependent() || SizeExpr->isValueDependent())
return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc,
VectorType::GenericVector);
- Optional<llvm::APSInt> VecSize = SizeExpr->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> VecSize =
+ SizeExpr->getIntegerConstantExpr(Context);
if (!VecSize) {
Diag(AttrLoc, diag::err_attribute_argument_type)
<< "vector_size" << AANT_ArgumentIntegerConstant
@@ -2697,8 +2751,19 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return QualType();
}
+ // Only support _BitInt elements with byte-sized power of 2 NumBits.
+ if (T->isBitIntType()) {
+ unsigned NumBits = T->getAs<BitIntType>()->getNumBits();
+ if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) {
+ Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type)
+ << (NumBits < 8);
+ return QualType();
+ }
+ }
+
if (!ArraySize->isTypeDependent() && !ArraySize->isValueDependent()) {
- Optional<llvm::APSInt> vecSize = ArraySize->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> vecSize =
+ ArraySize->getIntegerConstantExpr(Context);
if (!vecSize) {
Diag(AttrLoc, diag::err_attribute_argument_type)
<< "ext_vector_type" << AANT_ArgumentIntegerConstant
@@ -2744,8 +2809,9 @@ QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols,
return Context.getDependentSizedMatrixType(ElementTy, NumRows, NumCols,
AttrLoc);
- Optional<llvm::APSInt> ValueRows = NumRows->getIntegerConstantExpr(Context);
- Optional<llvm::APSInt> ValueColumns =
+ std::optional<llvm::APSInt> ValueRows =
+ NumRows->getIntegerConstantExpr(Context);
+ std::optional<llvm::APSInt> ValueColumns =
NumCols->getIntegerConstantExpr(Context);
auto const RowRange = NumRows->getSourceRange();
@@ -2810,7 +2876,8 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
}
// Functions cannot return half FP.
- if (T->isHalfType() && !getLangOpts().HalfArgsAndReturns) {
+ if (T->isHalfType() && !getLangOpts().NativeHalfArgsAndReturns &&
+ !Context.getTargetInfo().allowHalfArgsAndReturns()) {
Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 <<
FixItHint::CreateInsertion(Loc, "*");
return true;
@@ -2834,6 +2901,8 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
if (T.isVolatileQualified() && getLangOpts().CPlusPlus20)
Diag(Loc, diag::warn_deprecated_volatile_return) << T;
+ if (T.getAddressSpace() != LangAS::Default && getLangOpts().HLSL)
+ return true;
return false;
}
@@ -2916,7 +2985,8 @@ QualType Sema::BuildFunctionType(QualType T,
if (ParamType->isVoidType()) {
Diag(Loc, diag::err_param_with_void_type);
Invalid = true;
- } else if (ParamType->isHalfType() && !getLangOpts().HalfArgsAndReturns) {
+ } else if (ParamType->isHalfType() && !getLangOpts().NativeHalfArgsAndReturns &&
+ !Context.getTargetInfo().allowHalfArgsAndReturns()) {
// Disallow half FP arguments.
Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 <<
FixItHint::CreateInsertion(Loc, "*");
@@ -2992,7 +3062,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
return QualType();
}
- if (getLangOpts().HLSL) {
+ if (getLangOpts().HLSL && Loc.isValid()) {
Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0;
return QualType();
}
@@ -3540,7 +3610,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
!D.getNumTypeObjects() &&
D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorContext::TemplateTypeArg:
Error = 10; // Template type argument
break;
@@ -3565,7 +3635,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType &&
!Auto->isDecltypeAuto())
break; // auto(x)
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorContext::TypeName:
case DeclaratorContext::Association:
Error = 15; // Generic
@@ -3834,7 +3904,7 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) {
case DeclaratorChunk::Paren:
if (&C == &Paren)
continue;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorChunk::Pointer:
StartsWithDeclaratorId = false;
continue;
@@ -4604,7 +4674,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
// Determine whether we should infer _Nonnull on pointer types.
- Optional<NullabilityKind> inferNullability;
+ std::optional<NullabilityKind> inferNullability;
bool inferNullabilityCS = false;
bool inferNullabilityInnerOnly = false;
bool inferNullabilityInnerOnlyComplete = false;
@@ -4637,8 +4707,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// inner pointers.
complainAboutMissingNullability = CAMN_InnerPointers;
- if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
- !T->getNullability(S.Context)) {
+ if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
+ !T->getNullability()) {
// Note that we allow but don't require nullability on dependent types.
++NumPointersRemaining;
}
@@ -4674,7 +4744,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorContext::TrailingReturn:
case DeclaratorContext::TrailingReturnVar:
isFunctionOrMethod = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorContext::Member:
if (state.getDeclarator().isObjCIvar() && !isFunctionOrMethod) {
@@ -4683,12 +4753,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
// Weak properties are inferred to be nullable.
- if (state.getDeclarator().isObjCWeakProperty() && inAssumeNonNullRegion) {
- inferNullability = NullabilityKind::Nullable;
+ if (state.getDeclarator().isObjCWeakProperty()) {
+ // Weak properties cannot be nonnull, and should not complain about
+ // missing nullable attributes during completeness checks.
+ complainAboutMissingNullability = CAMN_No;
+ if (inAssumeNonNullRegion) {
+ inferNullability = NullabilityKind::Nullable;
+ }
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclaratorContext::File:
case DeclaratorContext::KNRTypeList: {
@@ -4843,7 +4918,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case CAMN_InnerPointers:
if (NumPointersRemaining == 0)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CAMN_Yes:
checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc);
@@ -4854,8 +4929,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If the type itself could have nullability but does not, infer pointer
// nullability and perform consistency checking.
if (S.CodeSynthesisContexts.empty()) {
- if (T->canHaveNullability(/*ResultIfUnknown*/false) &&
- !T->getNullability(S.Context)) {
+ if (T->canHaveNullability(/*ResultIfUnknown*/ false) &&
+ !T->getNullability()) {
if (isVaList(T)) {
// Record that we've seen a pointer, but do nothing else.
if (NumPointersRemaining > 0)
@@ -4878,9 +4953,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
- if (complainAboutMissingNullability == CAMN_Yes &&
- T->isArrayType() && !T->getNullability(S.Context) && !isVaList(T) &&
- D.isPrototypeContext() &&
+ if (complainAboutMissingNullability == CAMN_Yes && T->isArrayType() &&
+ !T->getNullability() && !isVaList(T) && D.isPrototypeContext() &&
!hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) {
checkNullabilityConsistency(S, SimplePointerKind::Array,
D.getDeclSpec().getTypeSpecTypeLoc());
@@ -5152,7 +5226,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << 0 /*pointer hint*/;
D.setInvalidType(true);
}
- } else if (!S.getLangOpts().HalfArgsAndReturns) {
+ } else if (!S.getLangOpts().NativeHalfArgsAndReturns &&
+ !S.Context.getTargetInfo().allowHalfArgsAndReturns()) {
S.Diag(D.getIdentifierLoc(),
diag::err_parameters_retval_cannot_have_fp16_type) << 1;
D.setInvalidType(true);
@@ -5301,14 +5376,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable" attribute. Scan
- // for this attribute now.
- if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus)
- if (!D.getDeclarationAttributes().hasAttribute(
- ParsedAttr::AT_Overloadable) &&
- !D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) &&
- !D.getDeclSpec().getAttributes().hasAttribute(
- ParsedAttr::AT_Overloadable))
+ // for this attribute now. We also allow it in C2x per WG14 N2975.
+ if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) {
+ if (LangOpts.C2x)
+ S.Diag(FTI.getEllipsisLoc(),
+ diag::warn_c17_compat_ellipsis_only_parameter);
+ else if (!D.getDeclarationAttributes().hasAttribute(
+ ParsedAttr::AT_Overloadable) &&
+ !D.getAttributes().hasAttribute(
+ ParsedAttr::AT_Overloadable) &&
+ !D.getDeclSpec().getAttributes().hasAttribute(
+ ParsedAttr::AT_Overloadable))
S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param);
+ }
if (FTI.NumParams && FTI.Params[0].Param == nullptr) {
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function
@@ -5384,16 +5464,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
D.setInvalidType();
Param->setInvalidDecl();
}
- } else if (!S.getLangOpts().HalfArgsAndReturns) {
+ } else if (!S.getLangOpts().NativeHalfArgsAndReturns &&
+ !S.Context.getTargetInfo().allowHalfArgsAndReturns()) {
S.Diag(Param->getLocation(),
diag::err_parameters_retval_cannot_have_fp16_type) << 0;
D.setInvalidType();
}
} else if (!FTI.hasPrototype) {
- if (ParamTy->isPromotableIntegerType()) {
+ if (Context.isPromotableIntegerType(ParamTy)) {
ParamTy = Context.getPromotedIntegerType(ParamTy);
Param->setKNRPromoted(true);
- } else if (const BuiltinType* BTy = ParamTy->getAs<BuiltinType>()) {
+ } else if (const BuiltinType *BTy = ParamTy->getAs<BuiltinType>()) {
if (BTy->getKind() == BuiltinType::Float) {
ParamTy = Context.DoubleTy;
Param->setKNRPromoted(true);
@@ -5538,7 +5619,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// in ClsType; hence we wrap ClsType into an ElaboratedType.
// NOTE: in particular, no wrap occurs if ClsType already is an
// Elaborated, DependentName, or DependentTemplateSpecialization.
- if (NNSPrefix && isa<TemplateSpecializationType>(NNS->getAsType()))
+ if (isa<TemplateSpecializationType>(NNS->getAsType()))
ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType);
break;
}
@@ -5775,7 +5856,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << D.getSourceRange();
D.setEllipsisLoc(SourceLocation());
} else {
- T = Context.getPackExpansionType(T, None, /*ExpectPackInType=*/false);
+ T = Context.getPackExpansionType(T, std::nullopt,
+ /*ExpectPackInType=*/false);
}
break;
case DeclaratorContext::TemplateParam:
@@ -5788,7 +5870,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// parameter packs in the type of the non-type template parameter, then
// it expands those parameter packs.
if (T->containsUnexpandedParameterPack())
- T = Context.getPackExpansionType(T, None);
+ T = Context.getPackExpansionType(T, std::nullopt);
else
S.Diag(D.getEllipsisLoc(),
LangOpts.CPlusPlus11
@@ -5974,6 +6056,21 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr()));
}
+static void fillMatrixTypeLoc(MatrixTypeLoc MTL,
+ const ParsedAttributesView &Attrs) {
+ for (const ParsedAttr &AL : Attrs) {
+ if (AL.getKind() == ParsedAttr::AT_MatrixType) {
+ MTL.setAttrNameLoc(AL.getLoc());
+ MTL.setAttrRowOperand(AL.getArgAsExpr(0));
+ MTL.setAttrColumnOperand(AL.getArgAsExpr(1));
+ MTL.setAttrOperandParensRange(SourceRange());
+ return;
+ }
+ }
+
+ llvm_unreachable("no matrix_type attribute found at the expected location!");
+}
+
namespace {
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
Sema &SemaRef;
@@ -6048,18 +6145,20 @@ namespace {
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
- assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualExpr);
TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
}
void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
- assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType);
+ assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType ||
+ DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualType);
TL.setTypeofLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
assert(DS.getRepAsType());
TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
- TL.setUnderlyingTInfo(TInfo);
+ TL.setUnmodifiedTInfo(TInfo);
}
void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
@@ -6067,8 +6166,7 @@ namespace {
TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
}
void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
- // FIXME: This holds only because we only have one unary transform.
- assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType);
+ assert(DS.isTransformTypeTrait(DS.getTypeSpecType()));
TL.setKWLoc(DS.getTypeSpecTypeLoc());
TL.setParensRange(DS.getTypeofParensRange());
assert(DS.getRepAsType());
@@ -6090,19 +6188,19 @@ namespace {
}
}
void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
- ElaboratedTypeKeyword Keyword
- = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType());
if (DS.getTypeSpecType() == TST_typename) {
TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
- if (TInfo) {
- TL.copy(TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>());
- return;
- }
+ if (TInfo)
+ if (auto ETL = TInfo->getTypeLoc().getAs<ElaboratedTypeLoc>()) {
+ TL.copy(ETL);
+ return;
+ }
}
- TL.setElaboratedKeywordLoc(Keyword != ETK_None
- ? DS.getTypeSpecTypeLoc()
- : SourceLocation());
+ const ElaboratedType *T = TL.getTypePtr();
+ TL.setElaboratedKeywordLoc(T->getKeyword() != ETK_None
+ ? DS.getTypeSpecTypeLoc()
+ : SourceLocation());
const CXXScopeSpec& SS = DS.getTypeSpecScope();
TL.setQualifierLoc(SS.getWithLocInContext(Context));
Visit(TL.getNextTypeLoc().getUnqualifiedLoc());
@@ -6158,6 +6256,9 @@ namespace {
void VisitTagTypeLoc(TagTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
+ void VisitUsingTypeLoc(UsingTypeLoc TL) {
+ TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
+ }
void VisitAtomicTypeLoc(AtomicTypeLoc TL) {
// An AtomicTypeLoc can come from either an _Atomic(...) type specifier
// or an _Atomic qualifier.
@@ -6339,6 +6440,9 @@ namespace {
VisitDependentSizedExtVectorTypeLoc(DependentSizedExtVectorTypeLoc TL) {
TL.setNameLoc(Chunk.Loc);
}
+ void VisitMatrixTypeLoc(MatrixTypeLoc TL) {
+ fillMatrixTypeLoc(TL, Chunk.getAttrs());
+ }
void VisitTypeLoc(TypeLoc TL) {
llvm_unreachable("unsupported TypeLoc kind in declarator!");
@@ -6386,21 +6490,6 @@ fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL,
"no address_space attribute found at the expected location!");
}
-static void fillMatrixTypeLoc(MatrixTypeLoc MTL,
- const ParsedAttributesView &Attrs) {
- for (const ParsedAttr &AL : Attrs) {
- if (AL.getKind() == ParsedAttr::AT_MatrixType) {
- MTL.setAttrNameLoc(AL.getLoc());
- MTL.setAttrRowOperand(AL.getArgAsExpr(0));
- MTL.setAttrColumnOperand(AL.getArgAsExpr(1));
- MTL.setAttrOperandParensRange(SourceRange());
- return;
- }
- }
-
- llvm_unreachable("no matrix_type attribute found at the expected location!");
-}
-
/// Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
@@ -6432,29 +6521,42 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
CurrTL = ATL.getValueLoc().getUnqualifiedLoc();
}
- while (MacroQualifiedTypeLoc TL = CurrTL.getAs<MacroQualifiedTypeLoc>()) {
- TL.setExpansionLoc(
- State.getExpansionLocForMacroQualifiedType(TL.getTypePtr()));
- CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
- }
+ bool HasDesugaredTypeLoc = true;
+ while (HasDesugaredTypeLoc) {
+ switch (CurrTL.getTypeLocClass()) {
+ case TypeLoc::MacroQualified: {
+ auto TL = CurrTL.castAs<MacroQualifiedTypeLoc>();
+ TL.setExpansionLoc(
+ State.getExpansionLocForMacroQualifiedType(TL.getTypePtr()));
+ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+ break;
+ }
- while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
- fillAttributedTypeLoc(TL, State);
- CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
- }
+ case TypeLoc::Attributed: {
+ auto TL = CurrTL.castAs<AttributedTypeLoc>();
+ fillAttributedTypeLoc(TL, State);
+ CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+ break;
+ }
- while (DependentAddressSpaceTypeLoc TL =
- CurrTL.getAs<DependentAddressSpaceTypeLoc>()) {
- fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs());
- CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc();
- }
+ case TypeLoc::Adjusted:
+ case TypeLoc::BTFTagAttributed: {
+ CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
+ break;
+ }
- if (MatrixTypeLoc TL = CurrTL.getAs<MatrixTypeLoc>())
- fillMatrixTypeLoc(TL, D.getTypeObject(i).getAttrs());
+ case TypeLoc::DependentAddressSpace: {
+ auto TL = CurrTL.castAs<DependentAddressSpaceTypeLoc>();
+ fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs());
+ CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc();
+ break;
+ }
- // FIXME: Ordering here?
- while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>())
- CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
+ default:
+ HasDesugaredTypeLoc = false;
+ break;
+ }
+ }
DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL);
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
@@ -6539,7 +6641,7 @@ static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx,
const Expr *AddrSpace,
SourceLocation AttrLoc) {
if (!AddrSpace->isValueDependent()) {
- Optional<llvm::APSInt> OptAddrSpace =
+ std::optional<llvm::APSInt> OptAddrSpace =
AddrSpace->getIntegerConstantExpr(S.Context);
if (!OptAddrSpace) {
S.Diag(AttrLoc, diag::err_attribute_argument_type)
@@ -6707,6 +6809,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
// The keyword-based type attributes imply which address space to use.
ASIdx = S.getLangOpts().SYCLIsDevice ? Attr.asSYCLLangAS()
: Attr.asOpenCLLangAS();
+ if (S.getLangOpts().HLSL)
+ ASIdx = Attr.asHLSLLangAS();
if (ASIdx == LangAS::Default)
llvm_unreachable("Invalid address space");
@@ -7158,17 +7262,25 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
}
std::bitset<attr::LastAttr> Attrs;
- attr::Kind NewAttrKind = A->getKind();
QualType Desugared = Type;
- const AttributedType *AT = dyn_cast<AttributedType>(Type);
- while (AT) {
+ for (;;) {
+ if (const TypedefType *TT = dyn_cast<TypedefType>(Desugared)) {
+ Desugared = TT->desugar();
+ continue;
+ } else if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Desugared)) {
+ Desugared = ET->desugar();
+ continue;
+ }
+ const AttributedType *AT = dyn_cast<AttributedType>(Desugared);
+ if (!AT)
+ break;
Attrs[AT->getAttrKind()] = true;
Desugared = AT->getModifiedType();
- AT = dyn_cast<AttributedType>(Desugared);
}
// You cannot specify duplicate type attributes, so if the attribute has
// already been applied, flag it.
+ attr::Kind NewAttrKind = A->getKind();
if (Attrs[NewAttrKind]) {
S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
return true;
@@ -7189,14 +7301,11 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
return true;
}
- // Pointer type qualifiers can only operate on pointer types, but not
- // pointer-to-member types.
- //
- // FIXME: Should we really be disallowing this attribute if there is any
- // type sugar between it and the pointer (other than attributes)? Eg, this
- // disallows the attribute on a parenthesized pointer.
- // And if so, should we really allow *any* type attribute?
+ // Check the raw (i.e., desugared) Canonical type to see if it
+ // is a pointer type.
if (!isa<PointerType>(Desugared)) {
+ // Pointer type qualifiers can only operate on pointer types, but not
+ // pointer-to-member types.
if (Type->isMemberPointerType())
S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr;
else
@@ -7206,7 +7315,8 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
// Add address space to type based on its attributes.
LangAS ASIdx = LangAS::Default;
- uint64_t PtrWidth = S.Context.getTargetInfo().getPointerWidth(0);
+ uint64_t PtrWidth =
+ S.Context.getTargetInfo().getPointerWidth(LangAS::Default);
if (PtrWidth == 32) {
if (Attrs[attr::Ptr64])
ASIdx = LangAS::ptr64;
@@ -7300,7 +7410,7 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state,
// This (unlike the code above) looks through typedefs that might
// have nullability specifiers on them, which means we cannot
// provide a useful Fix-It.
- if (auto existingNullability = desugared->getNullability(S.Context)) {
+ if (auto existingNullability = desugared->getNullability()) {
if (nullability != *existingNullability) {
S.Diag(nullabilityLoc, diag::err_nullability_conflicting)
<< DiagNullabilityKind(nullability, isContextSensitive)
@@ -7399,7 +7509,7 @@ static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type,
// If we started with an object pointer type, rebuild it.
if (ptrType) {
equivType = S.Context.getObjCObjectPointerType(equivType);
- if (auto nullability = type->getNullability(S.Context)) {
+ if (auto nullability = type->getNullability()) {
// We create a nullability attribute from the __kindof attribute.
// Make sure that will make sense.
assert(attr.getAttributeSpellingListIndex() == 0 &&
@@ -7714,7 +7824,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
case EST_NoexceptTrue:
case EST_NoThrow:
// Exception spec doesn't conflict with nothrow, so don't warn.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case EST_Unparsed:
case EST_Uninstantiated:
case EST_DependentNoexcept:
@@ -7853,7 +7963,7 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor,
CallingConv DefaultCC =
Context.getDefaultCallingConvention(IsVariadic, IsStatic);
- if (CurCC != DefaultCC || DefaultCC == ToCC)
+ if (CurCC != DefaultCC)
return;
if (hasExplicitCallingConv(T))
@@ -7960,7 +8070,7 @@ static bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr,
llvm::APSInt &Result) {
const auto *AttrExpr = Attr.getArgAsExpr(0);
if (!AttrExpr->isTypeDependent()) {
- if (Optional<llvm::APSInt> Res =
+ if (std::optional<llvm::APSInt> Res =
AttrExpr->getIntegerConstantExpr(S.Context)) {
Result = *Res;
return true;
@@ -8315,6 +8425,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case ParsedAttr::AT_OpenCLLocalAddressSpace:
case ParsedAttr::AT_OpenCLConstantAddressSpace:
case ParsedAttr::AT_OpenCLGenericAddressSpace:
+ case ParsedAttr::AT_HLSLGroupSharedAddressSpace:
case ParsedAttr::AT_AddressSpace:
HandleAddressSpaceTypeAttribute(type, attr, state);
attr.setUsedAsTypeAttr();
@@ -8443,7 +8554,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// clang, so revert to attribute-based handling for C.
if (!state.getSema().getLangOpts().CPlusPlus)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
FUNCTION_TYPE_ATTRS_CASELIST:
attr.setUsedAsTypeAttr();
@@ -9100,29 +9211,23 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword,
TagDecl *OwnedTagDecl) {
if (T.isNull())
return T;
- NestedNameSpecifier *NNS;
- if (SS.isValid())
- NNS = SS.getScopeRep();
- else {
- if (Keyword == ETK_None)
- return T;
- NNS = nullptr;
- }
- return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl);
+ return Context.getElaboratedType(
+ Keyword, SS.isValid() ? SS.getScopeRep() : nullptr, T, OwnedTagDecl);
}
-QualType Sema::BuildTypeofExprType(Expr *E) {
+QualType Sema::BuildTypeofExprType(Expr *E, TypeOfKind Kind) {
assert(!E->hasPlaceholderType() && "unexpected placeholder");
if (!getLangOpts().CPlusPlus && E->refersToBitField())
- Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 2;
+ Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield)
+ << (Kind == TypeOfKind::Unqualified ? 3 : 2);
if (!E->isTypeDependent()) {
QualType T = E->getType();
if (const TagType *TT = T->getAs<TagType>())
DiagnoseUseOfDecl(TT->getDecl(), E->getExprLoc());
}
- return Context.getTypeOfExprType(E);
+ return Context.getTypeOfExprType(E, Kind);
}
/// getDecltypeForExpr - Given an expr, will return the decltype for
@@ -9207,39 +9312,257 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
return Context.getDecltypeType(E, getDecltypeForExpr(E));
}
-QualType Sema::BuildUnaryTransformType(QualType BaseType,
- UnaryTransformType::UTTKind UKind,
- SourceLocation Loc) {
- switch (UKind) {
- case UnaryTransformType::EnumUnderlyingType:
- if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) {
- Diag(Loc, diag::err_only_enums_have_underlying_types);
- return QualType();
- } else {
- QualType Underlying = BaseType;
- if (!BaseType->isDependentType()) {
- // The enum could be incomplete if we're parsing its definition or
- // recovering from an error.
- NamedDecl *FwdDecl = nullptr;
- if (BaseType->isIncompleteType(&FwdDecl)) {
- Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType;
- Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl;
- return QualType();
- }
+static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType,
+ SourceLocation Loc) {
+ assert(BaseType->isEnumeralType());
+ EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl();
+ assert(ED && "EnumType has no EnumDecl");
- EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl();
- assert(ED && "EnumType has no EnumDecl");
+ S.DiagnoseUseOfDecl(ED, Loc);
- DiagnoseUseOfDecl(ED, Loc);
+ QualType Underlying = ED->getIntegerType();
+ assert(!Underlying.isNull());
- Underlying = ED->getIntegerType();
- assert(!Underlying.isNull());
- }
- return Context.getUnaryTransformType(BaseType, Underlying,
- UnaryTransformType::EnumUnderlyingType);
+ return Underlying;
+}
+
+QualType Sema::BuiltinEnumUnderlyingType(QualType BaseType,
+ SourceLocation Loc) {
+ if (!BaseType->isEnumeralType()) {
+ Diag(Loc, diag::err_only_enums_have_underlying_types);
+ return QualType();
+ }
+
+ // The enum could be incomplete if we're parsing its definition or
+ // recovering from an error.
+ NamedDecl *FwdDecl = nullptr;
+ if (BaseType->isIncompleteType(&FwdDecl)) {
+ Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType;
+ Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl;
+ return QualType();
+ }
+
+ return GetEnumUnderlyingType(*this, BaseType, Loc);
+}
+
+QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) {
+ QualType Pointer = BaseType.isReferenceable() || BaseType->isVoidType()
+ ? BuildPointerType(BaseType.getNonReferenceType(), Loc,
+ DeclarationName())
+ : BaseType;
+
+ return Pointer.isNull() ? QualType() : Pointer;
+}
+
+QualType Sema::BuiltinRemovePointer(QualType BaseType, SourceLocation Loc) {
+ // We don't want block pointers or ObjectiveC's id type.
+ if (!BaseType->isAnyPointerType() || BaseType->isObjCIdType())
+ return BaseType;
+
+ return BaseType->getPointeeType();
+}
+
+QualType Sema::BuiltinDecay(QualType BaseType, SourceLocation Loc) {
+ QualType Underlying = BaseType.getNonReferenceType();
+ if (Underlying->isArrayType())
+ return Context.getDecayedType(Underlying);
+
+ if (Underlying->isFunctionType())
+ return BuiltinAddPointer(BaseType, Loc);
+
+ SplitQualType Split = Underlying.getSplitUnqualifiedType();
+ // std::decay is supposed to produce 'std::remove_cv', but since 'restrict' is
+ // in the same group of qualifiers as 'const' and 'volatile', we're extending
+ // '__decay(T)' so that it removes all qualifiers.
+ Split.Quals.removeCVRQualifiers();
+ return Context.getQualifiedType(Split);
+}
+
+QualType Sema::BuiltinAddReference(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ assert(LangOpts.CPlusPlus);
+ QualType Reference =
+ BaseType.isReferenceable()
+ ? BuildReferenceType(BaseType,
+ UKind == UnaryTransformType::AddLvalueReference,
+ Loc, DeclarationName())
+ : BaseType;
+ return Reference.isNull() ? QualType() : Reference;
+}
+
+QualType Sema::BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ if (UKind == UnaryTransformType::RemoveAllExtents)
+ return Context.getBaseElementType(BaseType);
+
+ if (const auto *AT = Context.getAsArrayType(BaseType))
+ return AT->getElementType();
+
+ return BaseType;
+}
+
+QualType Sema::BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ assert(LangOpts.CPlusPlus);
+ QualType T = BaseType.getNonReferenceType();
+ if (UKind == UTTKind::RemoveCVRef &&
+ (T.isConstQualified() || T.isVolatileQualified())) {
+ Qualifiers Quals;
+ QualType Unqual = Context.getUnqualifiedArrayType(T, Quals);
+ Quals.removeConst();
+ Quals.removeVolatile();
+ T = Context.getQualifiedType(Unqual, Quals);
+ }
+ return T;
+}
+
+QualType Sema::BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ if ((BaseType->isReferenceType() && UKind != UTTKind::RemoveRestrict) ||
+ BaseType->isFunctionType())
+ return BaseType;
+
+ Qualifiers Quals;
+ QualType Unqual = Context.getUnqualifiedArrayType(BaseType, Quals);
+
+ if (UKind == UTTKind::RemoveConst || UKind == UTTKind::RemoveCV)
+ Quals.removeConst();
+ if (UKind == UTTKind::RemoveVolatile || UKind == UTTKind::RemoveCV)
+ Quals.removeVolatile();
+ if (UKind == UTTKind::RemoveRestrict)
+ Quals.removeRestrict();
+
+ return Context.getQualifiedType(Unqual, Quals);
+}
+
+static QualType ChangeIntegralSignedness(Sema &S, QualType BaseType,
+ bool IsMakeSigned,
+ SourceLocation Loc) {
+ if (BaseType->isEnumeralType()) {
+ QualType Underlying = GetEnumUnderlyingType(S, BaseType, Loc);
+ if (auto *BitInt = dyn_cast<BitIntType>(Underlying)) {
+ unsigned int Bits = BitInt->getNumBits();
+ if (Bits > 1)
+ return S.Context.getBitIntType(!IsMakeSigned, Bits);
+
+ S.Diag(Loc, diag::err_make_signed_integral_only)
+ << IsMakeSigned << /*_BitInt(1)*/ true << BaseType << 1 << Underlying;
+ return QualType();
+ }
+ if (Underlying->isBooleanType()) {
+ S.Diag(Loc, diag::err_make_signed_integral_only)
+ << IsMakeSigned << /*_BitInt(1)*/ false << BaseType << 1
+ << Underlying;
+ return QualType();
}
}
- llvm_unreachable("unknown unary transform type");
+
+ bool Int128Unsupported = !S.Context.getTargetInfo().hasInt128Type();
+ std::array<CanQualType *, 6> AllSignedIntegers = {
+ &S.Context.SignedCharTy, &S.Context.ShortTy, &S.Context.IntTy,
+ &S.Context.LongTy, &S.Context.LongLongTy, &S.Context.Int128Ty};
+ ArrayRef<CanQualType *> AvailableSignedIntegers(
+ AllSignedIntegers.data(), AllSignedIntegers.size() - Int128Unsupported);
+ std::array<CanQualType *, 6> AllUnsignedIntegers = {
+ &S.Context.UnsignedCharTy, &S.Context.UnsignedShortTy,
+ &S.Context.UnsignedIntTy, &S.Context.UnsignedLongTy,
+ &S.Context.UnsignedLongLongTy, &S.Context.UnsignedInt128Ty};
+ ArrayRef<CanQualType *> AvailableUnsignedIntegers(AllUnsignedIntegers.data(),
+ AllUnsignedIntegers.size() -
+ Int128Unsupported);
+ ArrayRef<CanQualType *> *Consider =
+ IsMakeSigned ? &AvailableSignedIntegers : &AvailableUnsignedIntegers;
+
+ uint64_t BaseSize = S.Context.getTypeSize(BaseType);
+ auto *Result =
+ llvm::find_if(*Consider, [&S, BaseSize](const CanQual<Type> *T) {
+ return BaseSize == S.Context.getTypeSize(T->getTypePtr());
+ });
+
+ assert(Result != Consider->end());
+ return QualType((*Result)->getTypePtr(), 0);
+}
+
+QualType Sema::BuiltinChangeSignedness(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ bool IsMakeSigned = UKind == UnaryTransformType::MakeSigned;
+ if ((!BaseType->isIntegerType() && !BaseType->isEnumeralType()) ||
+ BaseType->isBooleanType() ||
+ (BaseType->isBitIntType() &&
+ BaseType->getAs<BitIntType>()->getNumBits() < 2)) {
+ Diag(Loc, diag::err_make_signed_integral_only)
+ << IsMakeSigned << BaseType->isBitIntType() << BaseType << 0;
+ return QualType();
+ }
+
+ bool IsNonIntIntegral =
+ BaseType->isChar16Type() || BaseType->isChar32Type() ||
+ BaseType->isWideCharType() || BaseType->isEnumeralType();
+
+ QualType Underlying =
+ IsNonIntIntegral
+ ? ChangeIntegralSignedness(*this, BaseType, IsMakeSigned, Loc)
+ : IsMakeSigned ? Context.getCorrespondingSignedType(BaseType)
+ : Context.getCorrespondingUnsignedType(BaseType);
+ if (Underlying.isNull())
+ return Underlying;
+ return Context.getQualifiedType(Underlying, BaseType.getQualifiers());
+}
+
+QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind,
+ SourceLocation Loc) {
+ if (BaseType->isDependentType())
+ return Context.getUnaryTransformType(BaseType, BaseType, UKind);
+ QualType Result;
+ switch (UKind) {
+ case UnaryTransformType::EnumUnderlyingType: {
+ Result = BuiltinEnumUnderlyingType(BaseType, Loc);
+ break;
+ }
+ case UnaryTransformType::AddPointer: {
+ Result = BuiltinAddPointer(BaseType, Loc);
+ break;
+ }
+ case UnaryTransformType::RemovePointer: {
+ Result = BuiltinRemovePointer(BaseType, Loc);
+ break;
+ }
+ case UnaryTransformType::Decay: {
+ Result = BuiltinDecay(BaseType, Loc);
+ break;
+ }
+ case UnaryTransformType::AddLvalueReference:
+ case UnaryTransformType::AddRvalueReference: {
+ Result = BuiltinAddReference(BaseType, UKind, Loc);
+ break;
+ }
+ case UnaryTransformType::RemoveAllExtents:
+ case UnaryTransformType::RemoveExtent: {
+ Result = BuiltinRemoveExtent(BaseType, UKind, Loc);
+ break;
+ }
+ case UnaryTransformType::RemoveCVRef:
+ case UnaryTransformType::RemoveReference: {
+ Result = BuiltinRemoveReference(BaseType, UKind, Loc);
+ break;
+ }
+ case UnaryTransformType::RemoveConst:
+ case UnaryTransformType::RemoveCV:
+ case UnaryTransformType::RemoveRestrict:
+ case UnaryTransformType::RemoveVolatile: {
+ Result = BuiltinChangeCVRQualifiers(BaseType, UKind, Loc);
+ break;
+ }
+ case UnaryTransformType::MakeSigned:
+ case UnaryTransformType::MakeUnsigned: {
+ Result = BuiltinChangeSignedness(BaseType, UKind, Loc);
+ break;
+ }
+ }
+
+ return !Result.isNull()
+ ? Context.getUnaryTransformType(BaseType, Result, UKind)
+ : Result;
}
QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index a8589191fc91..6a05ecc5370f 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -40,6 +40,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
+#include <optional>
using namespace llvm::omp;
@@ -279,9 +280,8 @@ public:
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
- bool &ShouldExpand,
- bool &RetainExpansion,
- Optional<unsigned> &NumExpansions) {
+ bool &ShouldExpand, bool &RetainExpansion,
+ std::optional<unsigned> &NumExpansions) {
ShouldExpand = false;
return false;
}
@@ -636,6 +636,14 @@ public:
QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
#include "clang/AST/TypeLocNodes.def"
+ QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
+ TemplateTypeParmTypeLoc TL,
+ bool SuppressObjCLifetime);
+ QualType
+ TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB,
+ SubstTemplateTypeParmPackTypeLoc TL,
+ bool SuppressObjCLifetime);
+
template<typename Fn>
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
@@ -671,13 +679,49 @@ public:
/// The result vectors should be kept in sync; null entries in the
/// variables vector are acceptable.
///
+ /// LastParamTransformed, if non-null, will be set to the index of the last
+ /// parameter on which transfromation was started. In the event of an error,
+ /// this will contain the parameter which failed to instantiate.
+ ///
/// Return true on error.
bool TransformFunctionTypeParams(
SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
const QualType *ParamTypes,
const FunctionProtoType::ExtParameterInfo *ParamInfos,
SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars,
- Sema::ExtParameterInfoBuilder &PInfos);
+ Sema::ExtParameterInfoBuilder &PInfos, unsigned *LastParamTransformed);
+
+ bool TransformFunctionTypeParams(
+ SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
+ const QualType *ParamTypes,
+ const FunctionProtoType::ExtParameterInfo *ParamInfos,
+ SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars,
+ Sema::ExtParameterInfoBuilder &PInfos) {
+ return getDerived().TransformFunctionTypeParams(
+ Loc, Params, ParamTypes, ParamInfos, PTypes, PVars, PInfos, nullptr);
+ }
+
+ /// Transforms the parameters of a requires expresison into the given vectors.
+ ///
+ /// The result vectors should be kept in sync; null entries in the
+ /// variables vector are acceptable.
+ ///
+ /// Returns an unset ExprResult on success. Returns an ExprResult the 'not
+ /// satisfied' RequiresExpr if subsitution failed, OR an ExprError, both of
+ /// which are cases where transformation shouldn't continue.
+ ExprResult TransformRequiresTypeParams(
+ SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE,
+ RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params,
+ SmallVectorImpl<QualType> &PTypes,
+ SmallVectorImpl<ParmVarDecl *> &TransParams,
+ Sema::ExtParameterInfoBuilder &PInfos) {
+ if (getDerived().TransformFunctionTypeParams(
+ KWLoc, Params, /*ParamTypes=*/nullptr,
+ /*ParamInfos=*/nullptr, PTypes, &TransParams, PInfos))
+ return ExprError();
+
+ return ExprResult{};
+ }
/// Transforms a single function-type parameter. Return null
/// on error.
@@ -686,7 +730,7 @@ public:
/// scope index; can be negative
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- Optional<unsigned> NumExpansions,
+ std::optional<unsigned> NumExpansions,
bool ExpectParameterPack);
/// Transform the body of a lambda-expression.
@@ -963,12 +1007,13 @@ public:
///
/// By default, performs semantic analysis when building the typeof type.
/// Subclasses may override this routine to provide different behavior.
- QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc);
+ QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc,
+ TypeOfKind Kind);
/// Build a new typeof(type) type.
///
/// By default, builds a new TypeOfType with the given underlying type.
- QualType RebuildTypeOfType(QualType Underlying);
+ QualType RebuildTypeOfType(QualType Underlying, TypeOfKind Kind);
/// Build a new unary transform type.
QualType RebuildUnaryTransformType(QualType BaseType,
@@ -1061,23 +1106,18 @@ public:
// If it's still dependent, make a dependent specialization.
if (InstName.getAsDependentTemplateName())
- return SemaRef.Context.getDependentTemplateSpecializationType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
- Name,
- Args);
+ return SemaRef.Context.getDependentTemplateSpecializationType(
+ Keyword, QualifierLoc.getNestedNameSpecifier(), Name,
+ Args.arguments());
// Otherwise, make an elaborated type wrapping a non-dependent
// specialization.
QualType T =
- getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
- if (T.isNull()) return QualType();
-
- if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == nullptr)
- return T;
-
- return SemaRef.Context.getElaboratedType(Keyword,
- QualifierLoc.getNestedNameSpecifier(),
- T);
+ getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
+ if (T.isNull())
+ return QualType();
+ return SemaRef.Context.getElaboratedType(
+ Keyword, QualifierLoc.getNestedNameSpecifier(), T);
}
/// Build a new typename type that refers to an identifier.
@@ -1182,10 +1222,9 @@ public:
///
/// By default, builds a new PackExpansionType type from the given pattern.
/// Subclasses may override this routine to provide different behavior.
- QualType RebuildPackExpansionType(QualType Pattern,
- SourceRange PatternRange,
+ QualType RebuildPackExpansionType(QualType Pattern, SourceRange PatternRange,
SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, PatternRange, EllipsisLoc,
NumExpansions);
}
@@ -1252,9 +1291,11 @@ public:
/// be resolved to a specific template, then builds the appropriate kind of
/// template name. Subclasses may override this routine to provide different
/// behavior.
- TemplateName RebuildTemplateName(TemplateTemplateParmDecl *Param,
- const TemplateArgument &ArgPack) {
- return getSema().Context.getSubstTemplateTemplateParmPack(Param, ArgPack);
+ TemplateName RebuildTemplateName(const TemplateArgument &ArgPack,
+ Decl *AssociatedDecl, unsigned Index,
+ bool Final) {
+ return getSema().Context.getSubstTemplateTemplateParmPack(
+ ArgPack, AssociatedDecl, Index, Final);
}
/// Build a new compound statement.
@@ -1946,15 +1987,16 @@ public:
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPMapClause(
- ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
+ Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
ArrayRef<SourceLocation> MapTypeModifiersLoc,
CXXScopeSpec MapperIdScopeSpec, DeclarationNameInfo MapperId,
OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) {
return getSema().ActOnOpenMPMapClause(
- MapTypeModifiers, MapTypeModifiersLoc, MapperIdScopeSpec, MapperId,
- MapType, IsMapTypeImplicit, MapLoc, ColonLoc, VarList, Locs,
+ IteratorModifier, MapTypeModifiers, MapTypeModifiersLoc,
+ MapperIdScopeSpec, MapperId, MapType, IsMapTypeImplicit, MapLoc,
+ ColonLoc, VarList, Locs,
/*NoDiagnose=*/false, UnresolvedMappers);
}
@@ -2009,22 +2051,26 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPGrainsizeClause(Expr *Grainsize, SourceLocation StartLoc,
+ OMPClause *RebuildOMPGrainsizeClause(OpenMPGrainsizeClauseModifier Modifier,
+ Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ModifierLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPGrainsizeClause(Grainsize, StartLoc, LParenLoc,
- EndLoc);
+ return getSema().ActOnOpenMPGrainsizeClause(Modifier, Device, StartLoc,
+ LParenLoc, ModifierLoc, EndLoc);
}
/// Build a new OpenMP 'num_tasks' clause.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc,
+ OMPClause *RebuildOMPNumTasksClause(OpenMPNumTasksClauseModifier Modifier,
+ Expr *NumTasks, SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ModifierLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPNumTasksClause(NumTasks, StartLoc, LParenLoc,
- EndLoc);
+ return getSema().ActOnOpenMPNumTasksClause(Modifier, NumTasks, StartLoc,
+ LParenLoc, ModifierLoc, EndLoc);
}
/// Build a new OpenMP 'hint' clause.
@@ -2207,28 +2253,25 @@ public:
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPOrderClause(OpenMPOrderClauseKind Kind,
- SourceLocation KindKwLoc,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
- return getSema().ActOnOpenMPOrderClause(Kind, KindKwLoc, StartLoc,
- LParenLoc, EndLoc);
+ OMPClause *RebuildOMPOrderClause(
+ OpenMPOrderClauseKind Kind, SourceLocation KindKwLoc,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc,
+ OpenMPOrderClauseModifier Modifier, SourceLocation ModifierKwLoc) {
+ return getSema().ActOnOpenMPOrderClause(Modifier, Kind, StartLoc, LParenLoc,
+ ModifierKwLoc, KindKwLoc, EndLoc);
}
/// Build a new OpenMP 'init' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs,
- bool IsTarget, bool IsTargetSync,
+ OMPClause *RebuildOMPInitClause(Expr *InteropVar, OMPInteropInfo &InteropInfo,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation VarLoc,
SourceLocation EndLoc) {
- return getSema().ActOnOpenMPInitClause(InteropVar, PrefExprs, IsTarget,
- IsTargetSync, StartLoc, LParenLoc,
- VarLoc, EndLoc);
+ return getSema().ActOnOpenMPInitClause(InteropVar, InteropInfo, StartLoc,
+ LParenLoc, VarLoc, EndLoc);
}
/// Build a new OpenMP 'use' clause.
@@ -2301,6 +2344,17 @@ public:
EndLoc);
}
+ /// Build a new OpenMP 'ompx_dyn_cgroup_mem' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPXDynCGroupMemClause(Expr *Size, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPXDynCGroupMemClause(Size, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// Build a new OpenMP 'align' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -2311,6 +2365,41 @@ public:
return getSema().ActOnOpenMPAlignClause(A, StartLoc, LParenLoc, EndLoc);
}
+ /// Build a new OpenMP 'at' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPAtClause(OpenMPAtClauseKind Kind, SourceLocation KwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPAtClause(Kind, KwLoc, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// Build a new OpenMP 'severity' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPSeverityClause(OpenMPSeverityClauseKind Kind,
+ SourceLocation KwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPSeverityClause(Kind, KwLoc, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// Build a new OpenMP 'message' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPMessageClause(Expr *MS, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPMessageClause(MS, StartLoc, LParenLoc, EndLoc);
+ }
+
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -2783,20 +2872,18 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildExtVectorElementExpr(Expr *Base,
- SourceLocation OpLoc,
- SourceLocation AccessorLoc,
- IdentifierInfo &Accessor) {
+ ExprResult RebuildExtVectorElementExpr(Expr *Base, SourceLocation OpLoc,
+ bool IsArrow,
+ SourceLocation AccessorLoc,
+ IdentifierInfo &Accessor) {
CXXScopeSpec SS;
DeclarationNameInfo NameInfo(&Accessor, AccessorLoc);
- return getSema().BuildMemberReferenceExpr(Base, Base->getType(),
- OpLoc, /*IsArrow*/ false,
- SS, SourceLocation(),
- /*FirstQualifierInScope*/ nullptr,
- NameInfo,
- /* TemplateArgs */ nullptr,
- /*S*/ nullptr);
+ return getSema().BuildMemberReferenceExpr(
+ Base, Base->getType(), OpLoc, IsArrow, SS, SourceLocation(),
+ /*FirstQualifierInScope*/ nullptr, NameInfo,
+ /* TemplateArgs */ nullptr,
+ /*S*/ nullptr);
}
/// Build a new initializer list expression.
@@ -3134,9 +3221,10 @@ public:
/// By default, builds a new default-argument expression, which does not
/// require any semantic analysis. Subclasses may override this routine to
/// provide different behavior.
- ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param) {
+ ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param,
+ Expr *RewrittenExpr) {
return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param,
- getSema().CurContext);
+ RewrittenExpr, getSema().CurContext);
}
/// Build a new C++11 default-initialization expression.
@@ -3146,8 +3234,7 @@ public:
/// routine to provide different behavior.
ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc,
FieldDecl *Field) {
- return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field,
- getSema().CurContext);
+ return getSema().BuildCXXDefaultInitExpr(Loc, Field);
}
/// Build a new C++ zero-initialization expression.
@@ -3157,25 +3244,23 @@ public:
ExprResult RebuildCXXScalarValueInitExpr(TypeSourceInfo *TSInfo,
SourceLocation LParenLoc,
SourceLocation RParenLoc) {
- return getSema().BuildCXXTypeConstructExpr(
- TSInfo, LParenLoc, None, RParenLoc, /*ListInitialization=*/false);
+ return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, std::nullopt,
+ RParenLoc,
+ /*ListInitialization=*/false);
}
/// Build a new C++ "new" expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildCXXNewExpr(SourceLocation StartLoc,
- bool UseGlobal,
+ ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
- SourceRange TypeIdParens,
- QualType AllocatedType,
+ SourceRange TypeIdParens, QualType AllocatedType,
TypeSourceInfo *AllocatedTypeInfo,
- Optional<Expr *> ArraySize,
- SourceRange DirectInitRange,
- Expr *Initializer) {
+ std::optional<Expr *> ArraySize,
+ SourceRange DirectInitRange, Expr *Initializer) {
return getSema().BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
PlacementArgs,
@@ -3397,11 +3482,10 @@ public:
}
/// Build a new expression to compute the length of a parameter pack.
- ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc,
- NamedDecl *Pack,
+ ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc,
SourceLocation RParenLoc,
- Optional<unsigned> Length,
+ std::optional<unsigned> Length,
ArrayRef<TemplateArgument> PartialArgs) {
return SizeOfPackExpr::Create(SemaRef.Context, OperatorLoc, Pack, PackLoc,
RParenLoc, Length, PartialArgs);
@@ -3479,9 +3563,10 @@ public:
}
concepts::NestedRequirement *
- RebuildNestedRequirement(
- concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
- return SemaRef.BuildNestedRequirement(SubstDiag);
+ RebuildNestedRequirement(StringRef InvalidConstraintEntity,
+ const ASTConstraintSatisfaction &Satisfaction) {
+ return SemaRef.BuildNestedRequirement(InvalidConstraintEntity,
+ Satisfaction);
}
concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) {
@@ -3704,9 +3789,9 @@ public:
/// By default, performs semantic analysis to build a new pack expansion
/// for a template argument. Subclasses may override this routine to provide
/// different behavior.
- TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
- SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ TemplateArgumentLoc
+ RebuildPackExpansion(TemplateArgumentLoc Pattern, SourceLocation EllipsisLoc,
+ std::optional<unsigned> NumExpansions) {
switch (Pattern.getArgument().getKind()) {
case TemplateArgument::Expression: {
ExprResult Result
@@ -3753,7 +3838,7 @@ public:
/// for an expression. Subclasses may override this routine to provide
/// different behavior.
ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions);
}
@@ -3766,7 +3851,7 @@ public:
BinaryOperatorKind Operator,
SourceLocation EllipsisLoc, Expr *RHS,
SourceLocation RParenLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
return getSema().BuildCXXFoldExpr(ULE, LParenLoc, LHS, Operator,
EllipsisLoc, RHS, RParenLoc,
NumExpansions);
@@ -3781,6 +3866,16 @@ public:
return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator);
}
+ ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T,
+ unsigned NumUserSpecifiedExprs,
+ SourceLocation InitLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ return CXXParenListInitExpr::Create(getSema().Context, Args, T,
+ NumUserSpecifiedExprs, InitLoc,
+ LParenLoc, RParenLoc);
+ }
+
/// Build a new atomic operation expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -3931,13 +4026,13 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
// Revert value-initialization back to empty parens.
if (CXXScalarValueInitExpr *VIE = dyn_cast<CXXScalarValueInitExpr>(Init)) {
SourceRange Parens = VIE->getSourceRange();
- return getDerived().RebuildParenListExpr(Parens.getBegin(), None,
+ return getDerived().RebuildParenListExpr(Parens.getBegin(), std::nullopt,
Parens.getEnd());
}
// FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization.
if (isa<ImplicitValueInitExpr>(Init))
- return getDerived().RebuildParenListExpr(SourceLocation(), None,
+ return getDerived().RebuildParenListExpr(SourceLocation(), std::nullopt,
SourceLocation());
// Revert initialization by constructor back to a parenthesized or braced list
@@ -4005,8 +4100,8 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs,
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions = Expansion->getNumExpansions();
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions = Expansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
Pattern->getSourceRange(),
Unexpanded,
@@ -4123,9 +4218,13 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
NestedNameSpecifierLoc NNS, QualType ObjectType,
NamedDecl *FirstQualifierInScope) {
SmallVector<NestedNameSpecifierLoc, 4> Qualifiers;
- for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier;
- Qualifier = Qualifier.getPrefix())
- Qualifiers.push_back(Qualifier);
+
+ auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) {
+ for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier;
+ Qualifier = Qualifier.getPrefix())
+ Qualifiers.push_back(Qualifier);
+ };
+ insertNNS(NNS);
CXXScopeSpec SS;
while (!Qualifiers.empty()) {
@@ -4182,24 +4281,27 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
if (!TL)
return NestedNameSpecifierLoc();
- if (TL.getType()->isDependentType() || TL.getType()->isRecordType() ||
- (SemaRef.getLangOpts().CPlusPlus11 &&
- TL.getType()->isEnumeralType())) {
- assert(!TL.getType().hasLocalQualifiers() &&
- "Can't get cv-qualifiers here");
- if (TL.getType()->isEnumeralType())
+ QualType T = TL.getType();
+ if (T->isDependentType() || T->isRecordType() ||
+ (SemaRef.getLangOpts().CPlusPlus11 && T->isEnumeralType())) {
+ if (T->isEnumeralType())
SemaRef.Diag(TL.getBeginLoc(),
diag::warn_cxx98_compat_enum_nested_name_spec);
+
+ if (const auto ETL = TL.getAs<ElaboratedTypeLoc>()) {
+ SS.Adopt(ETL.getQualifierLoc());
+ TL = ETL.getNamedTypeLoc();
+ }
SS.Extend(SemaRef.Context, /*FIXME:*/ SourceLocation(), TL,
Q.getLocalEndLoc());
break;
}
// If the nested-name-specifier is an invalid type def, don't emit an
// error because a previous error should have already been emitted.
- TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>();
+ TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>();
if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) {
SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
- << TL.getType() << SS.getRange();
+ << T << SS.getRange();
}
return NestedNameSpecifierLoc();
}
@@ -4362,18 +4464,9 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS,
if (SubstTemplateTemplateParmPackStorage *SubstPack
= Name.getAsSubstTemplateTemplateParmPack()) {
- TemplateTemplateParmDecl *TransParam
- = cast_or_null<TemplateTemplateParmDecl>(
- getDerived().TransformDecl(NameLoc, SubstPack->getParameterPack()));
- if (!TransParam)
- return TemplateName();
-
- if (!getDerived().AlwaysRebuild() &&
- TransParam == SubstPack->getParameterPack())
- return Name;
-
- return getDerived().RebuildTemplateName(TransParam,
- SubstPack->getArgumentPack());
+ return getDerived().RebuildTemplateName(
+ SubstPack->getArgumentPack(), SubstPack->getAssociatedDecl(),
+ SubstPack->getIndex(), SubstPack->getFinal());
}
// These should be getting filtered out before they reach the AST.
@@ -4587,7 +4680,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
// We have a pack expansion, for which we will be substituting into
// the pattern.
SourceLocation Ellipsis;
- Optional<unsigned> OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions;
TemplateArgumentLoc Pattern
= getSema().getTemplateArgumentPackExpansionPattern(
In, Ellipsis, OrigNumExpansions);
@@ -4600,7 +4693,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Ellipsis,
Pattern.getSourceRange(),
Unexpanded,
@@ -4787,7 +4880,20 @@ template<typename Derived>
QualType
TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
QualifiedTypeLoc T) {
- QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc());
+ QualType Result;
+ TypeLoc UnqualTL = T.getUnqualifiedLoc();
+ auto SuppressObjCLifetime =
+ T.getType().getLocalQualifiers().hasObjCLifetime();
+ if (auto TTP = UnqualTL.getAs<TemplateTypeParmTypeLoc>()) {
+ Result = getDerived().TransformTemplateTypeParmType(TLB, TTP,
+ SuppressObjCLifetime);
+ } else if (auto STTP = UnqualTL.getAs<SubstTemplateTypeParmPackTypeLoc>()) {
+ Result = getDerived().TransformSubstTemplateTypeParmPackType(
+ TLB, STTP, SuppressObjCLifetime);
+ } else {
+ Result = getDerived().TransformType(TLB, UnqualTL);
+ }
+
if (Result.isNull())
return QualType();
@@ -4850,16 +4956,7 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
// A lifetime qualifier applied to a substituted template parameter
// overrides the lifetime qualifier from the template argument.
const AutoType *AutoTy;
- if (const SubstTemplateTypeParmType *SubstTypeParam
- = dyn_cast<SubstTemplateTypeParmType>(T)) {
- QualType Replacement = SubstTypeParam->getReplacementType();
- Qualifiers Qs = Replacement.getQualifiers();
- Qs.removeObjCLifetime();
- Replacement = SemaRef.Context.getQualifiedType(
- Replacement.getUnqualifiedType(), Qs);
- T = SemaRef.Context.getSubstTemplateTypeParmType(
- SubstTypeParam->getReplacedParameter(), Replacement);
- } else if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) {
+ if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) {
// 'auto' types behave the same way as template parameters.
QualType Deduced = AutoTy->getDeducedType();
Qualifiers Qs = Deduced.getQualifiers();
@@ -5604,8 +5701,8 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
template <typename Derived>
ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
- ParmVarDecl *OldParm, int indexAdjustment, Optional<unsigned> NumExpansions,
- bool ExpectParameterPack) {
+ ParmVarDecl *OldParm, int indexAdjustment,
+ std::optional<unsigned> NumExpansions, bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = nullptr;
@@ -5665,15 +5762,18 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
const FunctionProtoType::ExtParameterInfo *ParamInfos,
SmallVectorImpl<QualType> &OutParamTypes,
SmallVectorImpl<ParmVarDecl *> *PVars,
- Sema::ExtParameterInfoBuilder &PInfos) {
+ Sema::ExtParameterInfoBuilder &PInfos,
+ unsigned *LastParamTransformed) {
int indexAdjustment = 0;
unsigned NumParams = Params.size();
for (unsigned i = 0; i != NumParams; ++i) {
+ if (LastParamTransformed)
+ *LastParamTransformed = i;
if (ParmVarDecl *OldParm = Params[i]) {
assert(OldParm->getFunctionScopeIndex() == i);
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
ParmVarDecl *NewParm = nullptr;
if (OldParm->isParameterPack()) {
// We have a function parameter pack that may need to be expanded.
@@ -5688,7 +5788,7 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions;
if (Unexpanded.size() > 0) {
OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions();
NumExpansions = OrigNumExpansions;
@@ -5771,7 +5871,8 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
"transformation.");
} else {
NewParm = getDerived().TransformFunctionTypeParam(
- OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false);
+ OldParm, indexAdjustment, std::nullopt,
+ /*ExpectParameterPack=*/false);
}
if (!NewParm)
@@ -5787,14 +5888,16 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
// Deal with the possibility that we don't have a parameter
// declaration for this parameter.
+ assert(ParamTypes);
QualType OldType = ParamTypes[i];
bool IsPackExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
QualType NewType;
if (const PackExpansionType *Expansion
= dyn_cast<PackExpansionType>(OldType)) {
// We have a function parameter pack that may need to be expanded.
QualType Pattern = Expansion->getPattern();
+ NumExpansions = Expansion->getNumExpansions();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded);
@@ -5819,8 +5922,8 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
return true;
if (NewType->containsUnexpandedParameterPack()) {
- NewType =
- getSema().getASTContext().getPackExpansionType(NewType, None);
+ NewType = getSema().getASTContext().getPackExpansionType(
+ NewType, std::nullopt);
if (NewType.isNull())
return true;
@@ -5965,8 +6068,8 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
if (auto NewExtParamInfos =
ExtParamInfos.getPointerOrNull(ParamTypes.size())) {
if (!EPI.ExtParameterInfos ||
- llvm::makeArrayRef(EPI.ExtParameterInfos, TL.getNumParams())
- != llvm::makeArrayRef(NewExtParamInfos, ParamTypes.size())) {
+ llvm::ArrayRef(EPI.ExtParameterInfos, TL.getNumParams()) !=
+ llvm::ArrayRef(NewExtParamInfos, ParamTypes.size())) {
EPIChanged = true;
}
EPI.ExtParameterInfos = NewExtParamInfos;
@@ -5977,7 +6080,7 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() ||
- T->getParamTypes() != llvm::makeArrayRef(ParamTypes) || EPIChanged) {
+ T->getParamTypes() != llvm::ArrayRef(ParamTypes) || EPIChanged) {
Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI);
if (Result.isNull())
return QualType();
@@ -6041,7 +6144,7 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
// be expanded.
bool Expand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
// FIXME: Track the location of the ellipsis (and track source location
// information for the types in the exception specification in general).
if (getDerived().TryExpandParameterPacks(
@@ -6203,13 +6306,13 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
return QualType();
QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- E.get() != TL.getUnderlyingExpr()) {
- Result = getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc());
+ TypeOfKind Kind = Result->getAs<TypeOfExprType>()->getKind();
+ if (getDerived().AlwaysRebuild() || E.get() != TL.getUnderlyingExpr()) {
+ Result =
+ getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc(), Kind);
if (Result.isNull())
return QualType();
}
- else E.get();
TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result);
NewTL.setTypeofLoc(TL.getTypeofLoc());
@@ -6222,14 +6325,15 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
template<typename Derived>
QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
TypeOfTypeLoc TL) {
- TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo();
+ TypeSourceInfo* Old_Under_TI = TL.getUnmodifiedTInfo();
TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI);
if (!New_Under_TI)
return QualType();
QualType Result = TL.getType();
+ TypeOfKind Kind = Result->getAs<TypeOfType>()->getKind();
if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) {
- Result = getDerived().RebuildTypeOfType(New_Under_TI->getType());
+ Result = getDerived().RebuildTypeOfType(New_Under_TI->getType(), Kind);
if (Result.isNull())
return QualType();
}
@@ -6238,7 +6342,7 @@ QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
NewTL.setTypeofLoc(TL.getTypeofLoc());
NewTL.setLParenLoc(TL.getLParenLoc());
NewTL.setRParenLoc(TL.getRParenLoc());
- NewTL.setUnderlyingTInfo(New_Under_TI);
+ NewTL.setUnmodifiedTInfo(New_Under_TI);
return Result;
}
@@ -6395,6 +6499,14 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
TypeLocBuilder &TLB,
TemplateTypeParmTypeLoc TL) {
+ return getDerived().TransformTemplateTypeParmType(
+ TLB, TL,
+ /*SuppressObjCLifetime=*/false);
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
+ TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL, bool) {
return TransformTypeSpecType(TLB, TL);
}
@@ -6404,6 +6516,9 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
SubstTemplateTypeParmTypeLoc TL) {
const SubstTemplateTypeParmType *T = TL.getTypePtr();
+ Decl *NewReplaced =
+ getDerived().TransformDecl(TL.getNameLoc(), T->getAssociatedDecl());
+
// Substitute into the replacement type, which itself might involve something
// that needs to be transformed. This only tends to occur with default
// template arguments of template template parameters.
@@ -6412,11 +6527,8 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
if (Replacement.isNull())
return QualType();
- // Always canonicalize the replacement type.
- Replacement = SemaRef.Context.getCanonicalType(Replacement);
- QualType Result
- = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(),
- Replacement);
+ QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(
+ Replacement, NewReplaced, T->getIndex(), T->getPackIndex());
// Propagate type-source information.
SubstTemplateTypeParmTypeLoc NewTL
@@ -6430,6 +6542,13 @@ template<typename Derived>
QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType(
TypeLocBuilder &TLB,
SubstTemplateTypeParmPackTypeLoc TL) {
+ return getDerived().TransformSubstTemplateTypeParmPackType(
+ TLB, TL, /*SuppressObjCLifetime=*/false);
+}
+
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType(
+ TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL, bool) {
return TransformTypeSpecType(TLB, TL);
}
@@ -6750,12 +6869,9 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType(
// FIXME: maybe don't rebuild if all the template arguments are the same.
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
- QualType Result
- = getSema().Context.getDependentTemplateSpecializationType(
- TL.getTypePtr()->getKeyword(),
- DTN->getQualifier(),
- DTN->getIdentifier(),
- NewTemplateArgs);
+ QualType Result = getSema().Context.getDependentTemplateSpecializationType(
+ TL.getTypePtr()->getKeyword(), DTN->getQualifier(),
+ DTN->getIdentifier(), NewTemplateArgs.arguments());
DependentTemplateSpecializationTypeLoc NewTL
= TLB.push<DependentTemplateSpecializationTypeLoc>(Result);
@@ -7113,12 +7229,10 @@ TreeTransform<Derived>::TransformObjCTypeParamType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
OTP != T->getDecl()) {
- Result = getDerived().RebuildObjCTypeParamType(OTP,
- TL.getProtocolLAngleLoc(),
- llvm::makeArrayRef(TL.getTypePtr()->qual_begin(),
- TL.getNumProtocols()),
- TL.getProtocolLocs(),
- TL.getProtocolRAngleLoc());
+ Result = getDerived().RebuildObjCTypeParamType(
+ OTP, TL.getProtocolLAngleLoc(),
+ llvm::ArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()),
+ TL.getProtocolLocs(), TL.getProtocolRAngleLoc());
if (Result.isNull())
return QualType();
}
@@ -7166,7 +7280,7 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc();
bool Expand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
+ std::optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
if (getDerived().TryExpandParameterPacks(
PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
Unexpanded, Expand, RetainExpansion, NumExpansions))
@@ -7216,7 +7330,8 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
TypeLocBuilder TypeArgBuilder;
TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize());
- QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc);
+ QualType NewTypeArg =
+ getDerived().TransformType(TypeArgBuilder, TypeArgLoc);
if (NewTypeArg.isNull())
return QualType();
@@ -7237,7 +7352,7 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
Result = getDerived().RebuildObjCObjectType(
BaseType, TL.getBeginLoc(), TL.getTypeArgsLAngleLoc(), NewTypeArgInfos,
TL.getTypeArgsRAngleLoc(), TL.getProtocolLAngleLoc(),
- llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()),
+ llvm::ArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()),
TL.getProtocolLocs(), TL.getProtocolRAngleLoc());
if (Result.isNull())
@@ -7483,7 +7598,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
}
// If this is a constexpr if, determine which arm we should instantiate.
- llvm::Optional<bool> ConstexprConditionValue;
+ std::optional<bool> ConstexprConditionValue;
if (S->isConstexpr())
ConstexprConditionValue = Cond.getKnownValue();
@@ -7800,8 +7915,7 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
- ArrayRef<Token> AsmToks =
- llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks());
+ ArrayRef<Token> AsmToks = llvm::ArrayRef(S->getAsmToks(), S->getNumAsmToks());
bool HadError = false, HadChange = false;
@@ -8839,6 +8953,17 @@ TreeTransform<Derived>::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
}
template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPErrorDirective(OMPErrorDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_error, DirName, nullptr,
+ D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPTaskgroupDirective(
OMPTaskgroupDirective *D) {
DeclarationNameInfo DirName;
@@ -9676,17 +9801,17 @@ OMPClause *TreeTransform<Derived>::TransformOMPInitClause(OMPInitClause *C) {
if (IVR.isInvalid())
return nullptr;
- llvm::SmallVector<Expr *, 8> PrefExprs;
- PrefExprs.reserve(C->varlist_size() - 1);
+ OMPInteropInfo InteropInfo(C->getIsTarget(), C->getIsTargetSync());
+ InteropInfo.PreferTypes.reserve(C->varlist_size() - 1);
for (Expr *E : llvm::drop_begin(C->varlists())) {
ExprResult ER = getDerived().TransformExpr(cast<Expr>(E));
if (ER.isInvalid())
return nullptr;
- PrefExprs.push_back(ER.get());
+ InteropInfo.PreferTypes.push_back(ER.get());
}
- return getDerived().RebuildOMPInitClause(
- IVR.get(), PrefExprs, C->getIsTarget(), C->getIsTargetSync(),
- C->getBeginLoc(), C->getLParenLoc(), C->getVarLoc(), C->getEndLoc());
+ return getDerived().RebuildOMPInitClause(IVR.get(), InteropInfo,
+ C->getBeginLoc(), C->getLParenLoc(),
+ C->getVarLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -9786,6 +9911,32 @@ OMPClause *TreeTransform<Derived>::TransformOMPAtomicDefaultMemOrderClause(
}
template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPAtClause(OMPAtClause *C) {
+ return getDerived().RebuildOMPAtClause(C->getAtKind(), C->getAtKindKwLoc(),
+ C->getBeginLoc(), C->getLParenLoc(),
+ C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPSeverityClause(OMPSeverityClause *C) {
+ return getDerived().RebuildOMPSeverityClause(
+ C->getSeverityKind(), C->getSeverityKindKwLoc(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPMessageClause(OMPMessageClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getMessageString());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPMessageClause(
+ C->getMessageString(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getEndLoc());
+}
+
+template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
@@ -10168,6 +10319,13 @@ template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) {
OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
llvm::SmallVector<Expr *, 16> Vars;
+ Expr *IteratorModifier = C->getIteratorModifier();
+ if (IteratorModifier) {
+ ExprResult MapModRes = getDerived().TransformExpr(IteratorModifier);
+ if (MapModRes.isInvalid())
+ return nullptr;
+ IteratorModifier = MapModRes.get();
+ }
CXXScopeSpec MapperIdScopeSpec;
DeclarationNameInfo MapperIdInfo;
llvm::SmallVector<Expr *, 16> UnresolvedMappers;
@@ -10175,9 +10333,9 @@ OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) {
*this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers))
return nullptr;
return getDerived().RebuildOMPMapClause(
- C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), MapperIdScopeSpec,
- MapperIdInfo, C->getMapType(), C->isImplicitMapType(), C->getMapLoc(),
- C->getColonLoc(), Vars, Locs, UnresolvedMappers);
+ IteratorModifier, C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(),
+ MapperIdScopeSpec, MapperIdInfo, C->getMapType(), C->isImplicitMapType(),
+ C->getMapLoc(), C->getColonLoc(), Vars, Locs, UnresolvedMappers);
}
template <typename Derived>
@@ -10240,7 +10398,8 @@ TreeTransform<Derived>::TransformOMPGrainsizeClause(OMPGrainsizeClause *C) {
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPGrainsizeClause(
- E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ C->getModifier(), E.get(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getModifierLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -10250,7 +10409,8 @@ TreeTransform<Derived>::TransformOMPNumTasksClause(OMPNumTasksClause *C) {
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPNumTasksClause(
- E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ C->getModifier(), E.get(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getModifierLoc(), C->getEndLoc());
}
template <typename Derived>
@@ -10472,9 +10632,9 @@ TreeTransform<Derived>::TransformOMPAffinityClause(OMPAffinityClause *C) {
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPOrderClause(OMPOrderClause *C) {
- return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(),
- C->getBeginLoc(), C->getLParenLoc(),
- C->getEndLoc());
+ return getDerived().RebuildOMPOrderClause(
+ C->getKind(), C->getKindKwLoc(), C->getBeginLoc(), C->getLParenLoc(),
+ C->getEndLoc(), C->getModifier(), C->getModifierKwLoc());
}
template <typename Derived>
@@ -10484,6 +10644,16 @@ OMPClause *TreeTransform<Derived>::TransformOMPBindClause(OMPBindClause *C) {
C->getLParenLoc(), C->getEndLoc());
}
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPXDynCGroupMemClause(
+ OMPXDynCGroupMemClause *C) {
+ ExprResult Size = getDerived().TransformExpr(C->getSize());
+ if (Size.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPXDynCGroupMemClause(
+ Size.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -11190,7 +11360,7 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
return getDerived().RebuildBinaryOperator(
E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get());
Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
- FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts()));
+ FPOptionsOverride NewOverrides(E->getFPFeatures());
getSema().CurFPFeatures =
NewOverrides.applyOverrides(getSema().getLangOpts());
getSema().FpPragmaStack.CurrentValue = NewOverrides;
@@ -11257,7 +11427,7 @@ ExprResult
TreeTransform<Derived>::TransformCompoundAssignOperator(
CompoundAssignOperator *E) {
Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
- FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts()));
+ FPOptionsOverride NewOverrides(E->getFPFeatures());
getSema().CurFPFeatures =
NewOverrides.applyOverrides(getSema().getLangOpts());
getSema().FpPragmaStack.CurrentValue = NewOverrides;
@@ -11389,9 +11559,9 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) {
// FIXME: Bad source location
SourceLocation FakeOperatorLoc =
SemaRef.getLocForEndOfToken(E->getBase()->getEndLoc());
- return getDerived().RebuildExtVectorElementExpr(Base.get(), FakeOperatorLoc,
- E->getAccessorLoc(),
- E->getAccessor());
+ return getDerived().RebuildExtVectorElementExpr(
+ Base.get(), FakeOperatorLoc, E->isArrow(), E->getAccessorLoc(),
+ E->getAccessor());
}
template<typename Derived>
@@ -12024,11 +12194,20 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!Param)
return ExprError();
+ ExprResult InitRes;
+ if (E->hasRewrittenInit()) {
+ InitRes = getDerived().TransformExpr(E->getRewrittenExpr());
+ if (InitRes.isInvalid())
+ return ExprError();
+ }
+
if (!getDerived().AlwaysRebuild() && Param == E->getParam() &&
- E->getUsedContext() == SemaRef.CurContext)
+ E->getUsedContext() == SemaRef.CurContext &&
+ InitRes.get() == E->getRewrittenExpr())
return E;
- return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param);
+ return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param,
+ InitRes.get());
}
template<typename Derived>
@@ -12073,10 +12252,10 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
return ExprError();
// Transform the size of the array we're allocating (if any).
- Optional<Expr *> ArraySize;
+ std::optional<Expr *> ArraySize;
if (E->isArray()) {
ExprResult NewArraySize;
- if (Optional<Expr *> OldArraySize = E->getArraySize()) {
+ if (std::optional<Expr *> OldArraySize = E->getArraySize()) {
NewArraySize = getDerived().TransformExpr(*OldArraySize);
if (NewArraySize.isInvalid())
return ExprError();
@@ -12455,9 +12634,9 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions =
+ std::optional<unsigned> OrigNumExpansions =
ExpansionTL.getTypePtr()->getNumExpansions();
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
PatternTL.getSourceRange(),
Unexpanded,
@@ -12578,7 +12757,8 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) {
// C++2a [expr.prim.req]p2
// Expressions appearing within a requirement-body are unevaluated operands.
EnterExpressionEvaluationContext Ctx(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(
getSema().Context, getSema().CurContext,
@@ -12586,16 +12766,20 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) {
Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false);
- if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(),
- E->getLocalParameters(),
- /*ParamTypes=*/nullptr,
- /*ParamInfos=*/nullptr,
- TransParamTypes, &TransParams,
- ExtParamInfos))
- return ExprError();
+ ExprResult TypeParamResult = getDerived().TransformRequiresTypeParams(
+ E->getRequiresKWLoc(), E->getRBraceLoc(), E, Body,
+ E->getLocalParameters(), TransParamTypes, TransParams, ExtParamInfos);
for (ParmVarDecl *Param : TransParams)
- Param->setDeclContext(Body);
+ if (Param)
+ Param->setDeclContext(Body);
+
+ // On failure to transform, TransformRequiresTypeParams returns an expression
+ // in the event that the transformation of the type params failed in some way.
+ // It is expected that this will result in a 'not satisfied' Requires clause
+ // when instantiating.
+ if (!TypeParamResult.isUnset())
+ return TypeParamResult;
SmallVector<concepts::Requirement *, 4> TransReqs;
if (getDerived().TransformRequiresExprRequirements(E->getRequirements(),
@@ -12668,7 +12852,7 @@ TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req)
TransExpr = TransExprRes.get();
}
- llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
+ std::optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq;
const auto &RetReq = Req->getReturnTypeRequirement();
if (RetReq.isEmpty())
TransRetReq.emplace();
@@ -12697,10 +12881,10 @@ template<typename Derived>
concepts::NestedRequirement *
TreeTransform<Derived>::TransformNestedRequirement(
concepts::NestedRequirement *Req) {
- if (Req->isSubstitutionFailure()) {
+ if (Req->hasInvalidConstraint()) {
if (getDerived().AlwaysRebuild())
return getDerived().RebuildNestedRequirement(
- Req->getSubstitutionDiagnostic());
+ Req->getInvalidConstraintEntity(), Req->getConstraintSatisfaction());
return Req;
}
ExprResult TransConstraint =
@@ -12990,10 +13174,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
continue;
TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()];
- VarDecl *OldVD = C->getCapturedVar();
+ auto *OldVD = cast<VarDecl>(C->getCapturedVar());
auto SubstInitCapture = [&](SourceLocation EllipsisLoc,
- Optional<unsigned> NumExpansions) {
+ std::optional<unsigned> NumExpansions) {
ExprResult NewExprInitResult = getDerived().TransformInitializer(
OldVD->getInit(), OldVD->getInitStyle() == VarDecl::CallInit);
@@ -13005,9 +13189,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
QualType NewInitCaptureType =
getSema().buildLambdaInitCaptureInitialization(
- C->getLocation(), OldVD->getType()->isReferenceType(),
+ C->getLocation(), C->getCaptureKind() == LCK_ByRef,
EllipsisLoc, NumExpansions, OldVD->getIdentifier(),
- C->getCapturedVar()->getInitStyle() != VarDecl::CInit,
+ cast<VarDecl>(C->getCapturedVar())->getInitStyle() !=
+ VarDecl::CInit,
NewExprInit);
Result.Expansions.push_back(
InitCaptureInfoTy(NewExprInit, NewInitCaptureType));
@@ -13025,9 +13210,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions =
+ std::optional<unsigned> OrigNumExpansions =
ExpansionTL.getTypePtr()->getNumExpansions();
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(
ExpansionTL.getEllipsisLoc(),
OldVD->getInit()->getSourceRange(), Unexpanded, Expand,
@@ -13036,7 +13221,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
- SubstInitCapture(SourceLocation(), None);
+ SubstInitCapture(SourceLocation(), std::nullopt);
}
}
if (!Expand || RetainExpansion) {
@@ -13045,7 +13230,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
Result.EllipsisLoc = ExpansionTL.getEllipsisLoc();
}
} else {
- SubstInitCapture(SourceLocation(), None);
+ SubstInitCapture(SourceLocation(), std::nullopt);
}
}
@@ -13083,23 +13268,17 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewCallOpType);
}
- // Transform the trailing requires clause
- ExprResult NewTrailingRequiresClause;
- if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause())
- // FIXME: Concepts: Substitution into requires clause should only happen
- // when checking satisfaction.
- NewTrailingRequiresClause = getDerived().TransformExpr(TRC);
-
// Create the local class that will describe the lambda.
// FIXME: DependencyKind below is wrong when substituting inside a templated
// context that isn't a DeclContext (such as a variable template), or when
// substituting an unevaluated lambda inside of a function's parameter's type
// - as parameter types are not instantiated from within a function's DC. We
- // use isUnevaluatedContext() to distinguish the function parameter case.
+ // use evaluation contexts to distinguish the function parameter case.
CXXRecordDecl::LambdaDependencyKind DependencyKind =
CXXRecordDecl::LDK_Unknown;
- if (getSema().isUnevaluatedContext() &&
+ if ((getSema().isUnevaluatedContext() ||
+ getSema().isConstantEvaluatedContext()) &&
(getSema().CurContext->isFileContext() ||
!getSema().CurContext->getParent()->isDependentContext()))
DependencyKind = CXXRecordDecl::LDK_NeverDependent;
@@ -13111,7 +13290,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getDerived().transformedLocalDecl(OldClass, {Class});
- Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
+ std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
if (getDerived().ReplacingOriginal())
Mangling = std::make_tuple(OldClass->hasKnownLambdaInternalLinkage(),
OldClass->getLambdaManglingNumber(),
@@ -13124,7 +13303,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
E->getCallOperator()->getConstexprKind(),
- NewTrailingRequiresClause.get());
+ E->getCallOperator()->getStorageClass(),
+ E->getCallOperator()->getTrailingRequiresClause());
LSI->CallOperator = NewCallOperator;
@@ -13174,7 +13354,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
if (E->isInitCapture(C)) {
TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()];
- VarDecl *OldVD = C->getCapturedVar();
+ auto *OldVD = cast<VarDecl>(C->getCapturedVar());
llvm::SmallVector<Decl*, 4> NewVDs;
for (InitCaptureInfoTy &Info : NewC.Expansions) {
@@ -13192,7 +13372,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
break;
}
NewVDs.push_back(NewVD);
- getSema().addInitCapture(LSI, NewVD);
+ getSema().addInitCapture(LSI, NewVD, C->getCaptureKind() == LCK_ByRef);
}
if (Invalid)
@@ -13215,7 +13395,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation());
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
C->getLocation(),
Unexpanded,
@@ -13229,7 +13409,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// The transform has determined that we should perform an expansion;
// transform and capture each of the arguments.
// expansion of the pattern. Do so.
- VarDecl *Pack = C->getCapturedVar();
+ auto *Pack = cast<VarDecl>(C->getCapturedVar());
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
VarDecl *CapturedVar
@@ -13253,9 +13433,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
}
// Transform the captured variable.
- VarDecl *CapturedVar
- = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
- C->getCapturedVar()));
+ auto *CapturedVar = cast_or_null<ValueDecl>(
+ getDerived().TransformDecl(C->getLocation(), C->getCapturedVar()));
if (!CapturedVar || CapturedVar->isInvalidDecl()) {
Invalid = true;
continue;
@@ -13592,7 +13771,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> NumExpansions;
+ std::optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
Unexpanded,
ShouldExpand, RetainExpansion,
@@ -13605,9 +13784,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
auto *Pack = E->getPack();
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Pack)) {
ArgStorage = getSema().Context.getPackExpansionType(
- getSema().Context.getTypeDeclType(TTPD), None);
+ getSema().Context.getTypeDeclType(TTPD), std::nullopt);
} else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Pack)) {
- ArgStorage = TemplateArgument(TemplateName(TTPD), None);
+ ArgStorage = TemplateArgument(TemplateName(TTPD), std::nullopt);
} else {
auto *VD = cast<ValueDecl>(Pack);
ExprResult DRE = getSema().BuildDeclRefExpr(
@@ -13616,8 +13795,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
E->getPackLoc());
if (DRE.isInvalid())
return ExprError();
- ArgStorage = new (getSema().Context) PackExpansionExpr(
- getSema().Context.DependentTy, DRE.get(), E->getPackLoc(), None);
+ ArgStorage = new (getSema().Context)
+ PackExpansionExpr(getSema().Context.DependentTy, DRE.get(),
+ E->getPackLoc(), std::nullopt);
}
PackArgs = ArgStorage;
}
@@ -13629,13 +13809,13 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
getDerived().TransformDecl(E->getPackLoc(), E->getPack()));
if (!Pack)
return ExprError();
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack,
- E->getPackLoc(),
- E->getRParenLoc(), None, None);
+ return getDerived().RebuildSizeOfPackExpr(
+ E->getOperatorLoc(), Pack, E->getPackLoc(), E->getRParenLoc(),
+ std::nullopt, std::nullopt);
}
// Try to compute the result without performing a partial substitution.
- Optional<unsigned> Result = 0;
+ std::optional<unsigned> Result = 0;
for (const TemplateArgument &Arg : PackArgs) {
if (!Arg.isPackExpansion()) {
Result = *Result + 1;
@@ -13647,7 +13827,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
// Find the pattern of the pack expansion.
SourceLocation Ellipsis;
- Optional<unsigned> OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions;
TemplateArgumentLoc Pattern =
getSema().getTemplateArgumentPackExpansionPattern(ArgLoc, Ellipsis,
OrigNumExpansions);
@@ -13660,12 +13840,12 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
return true;
// See if we can determine the number of arguments from the result.
- Optional<unsigned> NumExpansions =
+ std::optional<unsigned> NumExpansions =
getSema().getFullyPackExpandedSize(OutPattern.getArgument());
if (!NumExpansions) {
// No: we must be in an alias template expansion, and we're going to need
// to actually expand the packs.
- Result = None;
+ Result = std::nullopt;
break;
}
@@ -13675,9 +13855,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
// Common case: we could determine the number of expansions without
// substituting.
if (Result)
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
- E->getPackLoc(),
- E->getRParenLoc(), *Result, None);
+ return getDerived().RebuildSizeOfPackExpr(
+ E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(),
+ *Result, std::nullopt);
TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(),
E->getPackLoc());
@@ -13702,13 +13882,13 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
}
if (PartialSubstitution)
- return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
- E->getPackLoc(),
- E->getRParenLoc(), None, Args);
+ return getDerived().RebuildSizeOfPackExpr(
+ E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(),
+ std::nullopt, Args);
return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(),
E->getPackLoc(), E->getRParenLoc(),
- Args.size(), None);
+ Args.size(), std::nullopt);
}
template<typename Derived>
@@ -13762,8 +13942,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions = E->getNumExpansions(),
- NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions = E->getNumExpansions(),
+ NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(),
Pattern->getSourceRange(),
Unexpanded,
@@ -13887,6 +14067,20 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
return Result;
}
+template <typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) {
+ SmallVector<Expr *, 4> TransformedInits;
+ ArrayRef<Expr *> InitExprs = E->getInitExprs();
+ if (TransformExprs(InitExprs.data(), InitExprs.size(), true,
+ TransformedInits))
+ return ExprError();
+
+ return getDerived().RebuildCXXParenListInitExpr(
+ TransformedInits, E->getType(), E->getUserSpecifiedInitExprs().size(),
+ E->getInitLoc(), E->getBeginLoc(), E->getEndLoc());
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXStdInitializerListExpr(
@@ -13959,8 +14153,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
// and should be expanded.
bool Expand = true;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
- Optional<unsigned> NumExpansions = OrigNumExpansions;
+ std::optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
+ std::optional<unsigned> NumExpansions = OrigNumExpansions;
SourceRange PatternRange(OrigElement.Key->getBeginLoc(),
OrigElement.Value->getEndLoc());
if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc,
@@ -14047,9 +14241,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
if (Value.get() != OrigElement.Value)
ArgChanged = true;
- ObjCDictionaryElement Element = {
- Key.get(), Value.get(), SourceLocation(), None
- };
+ ObjCDictionaryElement Element = {Key.get(), Value.get(), SourceLocation(),
+ std::nullopt};
Elements.push_back(Element);
}
@@ -14506,11 +14699,11 @@ QualType TreeTransform<Derived>::RebuildObjCObjectType(
ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc) {
- return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc,
- TypeArgs, TypeArgsRAngleLoc,
- ProtocolLAngleLoc, Protocols, ProtocolLocs,
- ProtocolRAngleLoc,
- /*FailOnError=*/true);
+ return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, TypeArgs,
+ TypeArgsRAngleLoc, ProtocolLAngleLoc,
+ Protocols, ProtocolLocs, ProtocolRAngleLoc,
+ /*FailOnError=*/true,
+ /*Rebuilding=*/true);
}
template<typename Derived>
@@ -14538,11 +14731,10 @@ TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy,
SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty
};
- const unsigned NumTypes = llvm::array_lengthof(Types);
QualType SizeType;
- for (unsigned I = 0; I != NumTypes; ++I)
- if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) {
- SizeType = Types[I];
+ for (const auto &T : Types)
+ if (Size->getBitWidth() == SemaRef.Context.getIntWidth(T)) {
+ SizeType = T;
break;
}
@@ -14733,14 +14925,15 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc,
}
template <typename Derived>
-QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E,
- SourceLocation) {
- return SemaRef.BuildTypeofExprType(E);
+QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E, SourceLocation,
+ TypeOfKind Kind) {
+ return SemaRef.BuildTypeofExprType(E, Kind);
}
template<typename Derived>
-QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) {
- return SemaRef.Context.getTypeOfType(Underlying);
+QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying,
+ TypeOfKind Kind) {
+ return SemaRef.Context.getTypeOfType(Underlying, Kind);
}
template <typename Derived>
diff --git a/clang/lib/Sema/TypeLocBuilder.cpp b/clang/lib/Sema/TypeLocBuilder.cpp
index 2dcbbd83c691..fcd090ff2020 100644
--- a/clang/lib/Sema/TypeLocBuilder.cpp
+++ b/clang/lib/Sema/TypeLocBuilder.cpp
@@ -41,6 +41,29 @@ void TypeLocBuilder::pushFullCopy(TypeLoc L) {
}
}
+void TypeLocBuilder::pushTrivial(ASTContext &Context, QualType T,
+ SourceLocation Loc) {
+ auto L = TypeLoc(T, nullptr);
+ reserve(L.getFullDataSize());
+
+ SmallVector<TypeLoc, 4> TypeLocs;
+ for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc())
+ TypeLocs.push_back(CurTL);
+
+ for (const auto &CurTL : llvm::reverse(TypeLocs)) {
+ switch (CurTL.getTypeLocClass()) {
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ case TypeLoc::CLASS: { \
+ auto NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
+ NewTL.initializeLocal(Context, Loc); \
+ break; \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ }
+ }
+}
+
void TypeLocBuilder::grow(size_t NewCapacity) {
assert(NewCapacity > Capacity);
@@ -85,7 +108,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli
// FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
// hardcode them.
if (LocalAlignment == 4) {
- if (NumBytesAtAlign8 == 0) {
+ if (!AtAlign8) {
NumBytesAtAlign4 += LocalSize;
} else {
unsigned Padding = NumBytesAtAlign4 % 8;
@@ -114,7 +137,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli
NumBytesAtAlign4 += LocalSize;
}
} else if (LocalAlignment == 8) {
- if (NumBytesAtAlign8 == 0) {
+ if (!AtAlign8) {
// We have not seen any 8-byte aligned element yet. We insert a padding
// only if the new Index is not 8-byte-aligned.
if ((Index - LocalSize) % 8 != 0) {
@@ -149,7 +172,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli
// Forget about any padding.
NumBytesAtAlign4 = 0;
- NumBytesAtAlign8 += LocalSize;
+ AtAlign8 = true;
} else {
assert(LocalSize == 0);
}
diff --git a/clang/lib/Sema/TypeLocBuilder.h b/clang/lib/Sema/TypeLocBuilder.h
index 738f731c9fe2..d413d74b74ff 100644
--- a/clang/lib/Sema/TypeLocBuilder.h
+++ b/clang/lib/Sema/TypeLocBuilder.h
@@ -40,12 +40,13 @@ class TypeLocBuilder {
/// The inline buffer.
enum { BufferMaxAlignment = alignof(void *) };
alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity];
- unsigned NumBytesAtAlign4, NumBytesAtAlign8;
+ unsigned NumBytesAtAlign4;
+ bool AtAlign8;
public:
TypeLocBuilder()
: Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity),
- NumBytesAtAlign4(0), NumBytesAtAlign8(0) {}
+ NumBytesAtAlign4(0), AtAlign8(false) {}
~TypeLocBuilder() {
if (Buffer != InlineBuffer)
@@ -63,6 +64,10 @@ public:
/// must be empty for this to work.
void pushFullCopy(TypeLoc L);
+ /// Pushes 'T' with all locations pointing to 'Loc'.
+ /// The builder must be empty for this to work.
+ void pushTrivial(ASTContext &Context, QualType T, SourceLocation Loc);
+
/// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs
/// previously retrieved from this builder.
TypeSpecTypeLoc pushTypeSpec(QualType T) {
@@ -77,7 +82,8 @@ public:
LastTy = QualType();
#endif
Index = Capacity;
- NumBytesAtAlign4 = NumBytesAtAlign8 = 0;
+ NumBytesAtAlign4 = 0;
+ AtAlign8 = false;
}
/// Tell the TypeLocBuilder that the type it is storing has been
diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h
index 24b7342b3fb4..580d702f96fe 100644
--- a/clang/lib/Sema/UsedDeclVisitor.h
+++ b/clang/lib/Sema/UsedDeclVisitor.h
@@ -82,11 +82,28 @@ public:
void VisitCXXConstructExpr(CXXConstructExpr *E) {
asImpl().visitUsedDecl(E->getBeginLoc(), E->getConstructor());
+ CXXConstructorDecl *D = E->getConstructor();
+ for (const CXXCtorInitializer *Init : D->inits()) {
+ if (Init->isInClassMemberInitializer())
+ asImpl().Visit(Init->getInit());
+ }
Inherited::VisitCXXConstructExpr(E);
}
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
asImpl().Visit(E->getExpr());
+ Inherited::VisitCXXDefaultArgExpr(E);
+ }
+
+ void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ asImpl().Visit(E->getExpr());
+ Inherited::VisitCXXDefaultInitExpr(E);
+ }
+
+ void VisitInitListExpr(InitListExpr *ILE) {
+ if (ILE->hasArrayFiller())
+ asImpl().Visit(ILE->getArrayFiller());
+ Inherited::VisitInitListExpr(ILE);
}
void visitUsedDecl(SourceLocation Loc, Decl *D) {
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index 26b722b6b14a..96bc47dcdb4e 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -412,6 +412,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::PragmaComment:
case Decl::PragmaDetectMismatch:
case Decl::FileScopeAsm:
+ case Decl::TopLevelStmt:
case Decl::AccessSpec:
case Decl::Friend:
case Decl::FriendTemplate:
@@ -430,9 +431,11 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Decomposition:
case Decl::Binding:
case Decl::Concept:
+ case Decl::ImplicitConceptSpecialization:
case Decl::LifetimeExtendedTemporary:
case Decl::RequiresExprBody:
case Decl::UnresolvedUsingIfExists:
+ case Decl::HLSLBuffer:
return false;
// These indirectly derive from Redeclarable<T> but are not actually
@@ -472,7 +475,7 @@ bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) {
if (auto *VD = dyn_cast<VarDecl>(D))
return VD->isStaticLocal();
// FIXME: What about CapturedDecls (and declarations nested within them)?
- return isa<TagDecl>(D) || isa<BlockDecl>(D);
+ return isa<TagDecl, BlockDecl>(D);
}
// Otherwise, we only care about anonymous class members / block-scope decls.
@@ -482,5 +485,5 @@ bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) {
return false;
if (!isa<RecordDecl, ObjCInterfaceDecl>(D->getLexicalDeclContext()))
return false;
- return isa<TagDecl>(D) || isa<FieldDecl>(D);
+ return isa<TagDecl, FieldDecl>(D);
}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 76281d26b2ae..4d72596b7439 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/ODRDiagsEmitter.h"
#include "clang/AST/ODRHash.h"
#include "clang/AST/OpenMPClause.h"
#include "clang/AST/RawCommentList.h"
@@ -96,8 +97,6 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -121,6 +120,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/raw_ostream.h"
@@ -134,6 +134,7 @@
#include <limits>
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include <system_error>
#include <tuple>
@@ -624,20 +625,28 @@ collectMacroDefinitions(const PreprocessorOptions &PPOpts,
}
}
+enum OptionValidation {
+ OptionValidateNone,
+ OptionValidateContradictions,
+ OptionValidateStrictMatches,
+};
+
/// Check the preprocessor options deserialized from the control block
/// against the preprocessor options in an existing preprocessor.
///
/// \param Diags If non-null, produce diagnostics for any mismatches incurred.
-/// \param Validate If true, validate preprocessor options. If false, allow
-/// macros defined by \p ExistingPPOpts to override those defined by
-/// \p PPOpts in SuggestedPredefines.
-static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
- const PreprocessorOptions &ExistingPPOpts,
- DiagnosticsEngine *Diags,
- FileManager &FileMgr,
- std::string &SuggestedPredefines,
- const LangOptions &LangOpts,
- bool Validate = true) {
+/// \param Validation If set to OptionValidateNone, ignore differences in
+/// preprocessor options. If set to OptionValidateContradictions,
+/// require that options passed both in the AST file and on the command
+/// line (-D or -U) match, but tolerate options missing in one or the
+/// other. If set to OptionValidateContradictions, require that there
+/// are no differences in the options between the two.
+static bool checkPreprocessorOptions(
+ const PreprocessorOptions &PPOpts,
+ const PreprocessorOptions &ExistingPPOpts, DiagnosticsEngine *Diags,
+ FileManager &FileMgr, std::string &SuggestedPredefines,
+ const LangOptions &LangOpts,
+ OptionValidation Validation = OptionValidateContradictions) {
// Check macro definitions.
MacroDefinitionsMap ASTFileMacros;
collectMacroDefinitions(PPOpts, ASTFileMacros);
@@ -653,7 +662,15 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
// Check whether we know anything about this macro name or not.
llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/>>::iterator Known =
ASTFileMacros.find(MacroName);
- if (!Validate || Known == ASTFileMacros.end()) {
+ if (Validation == OptionValidateNone || Known == ASTFileMacros.end()) {
+ if (Validation == OptionValidateStrictMatches) {
+ // If strict matches are requested, don't tolerate any extra defines on
+ // the command line that are missing in the AST file.
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_undef) << MacroName << true;
+ }
+ return true;
+ }
// FIXME: Check whether this identifier was referenced anywhere in the
// AST file. If so, we should reject the AST file. Unfortunately, this
// information isn't in the control block. What shall we do about it?
@@ -684,8 +701,10 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
// If the macro was #undef'd in both, or if the macro bodies are identical,
// it's fine.
- if (Existing.second || Existing.first == Known->second.first)
+ if (Existing.second || Existing.first == Known->second.first) {
+ ASTFileMacros.erase(Known);
continue;
+ }
// The macro bodies differ; complain.
if (Diags) {
@@ -694,9 +713,20 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
}
return true;
}
+ if (Validation == OptionValidateStrictMatches) {
+ // If strict matches are requested, don't tolerate any extra defines in
+ // the AST file that are missing on the command line.
+ for (const auto &MacroName : ASTFileMacros.keys()) {
+ if (Diags) {
+ Diags->Report(diag::err_pch_macro_def_undef) << MacroName << false;
+ }
+ return true;
+ }
+ }
// Check whether we're using predefines.
- if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines && Validate) {
+ if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines &&
+ Validation != OptionValidateNone) {
if (Diags) {
Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines;
}
@@ -705,7 +735,8 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts,
// Detailed record is important since it is used for the module cache hash.
if (LangOpts.Modules &&
- PPOpts.DetailedRecord != ExistingPPOpts.DetailedRecord && Validate) {
+ PPOpts.DetailedRecord != ExistingPPOpts.DetailedRecord &&
+ Validation != OptionValidateNone) {
if (Diags) {
Diags->Report(diag::err_pch_pp_detailed_record) << PPOpts.DetailedRecord;
}
@@ -766,13 +797,9 @@ bool SimpleASTReaderListener::ReadPreprocessorOptions(
const PreprocessorOptions &PPOpts,
bool Complain,
std::string &SuggestedPredefines) {
- return checkPreprocessorOptions(PPOpts,
- PP.getPreprocessorOpts(),
- nullptr,
- PP.getFileManager(),
- SuggestedPredefines,
- PP.getLangOpts(),
- false);
+ return checkPreprocessorOptions(PPOpts, PP.getPreprocessorOpts(), nullptr,
+ PP.getFileManager(), SuggestedPredefines,
+ PP.getLangOpts(), OptionValidateNone);
}
/// Check the header search options deserialized from the control block
@@ -1197,7 +1224,7 @@ bool ASTReader::ReadLexicalDeclContextStorage(ModuleFile &M,
auto &Lex = LexicalDecls[DC];
if (!Lex.first) {
Lex = std::make_pair(
- &M, llvm::makeArrayRef(
+ &M, llvm::ArrayRef(
reinterpret_cast<const llvm::support::unaligned_uint32_t *>(
Blob.data()),
Blob.size() / 4));
@@ -1275,10 +1302,10 @@ void ASTReader::Error(llvm::Error &&Err) const {
switch (NumArgs) {
case 3:
Arg3 = Diag.getStringArg(2);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 2:
Arg2 = Diag.getStringArg(1);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case 1:
Arg1 = Diag.getStringArg(0);
}
@@ -1310,10 +1337,7 @@ void ASTReader::ParseLineTable(ModuleFile &F, const RecordData &Record) {
// Parse the line entries
std::vector<LineEntry> Entries;
while (Idx < Record.size()) {
- int FID = Record[Idx++];
- assert(FID >= 0 && "Serialized line entries for non-local file.");
- // Remap FileID from 1-based old view.
- FID += F.SLocEntryBaseID - 1;
+ FileID FID = ReadFileID(F, Record, Idx);
// Extract the line entries
unsigned NumEntries = Record[Idx++];
@@ -1330,7 +1354,7 @@ void ASTReader::ParseLineTable(ModuleFile &F, const RecordData &Record) {
Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID,
FileKind, IncludeOffset));
}
- LineTable.AddEntry(FileID::get(FID), Entries);
+ LineTable.AddEntry(FID, Entries);
}
}
@@ -1395,41 +1419,6 @@ llvm::Error ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
}
}
-/// If a header file is not found at the path that we expect it to be
-/// and the PCH file was moved from its original location, try to resolve the
-/// file by assuming that header+PCH were moved together and the header is in
-/// the same place relative to the PCH.
-static std::string
-resolveFileRelativeToOriginalDir(const std::string &Filename,
- const std::string &OriginalDir,
- const std::string &CurrDir) {
- assert(OriginalDir != CurrDir &&
- "No point trying to resolve the file if the PCH dir didn't change");
-
- using namespace llvm::sys;
-
- SmallString<128> filePath(Filename);
- fs::make_absolute(filePath);
- assert(path::is_absolute(OriginalDir));
- SmallString<128> currPCHPath(CurrDir);
-
- path::const_iterator fileDirI = path::begin(path::parent_path(filePath)),
- fileDirE = path::end(path::parent_path(filePath));
- path::const_iterator origDirI = path::begin(OriginalDir),
- origDirE = path::end(OriginalDir);
- // Skip the common path components from filePath and OriginalDir.
- while (fileDirI != fileDirE && origDirI != origDirE &&
- *fileDirI == *origDirI) {
- ++fileDirI;
- ++origDirI;
- }
- for (; origDirI != origDirE; ++origDirI)
- path::append(currPCHPath, "..");
- path::append(currPCHPath, fileDirI, fileDirE);
- path::append(currPCHPath, path::filename(Filename));
- return std::string(currPCHPath.str());
-}
-
bool ASTReader::ReadSLocEntry(int ID) {
if (ID == 0)
return false;
@@ -1462,19 +1451,25 @@ bool ASTReader::ReadSLocEntry(int ID) {
unsigned RecCode = MaybeRecCode.get();
if (RecCode == SM_SLOC_BUFFER_BLOB_COMPRESSED) {
- if (!llvm::compression::zlib::isAvailable()) {
- Error("zlib is not available");
+ // Inspect the first byte to differentiate zlib (\x78) and zstd
+ // (little-endian 0xFD2FB528).
+ const llvm::compression::Format F =
+ Blob.size() > 0 && Blob.data()[0] == 0x78
+ ? llvm::compression::Format::Zlib
+ : llvm::compression::Format::Zstd;
+ if (const char *Reason = llvm::compression::getReasonIfUnsupported(F)) {
+ Error(Reason);
return nullptr;
}
- SmallVector<uint8_t, 0> Uncompressed;
- if (llvm::Error E = llvm::compression::zlib::uncompress(
- llvm::arrayRefFromStringRef(Blob), Uncompressed, Record[0])) {
+ SmallVector<uint8_t, 0> Decompressed;
+ if (llvm::Error E = llvm::compression::decompress(
+ F, llvm::arrayRefFromStringRef(Blob), Decompressed, Record[0])) {
Error("could not decompress embedded file contents: " +
llvm::toString(std::move(E)));
return nullptr;
}
return llvm::MemoryBuffer::getMemBufferCopy(
- llvm::toStringRef(Uncompressed), Name);
+ llvm::toStringRef(Decompressed), Name);
} else if (RecCode == SM_SLOC_BUFFER_BLOB) {
return llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name, true);
} else {
@@ -1525,7 +1520,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
// we will also try to fail gracefully by setting up the SLocEntry.
unsigned InputID = Record[4];
InputFile IF = getInputFile(*F, InputID);
- Optional<FileEntryRef> File = IF.getFile();
+ OptionalFileEntryRef File = IF.getFile();
bool OverriddenBuffer = IF.isOverridden();
// Note that we only check if a File was returned. If it was out-of-date
@@ -1553,8 +1548,8 @@ bool ASTReader::ReadSLocEntry(int ID) {
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));
+ FileDeclIDs[FID] =
+ FileDeclsInfo(F, llvm::ArrayRef(FirstDecl, NumFileDecls));
}
const SrcMgr::ContentCache &ContentCache =
@@ -1673,11 +1668,38 @@ Token ASTReader::ReadToken(ModuleFile &F, const RecordDataImpl &Record,
Token Tok;
Tok.startToken();
Tok.setLocation(ReadSourceLocation(F, Record, Idx));
- Tok.setLength(Record[Idx++]);
- if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
- Tok.setIdentifierInfo(II);
Tok.setKind((tok::TokenKind)Record[Idx++]);
Tok.setFlag((Token::TokenFlags)Record[Idx++]);
+
+ if (Tok.isAnnotation()) {
+ Tok.setAnnotationEndLoc(ReadSourceLocation(F, Record, Idx));
+ switch (Tok.getKind()) {
+ case tok::annot_pragma_loop_hint: {
+ auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
+ Info->PragmaName = ReadToken(F, Record, Idx);
+ Info->Option = ReadToken(F, Record, Idx);
+ unsigned NumTokens = Record[Idx++];
+ SmallVector<Token, 4> Toks;
+ Toks.reserve(NumTokens);
+ for (unsigned I = 0; I < NumTokens; ++I)
+ Toks.push_back(ReadToken(F, Record, Idx));
+ Info->Toks = llvm::ArrayRef(Toks).copy(PP.getPreprocessorAllocator());
+ Tok.setAnnotationValue(static_cast<void *>(Info));
+ break;
+ }
+ // Some annotation tokens do not use the PtrData field.
+ case tok::annot_pragma_openmp:
+ case tok::annot_pragma_openmp_end:
+ case tok::annot_pragma_unused:
+ break;
+ default:
+ llvm_unreachable("missing deserialization code for annotation token");
+ }
+ } else {
+ Tok.setLength(Record[Idx++]);
+ if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++]))
+ Tok.setIdentifierInfo(II);
+ }
return Tok;
}
@@ -1909,8 +1931,8 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
"Wrong data length in HeaderFileInfo deserialization");
while (d != End) {
uint32_t LocalSMID = endian::readNext<uint32_t, little, unaligned>(d);
- auto HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>(LocalSMID & 3);
- LocalSMID >>= 2;
+ auto HeaderRole = static_cast<ModuleMap::ModuleHeaderRole>(LocalSMID & 7);
+ LocalSMID >>= 3;
// This header is part of a module. Associate it with the module to enable
// implicit module import.
@@ -1925,9 +1947,9 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
Reader.ResolveImportedPath(M, Filename);
// FIXME: NameAsWritten
Module::Header H = {std::string(key.Filename), "",
- *FileMgr.getFile(Filename)};
+ FileMgr.getOptionalFileRef(Filename)};
ModMap.addHeader(Mod, H, HeaderRole, /*Imported*/true);
- HFI.isModuleHeader |= !(HeaderRole & ModuleMap::TextualHeader);
+ HFI.isModuleHeader |= ModuleMap::isModular(HeaderRole);
}
// This HeaderFileInfo was externally loaded.
@@ -2243,8 +2265,15 @@ bool ASTReader::shouldDisableValidationForFile(
return false;
}
-ASTReader::InputFileInfo
-ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
+InputFileInfo ASTReader::getInputFileInfo(ModuleFile &F, unsigned ID) {
+ // If this ID is bogus, just return an empty input file.
+ if (ID == 0 || ID > F.InputFileInfosLoaded.size())
+ return InputFileInfo();
+
+ // If we've already loaded this input file, return it.
+ if (!F.InputFileInfosLoaded[ID - 1].Filename.empty())
+ return F.InputFileInfosLoaded[ID - 1];
+
// Go find this input file.
BitstreamCursor &Cursor = F.InputFilesCursor;
SavedStreamPosition SavedPosition(Cursor);
@@ -2297,6 +2326,9 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
}
R.ContentHash = (static_cast<uint64_t>(Record[1]) << 32) |
static_cast<uint64_t>(Record[0]);
+
+ // Note that we've loaded this input file info.
+ F.InputFileInfosLoaded[ID - 1] = R;
return R;
}
@@ -2321,7 +2353,7 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
consumeError(std::move(Err));
}
- InputFileInfo FI = readInputFileInfo(F, ID);
+ InputFileInfo FI = getInputFileInfo(F, ID);
off_t StoredSize = FI.StoredSize;
time_t StoredTime = FI.StoredTime;
bool Overridden = FI.Overridden;
@@ -2329,18 +2361,8 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
StringRef Filename = FI.Filename;
uint64_t StoredContentHash = FI.ContentHash;
- OptionalFileEntryRefDegradesToFileEntryPtr File =
- expectedToOptional(FileMgr.getFileRef(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 && !F.OriginalDir.empty() && !F.BaseDirectory.empty() &&
- F.OriginalDir != F.BaseDirectory) {
- std::string Resolved = resolveFileRelativeToOriginalDir(
- std::string(Filename), F.OriginalDir, F.BaseDirectory);
- if (!Resolved.empty())
- File = expectedToOptional(FileMgr.getFileRef(Resolved));
- }
+ OptionalFileEntryRefDegradesToFileEntryPtr File = OptionalFileEntryRef(
+ expectedToOptional(FileMgr.getFileRef(Filename, /*OpenFile=*/false)));
// For an overridden file, create a virtual file with the stored
// size/timestamp.
@@ -2387,8 +2409,8 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
Content,
None,
} Kind;
- llvm::Optional<int64_t> Old = llvm::None;
- llvm::Optional<int64_t> New = llvm::None;
+ std::optional<int64_t> Old = std::nullopt;
+ std::optional<int64_t> New = std::nullopt;
};
auto HasInputFileChanged = [&]() {
if (StoredSize != File->getSize())
@@ -2657,12 +2679,11 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// so we verify all input files. Otherwise, verify only user input
// files.
- unsigned N = NumUserInputs;
- if (ValidateSystemInputs ||
- (HSOpts.ModulesValidateOncePerBuildSession &&
- F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp &&
- F.Kind == MK_ImplicitModule))
- N = NumInputs;
+ unsigned N = ValidateSystemInputs ? NumInputs : NumUserInputs;
+ if (HSOpts.ModulesValidateOncePerBuildSession &&
+ F.InputFilesValidationTimestamp > HSOpts.BuildSessionTimestamp &&
+ F.Kind == MK_ImplicitModule)
+ N = NumUserInputs;
for (unsigned I = 0; I < N; ++I) {
InputFile IF = getInputFile(F, I+1, Complain);
@@ -2679,7 +2700,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
: NumUserInputs;
for (unsigned I = 0; I < N; ++I) {
bool IsSystem = I >= NumUserInputs;
- InputFileInfo FI = readInputFileInfo(F, I+1);
+ InputFileInfo FI = getInputFileInfo(F, I + 1);
Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden,
F.Kind == MK_ExplicitModule ||
F.Kind == MK_PrebuiltModule);
@@ -2896,11 +2917,6 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.OriginalSourceFileID = FileID::get(Record[0]);
break;
- case ORIGINAL_PCH_DIR:
- F.OriginalDir = std::string(Blob);
- ResolveImportedPath(F, F.OriginalDir);
- break;
-
case MODULE_NAME:
F.ModuleName = std::string(Blob);
Diag(diag::remark_module_import)
@@ -2961,6 +2977,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.InputFileOffsets =
(const llvm::support::unaligned_uint64_t *)Blob.data();
F.InputFilesLoaded.resize(NumInputs);
+ F.InputFileInfosLoaded.resize(NumInputs);
F.NumUserInputFiles = NumUserInputs;
break;
}
@@ -2976,7 +2993,7 @@ void ASTReader::readIncludedFiles(ModuleFile &F, StringRef Blob,
for (unsigned I = 0; I < FileCount; ++I) {
size_t ID = endian::readNext<uint32_t, little, unaligned>(D);
- InputFileInfo IFI = readInputFileInfo(F, ID);
+ InputFileInfo IFI = getInputFileInfo(F, ID);
if (llvm::ErrorOr<const FileEntry *> File =
PP.getFileManager().getFile(IFI.Filename))
PP.getIncludedFiles().insert(*File);
@@ -3386,7 +3403,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
if (!Record.empty()) {
unsigned Idx = 0, End = Record.size() - 1;
bool ReachedEOFWhileSkipping = Record[Idx++];
- llvm::Optional<Preprocessor::PreambleSkipInfo> SkipInfo;
+ std::optional<Preprocessor::PreambleSkipInfo> SkipInfo;
if (ReachedEOFWhileSkipping) {
SourceLocation HashToken = ReadSourceLocation(F, Record, Idx);
SourceLocation IfTokenLoc = ReadSourceLocation(F, Record, Idx);
@@ -3427,9 +3444,14 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
SLocSpaceSize);
- if (!F.SLocEntryBaseID)
+ if (!F.SLocEntryBaseID) {
+ if (!Diags.isDiagnosticInFlight()) {
+ Diags.Report(SourceLocation(), diag::remark_sloc_usage);
+ SourceMgr.noteSLocAddressSpaceUsage(Diags);
+ }
return llvm::createStringError(std::errc::invalid_argument,
"ran out of source locations");
+ }
// Make our entry in the range map. BaseID is negative and growing, so
// we invert it. Because we invert it, though, we need the other end of
// the range.
@@ -3942,13 +3964,14 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
Module *M =
PP.getHeaderSearchInfo().lookupModule(F.ModuleName, F.ImportLoc);
auto &Map = PP.getHeaderSearchInfo().getModuleMap();
- const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr;
+ OptionalFileEntryRef ModMap =
+ M ? Map.getModuleMapFileForUniquing(M) : std::nullopt;
// Don't emit module relocation error if we have -fno-validate-pch
if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation &
DisableValidationForModuleKind::Module) &&
!ModMap) {
if (!canRecoverFromOutOfDate(F.FileName, ClientLoadCapabilities)) {
- if (auto ASTFE = M ? M->getASTFile() : None) {
+ if (auto ASTFE = M ? M->getASTFile() : std::nullopt) {
// This module was defined by an imported (explicit) module.
Diag(diag::err_module_file_conflict) << F.ModuleName << F.FileName
<< ASTFE->getName();
@@ -4231,9 +4254,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
SourceLocation ImportLoc,
unsigned ClientLoadCapabilities,
SmallVectorImpl<ImportedSubmodule> *Imported) {
- llvm::SaveAndRestore<SourceLocation>
- SetCurImportLocRAII(CurrentImportLoc, ImportLoc);
- llvm::SaveAndRestore<Optional<ModuleKind>> SetCurModuleKindRAII(
+ llvm::TimeTraceScope scope("ReadAST", FileName);
+
+ llvm::SaveAndRestore SetCurImportLocRAII(CurrentImportLoc, ImportLoc);
+ llvm::SaveAndRestore<std::optional<ModuleKind>> SetCurModuleKindRAII(
CurrentDeserializingModuleKind, Type);
// Defer any pending actions until we get to the end of reading the AST file.
@@ -4250,10 +4274,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
ReadASTCore(FileName, Type, ImportLoc,
/*ImportedBy=*/nullptr, Loaded, 0, 0, ASTFileSignature(),
ClientLoadCapabilities)) {
- ModuleMgr.removeModules(ModuleMgr.begin() + NumModules,
- PP.getLangOpts().Modules
- ? &PP.getHeaderSearchInfo().getModuleMap()
- : nullptr);
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules);
// If we find that any modules are unusable, the global index is going
// to be out-of-date. Just remove it.
@@ -4273,6 +4294,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
// hit errors parsing the ASTs at this point.
for (ImportedModule &M : Loaded) {
ModuleFile &F = *M.Mod;
+ llvm::TimeTraceScope Scope2("Read Loaded AST", F.ModuleName);
// Read the AST block.
if (llvm::Error Err = ReadASTBlock(F, ClientLoadCapabilities)) {
@@ -4317,10 +4339,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
// Map the original source file ID into the ID space of the current
// compilation.
- if (F.OriginalSourceFileID.isValid()) {
- F.OriginalSourceFileID = FileID::get(
- F.SLocEntryBaseID + F.OriginalSourceFileID.getOpaqueValue() - 1);
- }
+ if (F.OriginalSourceFileID.isValid())
+ F.OriginalSourceFileID = TranslateFileID(F, F.OriginalSourceFileID);
// Preload all the pending interesting identifiers by marking them out of
// date.
@@ -4400,6 +4420,11 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName,
Unresolved.Mod->Imports.insert(ResolvedMod);
continue;
+ case UnresolvedModuleRef::Affecting:
+ if (ResolvedMod)
+ Unresolved.Mod->AffectingClangModules.insert(ResolvedMod);
+ continue;
+
case UnresolvedModuleRef::Export:
if (ResolvedMod || Unresolved.IsWildcard)
Unresolved.Mod->Exports.push_back(
@@ -4780,6 +4805,13 @@ ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl(
Result = OutOfDate; // Don't return early. Read the signature.
break;
}
+ case HEADER_SEARCH_PATHS: {
+ bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+ if (!AllowCompatibleConfigurationMismatch &&
+ ParseHeaderSearchPaths(Record, Complain, *Listener))
+ Result = ConfigurationMismatch;
+ break;
+ }
case DIAG_PRAGMA_MAPPINGS:
if (!F)
break;
@@ -5138,16 +5170,19 @@ namespace {
const PreprocessorOptions &ExistingPPOpts;
std::string ExistingModuleCachePath;
FileManager &FileMgr;
+ bool StrictOptionMatches;
public:
SimplePCHValidator(const LangOptions &ExistingLangOpts,
const TargetOptions &ExistingTargetOpts,
const PreprocessorOptions &ExistingPPOpts,
- StringRef ExistingModuleCachePath, FileManager &FileMgr)
+ StringRef ExistingModuleCachePath, FileManager &FileMgr,
+ bool StrictOptionMatches)
: ExistingLangOpts(ExistingLangOpts),
ExistingTargetOpts(ExistingTargetOpts),
ExistingPPOpts(ExistingPPOpts),
- ExistingModuleCachePath(ExistingModuleCachePath), FileMgr(FileMgr) {}
+ ExistingModuleCachePath(ExistingModuleCachePath), FileMgr(FileMgr),
+ StrictOptionMatches(StrictOptionMatches) {}
bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain,
bool AllowCompatibleDifferences) override {
@@ -5172,9 +5207,11 @@ namespace {
bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
bool Complain,
std::string &SuggestedPredefines) override {
- return checkPreprocessorOptions(PPOpts, ExistingPPOpts, /*Diags=*/nullptr,
- FileMgr, SuggestedPredefines,
- ExistingLangOpts);
+ return checkPreprocessorOptions(
+ PPOpts, ExistingPPOpts, /*Diags=*/nullptr, FileMgr,
+ SuggestedPredefines, ExistingLangOpts,
+ StrictOptionMatches ? OptionValidateStrictMatches
+ : OptionValidateContradictions);
}
};
@@ -5182,19 +5219,28 @@ namespace {
bool ASTReader::readASTFileControlBlock(
StringRef Filename, FileManager &FileMgr,
- const PCHContainerReader &PCHContainerRdr,
- bool FindModuleFileExtensions,
+ const InMemoryModuleCache &ModuleCache,
+ const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions,
ASTReaderListener &Listener, bool ValidateDiagnosticOptions) {
// Open the AST file.
- // FIXME: This allows use of the VFS; we do not allow use of the
- // VFS when actually loading a module.
- auto Buffer = FileMgr.getBufferForFile(Filename);
+ std::unique_ptr<llvm::MemoryBuffer> OwnedBuffer;
+ llvm::MemoryBuffer *Buffer = ModuleCache.lookupPCM(Filename);
if (!Buffer) {
- return true;
+ // FIXME: We should add the pcm to the InMemoryModuleCache if it could be
+ // read again later, but we do not have the context here to determine if it
+ // is safe to change the result of InMemoryModuleCache::getPCMState().
+
+ // FIXME: This allows use of the VFS; we do not allow use of the
+ // VFS when actually loading a module.
+ auto BufferOrErr = FileMgr.getBufferForFile(Filename);
+ if (!BufferOrErr)
+ return true;
+ OwnedBuffer = std::move(*BufferOrErr);
+ Buffer = OwnedBuffer.get();
}
// Initialize the stream
- StringRef Bytes = PCHContainerRdr.ExtractPCH(**Buffer);
+ StringRef Bytes = PCHContainerRdr.ExtractPCH(*Buffer);
BitstreamCursor Stream(Bytes);
// Sniff for the signature.
@@ -5447,16 +5493,19 @@ bool ASTReader::readASTFileControlBlock(
}
bool ASTReader::isAcceptableASTFile(StringRef Filename, FileManager &FileMgr,
+ const InMemoryModuleCache &ModuleCache,
const PCHContainerReader &PCHContainerRdr,
const LangOptions &LangOpts,
const TargetOptions &TargetOpts,
const PreprocessorOptions &PPOpts,
- StringRef ExistingModuleCachePath) {
+ StringRef ExistingModuleCachePath,
+ bool RequireStrictOptionMatches) {
SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts,
- ExistingModuleCachePath, FileMgr);
- return !readASTFileControlBlock(Filename, FileMgr, PCHContainerRdr,
- /*FindModuleFileExtensions=*/false,
- validator,
+ ExistingModuleCachePath, FileMgr,
+ RequireStrictOptionMatches);
+ return !readASTFileControlBlock(Filename, FileMgr, ModuleCache,
+ PCHContainerRdr,
+ /*FindModuleFileExtensions=*/false, validator,
/*ValidateDiagnosticOptions=*/true);
}
@@ -5612,7 +5661,7 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
// `Headers/`, so this path will never exist.
std::string Filename = std::string(Blob);
ResolveImportedPath(F, Filename);
- if (auto Umbrella = PP.getFileManager().getFile(Filename)) {
+ if (auto Umbrella = PP.getFileManager().getOptionalFileRef(Filename)) {
if (!CurrentModule->getUmbrellaHeader()) {
// FIXME: NameAsWritten
ModMap.setUmbrellaHeader(CurrentModule, *Umbrella, Blob, "");
@@ -5691,6 +5740,18 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
}
break;
+ case SUBMODULE_AFFECTING_MODULES:
+ for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
+ UnresolvedModuleRef Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[Idx];
+ Unresolved.Kind = UnresolvedModuleRef::Affecting;
+ Unresolved.IsWildcard = false;
+ UnresolvedModuleRefs.push_back(Unresolved);
+ }
+ break;
+
case SUBMODULE_EXPORTS:
for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
UnresolvedModuleRef Unresolved;
@@ -5853,6 +5914,28 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
unsigned Idx = 0;
HSOpts.Sysroot = ReadString(Record, Idx);
+ HSOpts.ResourceDir = ReadString(Record, Idx);
+ HSOpts.ModuleCachePath = ReadString(Record, Idx);
+ HSOpts.ModuleUserBuildPath = ReadString(Record, Idx);
+ HSOpts.DisableModuleHash = Record[Idx++];
+ HSOpts.ImplicitModuleMaps = Record[Idx++];
+ HSOpts.ModuleMapFileHomeIsCwd = Record[Idx++];
+ HSOpts.EnablePrebuiltImplicitModules = Record[Idx++];
+ HSOpts.UseBuiltinIncludes = Record[Idx++];
+ HSOpts.UseStandardSystemIncludes = Record[Idx++];
+ HSOpts.UseStandardCXXIncludes = Record[Idx++];
+ HSOpts.UseLibcxx = Record[Idx++];
+ std::string SpecificModuleCachePath = ReadString(Record, Idx);
+
+ return Listener.ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
+ Complain);
+}
+
+bool ASTReader::ParseHeaderSearchPaths(const RecordData &Record, bool Complain,
+ ASTReaderListener &Listener) {
+ HeaderSearchOptions HSOpts;
+ unsigned Idx = 0;
+
// Include entries.
for (unsigned N = Record[Idx++]; N; --N) {
std::string Path = ReadString(Record, Idx);
@@ -5871,21 +5954,13 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
HSOpts.SystemHeaderPrefixes.emplace_back(std::move(Prefix), IsSystemHeader);
}
- HSOpts.ResourceDir = ReadString(Record, Idx);
- HSOpts.ModuleCachePath = ReadString(Record, Idx);
- HSOpts.ModuleUserBuildPath = ReadString(Record, Idx);
- HSOpts.DisableModuleHash = Record[Idx++];
- HSOpts.ImplicitModuleMaps = Record[Idx++];
- HSOpts.ModuleMapFileHomeIsCwd = Record[Idx++];
- HSOpts.EnablePrebuiltImplicitModules = Record[Idx++];
- HSOpts.UseBuiltinIncludes = Record[Idx++];
- HSOpts.UseStandardSystemIncludes = Record[Idx++];
- HSOpts.UseStandardCXXIncludes = Record[Idx++];
- HSOpts.UseLibcxx = Record[Idx++];
- std::string SpecificModuleCachePath = ReadString(Record, Idx);
+ // VFS overlay files.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ std::string VFSOverlayFile = ReadString(Record, Idx);
+ HSOpts.VFSOverlayFiles.emplace_back(std::move(VFSOverlayFile));
+ }
- return Listener.ReadHeaderSearchOptions(HSOpts, SpecificModuleCachePath,
- Complain);
+ return Listener.ReadHeaderSearchPaths(HSOpts, Complain);
}
bool ASTReader::ParsePreprocessorOptions(const RecordData &Record,
@@ -6051,7 +6126,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
case PPD_INCLUSION_DIRECTIVE: {
const char *FullFileNameStart = Blob.data() + Record[0];
StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]);
- Optional<FileEntryRef> File;
+ OptionalFileEntryRef File;
if (!FullFileName.empty())
File = PP.getFileManager().getOptionalFileRef(FullFileName);
@@ -6190,8 +6265,8 @@ std::pair<unsigned, unsigned>
/// Optionally returns true or false if the preallocated preprocessed
/// entity with index \arg Index came from file \arg FID.
-Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
- FileID FID) {
+std::optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
+ FileID FID) {
if (FID.isInvalid())
return false;
@@ -6215,7 +6290,7 @@ namespace {
/// Visitor used to search for information about a header file.
class HeaderFileInfoVisitor {
const FileEntry *FE;
- Optional<HeaderFileInfo> HFI;
+ std::optional<HeaderFileInfo> HFI;
public:
explicit HeaderFileInfoVisitor(const FileEntry *FE) : FE(FE) {}
@@ -6235,7 +6310,7 @@ namespace {
return true;
}
- Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
+ std::optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
};
} // namespace
@@ -6243,8 +6318,8 @@ namespace {
HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
HeaderFileInfoVisitor Visitor(FE);
ModuleMgr.visit(Visitor);
- if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo())
- return *HFI;
+ if (std::optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo())
+ return *HFI;
return HeaderFileInfo();
}
@@ -6261,9 +6336,8 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
DiagStates.clear();
- auto ReadDiagState =
- [&](const DiagState &BasedOn, SourceLocation Loc,
- bool IncludeNonPragmaStates) -> DiagnosticsEngine::DiagState * {
+ auto ReadDiagState = [&](const DiagState &BasedOn,
+ bool IncludeNonPragmaStates) {
unsigned BackrefID = Record[Idx++];
if (BackrefID != 0)
return DiagStates[BackrefID - 1];
@@ -6324,7 +6398,7 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
Initial.EnableAllWarnings = Flags & 1; Flags >>= 1;
Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1;
Initial.ExtBehavior = (diag::Severity)Flags;
- FirstState = ReadDiagState(Initial, SourceLocation(), true);
+ FirstState = ReadDiagState(Initial, true);
assert(F.OriginalSourceFileID.isValid());
@@ -6337,8 +6411,7 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
// For prefix ASTs, start with whatever the user configured on the
// command line.
Idx++; // Skip flags.
- FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState,
- SourceLocation(), false);
+ FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState, false);
}
// Read the state transitions.
@@ -6360,8 +6433,7 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
F.StateTransitions.reserve(F.StateTransitions.size() + Transitions);
for (unsigned I = 0; I != Transitions; ++I) {
unsigned Offset = Record[Idx++];
- auto *State =
- ReadDiagState(*FirstState, Loc.getLocWithOffset(Offset), false);
+ auto *State = ReadDiagState(*FirstState, false);
F.StateTransitions.push_back({State, Offset});
}
}
@@ -6371,7 +6443,7 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
"Invalid data, missing final pragma diagnostic state");
SourceLocation CurStateLoc =
ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]);
- auto *CurState = ReadDiagState(*FirstState, CurStateLoc, false);
+ auto *CurState = ReadDiagState(*FirstState, false);
if (!F.isModule()) {
Diag.DiagStatesByLoc.CurDiagState = CurState;
@@ -6402,12 +6474,13 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
M->DeclsBlockStartOffset);
}
-static llvm::Optional<Type::TypeClass> getTypeClassForCode(TypeCode code) {
+static std::optional<Type::TypeClass> getTypeClassForCode(TypeCode code) {
switch (code) {
#define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \
case TYPE_##CODE_ID: return Type::CLASS_ID;
#include "clang/Serialization/TypeBitCodes.def"
- default: return llvm::None;
+ default:
+ return std::nullopt;
}
}
@@ -6664,7 +6737,7 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
TL.setTypeofLoc(readSourceLocation());
TL.setLParenLoc(readSourceLocation());
TL.setRParenLoc(readSourceLocation());
- TL.setUnderlyingTInfo(GetTypeSourceInfo());
+ TL.setUnmodifiedTInfo(GetTypeSourceInfo());
}
void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
@@ -6689,8 +6762,9 @@ void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
TL.setLAngleLoc(readSourceLocation());
TL.setRAngleLoc(readSourceLocation());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo(
- TL.getTypePtr()->getArg(i).getKind()));
+ TL.setArgLocInfo(
+ i, Reader.readTemplateArgumentLocInfo(
+ TL.getTypePtr()->getTypeConstraintArguments()[i].getKind()));
}
if (Reader.readBool())
TL.setRParenLoc(readSourceLocation());
@@ -6738,10 +6812,9 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc(
TL.setLAngleLoc(readSourceLocation());
TL.setRAngleLoc(readSourceLocation());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- TL.setArgLocInfo(
- i,
- Reader.readTemplateArgumentLocInfo(
- TL.getTypePtr()->getArg(i).getKind()));
+ TL.setArgLocInfo(i,
+ Reader.readTemplateArgumentLocInfo(
+ TL.getTypePtr()->template_arguments()[i].getKind()));
}
void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) {
@@ -6773,10 +6846,9 @@ void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc(
TL.setLAngleLoc(readSourceLocation());
TL.setRAngleLoc(readSourceLocation());
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
- TL.setArgLocInfo(
- I,
- Reader.readTemplateArgumentLocInfo(
- TL.getTypePtr()->getArg(I).getKind()));
+ TL.setArgLocInfo(I,
+ Reader.readTemplateArgumentLocInfo(
+ TL.getTypePtr()->template_arguments()[I].getKind()));
}
void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
@@ -6785,6 +6857,7 @@ void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
TL.setNameLoc(readSourceLocation());
+ TL.setNameEndLoc(readSourceLocation());
}
void TypeLocReader::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) {
@@ -7229,8 +7302,7 @@ void ASTReader::CompleteRedeclChain(const Decl *D) {
//
// FIXME: Merging a function definition should merge
// all mergeable entities within it.
- if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC) ||
- isa<CXXRecordDecl>(DC) || isa<EnumDecl>(DC)) {
+ if (isa<TranslationUnitDecl, NamespaceDecl, RecordDecl, EnumDecl>(DC)) {
if (DeclarationName Name = cast<NamedDecl>(D)->getDeclName()) {
if (!getContext().getLangOpts().CPlusPlus &&
isa<TranslationUnitDecl>(DC)) {
@@ -7964,8 +8036,8 @@ void ASTReader::UpdateSema() {
PragmaAlignPackStack.front().PushLocation);
DropFirst = true;
}
- for (const auto &Entry : llvm::makeArrayRef(PragmaAlignPackStack)
- .drop_front(DropFirst ? 1 : 0)) {
+ for (const auto &Entry :
+ llvm::ArrayRef(PragmaAlignPackStack).drop_front(DropFirst ? 1 : 0)) {
SemaObj->AlignPackStack.Stack.emplace_back(
Entry.SlotLabel, Entry.Value, Entry.Location, Entry.PushLocation);
}
@@ -7996,7 +8068,7 @@ void ASTReader::UpdateSema() {
DropFirst = true;
}
for (const auto &Entry :
- llvm::makeArrayRef(FpPragmaStack).drop_front(DropFirst ? 1 : 0))
+ llvm::ArrayRef(FpPragmaStack).drop_front(DropFirst ? 1 : 0))
SemaObj->FpPragmaStack.Stack.emplace_back(
Entry.SlotLabel, Entry.Value, Entry.Location, Entry.PushLocation);
if (FpPragmaCurrentLocation.isInvalid()) {
@@ -8032,7 +8104,7 @@ IdentifierInfo *ASTReader::get(StringRef Name) {
// lookups). Perform the lookup in PCH files, though, since we don't build
// a complete initial identifier table if we're carrying on from a PCH.
if (PP.getLangOpts().CPlusPlus) {
- for (auto F : ModuleMgr.pch_modules())
+ for (auto *F : ModuleMgr.pch_modules())
if (Visitor(*F))
break;
} else {
@@ -8239,8 +8311,8 @@ namespace serialization {
/// Add the given set of methods to the method list.
static void addMethodsToPool(Sema &S, ArrayRef<ObjCMethodDecl *> Methods,
ObjCMethodList &List) {
- for (auto I = Methods.rbegin(), E = Methods.rend(); I != E; ++I)
- S.addMethodToGlobalList(&List, *I);
+ for (ObjCMethodDecl *M : llvm::reverse(Methods))
+ S.addMethodToGlobalList(&List, M);
}
void ASTReader::ReadMethodPool(Selector Sel) {
@@ -8692,8 +8764,7 @@ unsigned ASTReader::getModuleFileID(ModuleFile *F) {
return (I - PCHModules.end()) << 1;
}
-llvm::Optional<ASTSourceDescriptor>
-ASTReader::getSourceDescriptor(unsigned ID) {
+std::optional<ASTSourceDescriptor> ASTReader::getSourceDescriptor(unsigned ID) {
if (Module *M = getSubmodule(ID))
return ASTSourceDescriptor(*M);
@@ -8704,10 +8775,11 @@ ASTReader::getSourceDescriptor(unsigned ID) {
ModuleFile &MF = ModuleMgr.getPrimaryModule();
StringRef ModuleName = llvm::sys::path::filename(MF.OriginalSourceFileName);
StringRef FileName = llvm::sys::path::filename(MF.FileName);
- return ASTSourceDescriptor(ModuleName, MF.OriginalDir, FileName,
- MF.Signature);
+ return ASTSourceDescriptor(ModuleName,
+ llvm::sys::path::parent_path(MF.FileName),
+ FileName, MF.Signature);
}
- return None;
+ return std::nullopt;
}
ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(const Decl *FD) {
@@ -9174,30 +9246,16 @@ void ASTReader::visitInputFiles(serialization::ModuleFile &MF,
void ASTReader::visitTopLevelModuleMaps(
serialization::ModuleFile &MF,
- llvm::function_ref<void(const FileEntry *FE)> Visitor) {
+ llvm::function_ref<void(FileEntryRef FE)> Visitor) {
unsigned NumInputs = MF.InputFilesLoaded.size();
for (unsigned I = 0; I < NumInputs; ++I) {
- InputFileInfo IFI = readInputFileInfo(MF, I + 1);
+ InputFileInfo IFI = getInputFileInfo(MF, I + 1);
if (IFI.TopLevelModuleMap)
- // FIXME: This unnecessarily re-reads the InputFileInfo.
if (auto FE = getInputFile(MF, I + 1).getFile())
- Visitor(FE);
+ Visitor(*FE);
}
}
-std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
- // If we know the owning module, use it.
- if (Module *M = D->getImportedOwningModule())
- return M->getFullModuleName();
-
- // Otherwise, use the name of the top-level module the decl is within.
- if (ModuleFile *M = getOwningModuleFile(D))
- return M->ModuleName;
-
- // Not from a module.
- return {};
-}
-
void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() || !PendingFunctionTypes.empty() ||
!PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
@@ -9445,35 +9503,13 @@ void ASTReader::finishPendingActions() {
PendingMergedDefinitionsToDeduplicate.clear();
}
-static unsigned computeODRHash(QualType Ty) {
- ODRHash Hasher;
- Hasher.AddQualType(Ty);
- return Hasher.CalculateHash();
-}
-
-static unsigned computeODRHash(const Stmt *S) {
- ODRHash Hasher;
- Hasher.AddStmt(S);
- return Hasher.CalculateHash();
-}
-
-static unsigned computeODRHash(const Decl *D) {
- assert(D);
- ODRHash Hasher;
- Hasher.AddSubDecl(D);
- return Hasher.CalculateHash();
-}
-
-static unsigned computeODRHash(const TemplateArgument &TA) {
- ODRHash Hasher;
- Hasher.AddTemplateArgument(TA);
- return Hasher.CalculateHash();
-}
-
void ASTReader::diagnoseOdrViolations() {
if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty() &&
+ PendingRecordOdrMergeFailures.empty() &&
PendingFunctionOdrMergeFailures.empty() &&
- PendingEnumOdrMergeFailures.empty())
+ PendingEnumOdrMergeFailures.empty() &&
+ PendingObjCInterfaceOdrMergeFailures.empty() &&
+ PendingObjCProtocolOdrMergeFailures.empty())
return;
// Trigger the import of the full definition of each class that had any
@@ -9495,6 +9531,25 @@ void ASTReader::diagnoseOdrViolations() {
}
}
+ // Trigger the import of the full definition of each record in C/ObjC.
+ auto RecordOdrMergeFailures = std::move(PendingRecordOdrMergeFailures);
+ PendingRecordOdrMergeFailures.clear();
+ for (auto &Merge : RecordOdrMergeFailures) {
+ Merge.first->decls_begin();
+ for (auto &D : Merge.second)
+ D->decls_begin();
+ }
+
+ // Trigger the import of the full interface definition.
+ auto ObjCInterfaceOdrMergeFailures =
+ std::move(PendingObjCInterfaceOdrMergeFailures);
+ PendingObjCInterfaceOdrMergeFailures.clear();
+ for (auto &Merge : ObjCInterfaceOdrMergeFailures) {
+ Merge.first->decls_begin();
+ for (auto &InterfacePair : Merge.second)
+ InterfacePair.first->decls_begin();
+ }
+
// Trigger the import of functions.
auto FunctionOdrMergeFailures = std::move(PendingFunctionOdrMergeFailures);
PendingFunctionOdrMergeFailures.clear();
@@ -9519,6 +9574,16 @@ void ASTReader::diagnoseOdrViolations() {
}
}
+ // Trigger the import of the full protocol definition.
+ auto ObjCProtocolOdrMergeFailures =
+ std::move(PendingObjCProtocolOdrMergeFailures);
+ PendingObjCProtocolOdrMergeFailures.clear();
+ for (auto &Merge : ObjCProtocolOdrMergeFailures) {
+ Merge.first->decls_begin();
+ for (auto &ProtocolPair : Merge.second)
+ ProtocolPair.first->decls_begin();
+ }
+
// For each declaration from a merged context, check that the canonical
// definition of that context also contains a declaration of the same
// entity.
@@ -9540,7 +9605,7 @@ void ASTReader::diagnoseOdrViolations() {
bool Found = false;
const Decl *DCanon = D->getCanonicalDecl();
- for (auto RI : D->redecls()) {
+ for (auto *RI : D->redecls()) {
if (RI->getLexicalDeclContext() == CanonDef) {
Found = true;
break;
@@ -9582,9 +9647,10 @@ void ASTReader::diagnoseOdrViolations() {
Deserializing RecursionGuard(this);
std::string CanonDefModule =
- getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef));
+ ODRDiagsEmitter::getOwningModuleNameForDiagnostic(
+ cast<Decl>(CanonDef));
Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
- << D << getOwningModuleNameForDiagnostic(D)
+ << D << ODRDiagsEmitter::getOwningModuleNameForDiagnostic(D)
<< CanonDef << CanonDefModule.empty() << CanonDefModule;
if (Candidates.empty())
@@ -9601,392 +9667,17 @@ void ASTReader::diagnoseOdrViolations() {
}
}
- if (OdrMergeFailures.empty() && FunctionOdrMergeFailures.empty() &&
- EnumOdrMergeFailures.empty())
+ if (OdrMergeFailures.empty() && RecordOdrMergeFailures.empty() &&
+ FunctionOdrMergeFailures.empty() && EnumOdrMergeFailures.empty() &&
+ ObjCInterfaceOdrMergeFailures.empty() &&
+ ObjCProtocolOdrMergeFailures.empty())
return;
// Ensure we don't accidentally recursively enter deserialization while
// we're producing our diagnostics.
Deserializing RecursionGuard(this);
-
- // Used with err_module_odr_violation_mismatch_decl and
- // note_module_odr_violation_mismatch_decl
- // This list should be the same Decl's as in ODRHash::isDeclToBeProcessed
- enum ODRMismatchDecl {
- EndOfClass,
- PublicSpecifer,
- PrivateSpecifer,
- ProtectedSpecifer,
- StaticAssert,
- Field,
- CXXMethod,
- TypeAlias,
- TypeDef,
- Var,
- Friend,
- FunctionTemplate,
- Other
- };
-
- // These lambdas have the common portions of the ODR diagnostics. This
- // has the same return as Diag(), so addition parameters can be passed
- // in with operator<<
- auto ODRDiagField = [this](NamedDecl *FirstRecord, StringRef FirstModule,
- StringRef SecondModule,
- const FieldDecl *FirstField,
- const FieldDecl *SecondField) {
- enum ODRFieldDifference {
- FieldName,
- FieldTypeName,
- FieldSingleBitField,
- FieldDifferentWidthBitField,
- FieldSingleMutable,
- FieldSingleInitializer,
- FieldDifferentInitializers,
- };
-
- auto DiagError = [FirstRecord, FirstField, FirstModule,
- this](ODRFieldDifference DiffType) {
- return Diag(FirstField->getLocation(),
- diag::err_module_odr_violation_field)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstField->getSourceRange() << DiffType;
- };
- auto DiagNote = [SecondField, SecondModule,
- this](ODRFieldDifference DiffType) {
- return Diag(SecondField->getLocation(),
- diag::note_module_odr_violation_field)
- << SecondModule << SecondField->getSourceRange() << DiffType;
- };
-
- IdentifierInfo *FirstII = FirstField->getIdentifier();
- IdentifierInfo *SecondII = SecondField->getIdentifier();
- if (FirstII->getName() != SecondII->getName()) {
- DiagError(FieldName) << FirstII;
- DiagNote(FieldName) << SecondII;
- return true;
- }
-
- assert(getContext().hasSameType(FirstField->getType(),
- SecondField->getType()));
-
- QualType FirstType = FirstField->getType();
- QualType SecondType = SecondField->getType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagError(FieldTypeName) << FirstII << FirstType;
- DiagNote(FieldTypeName) << SecondII << SecondType;
- return true;
- }
-
- const bool IsFirstBitField = FirstField->isBitField();
- const bool IsSecondBitField = SecondField->isBitField();
- if (IsFirstBitField != IsSecondBitField) {
- DiagError(FieldSingleBitField) << FirstII << IsFirstBitField;
- DiagNote(FieldSingleBitField) << SecondII << IsSecondBitField;
- return true;
- }
-
- if (IsFirstBitField && IsSecondBitField) {
- unsigned FirstBitWidthHash = computeODRHash(FirstField->getBitWidth());
- unsigned SecondBitWidthHash = computeODRHash(SecondField->getBitWidth());
- if (FirstBitWidthHash != SecondBitWidthHash) {
- DiagError(FieldDifferentWidthBitField)
- << FirstII << FirstField->getBitWidth()->getSourceRange();
- DiagNote(FieldDifferentWidthBitField)
- << SecondII << SecondField->getBitWidth()->getSourceRange();
- return true;
- }
- }
-
- if (!PP.getLangOpts().CPlusPlus)
- return false;
-
- const bool IsFirstMutable = FirstField->isMutable();
- const bool IsSecondMutable = SecondField->isMutable();
- if (IsFirstMutable != IsSecondMutable) {
- DiagError(FieldSingleMutable) << FirstII << IsFirstMutable;
- DiagNote(FieldSingleMutable) << SecondII << IsSecondMutable;
- return true;
- }
-
- const Expr *FirstInitializer = FirstField->getInClassInitializer();
- const Expr *SecondInitializer = SecondField->getInClassInitializer();
- if ((!FirstInitializer && SecondInitializer) ||
- (FirstInitializer && !SecondInitializer)) {
- DiagError(FieldSingleInitializer)
- << FirstII << (FirstInitializer != nullptr);
- DiagNote(FieldSingleInitializer)
- << SecondII << (SecondInitializer != nullptr);
- return true;
- }
-
- if (FirstInitializer && SecondInitializer) {
- unsigned FirstInitHash = computeODRHash(FirstInitializer);
- unsigned SecondInitHash = computeODRHash(SecondInitializer);
- if (FirstInitHash != SecondInitHash) {
- DiagError(FieldDifferentInitializers)
- << FirstII << FirstInitializer->getSourceRange();
- DiagNote(FieldDifferentInitializers)
- << SecondII << SecondInitializer->getSourceRange();
- return true;
- }
- }
-
- return false;
- };
-
- auto ODRDiagTypeDefOrAlias =
- [this](NamedDecl *FirstRecord, StringRef FirstModule,
- StringRef SecondModule, const TypedefNameDecl *FirstTD,
- const TypedefNameDecl *SecondTD, bool IsTypeAlias) {
- enum ODRTypedefDifference {
- TypedefName,
- TypedefType,
- };
-
- auto DiagError = [FirstRecord, FirstTD, FirstModule,
- this](ODRTypedefDifference DiffType) {
- return Diag(FirstTD->getLocation(),
- diag::err_module_odr_violation_typedef)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstTD->getSourceRange() << DiffType;
- };
- auto DiagNote = [SecondTD, SecondModule,
- this](ODRTypedefDifference DiffType) {
- return Diag(SecondTD->getLocation(),
- diag::note_module_odr_violation_typedef)
- << SecondModule << SecondTD->getSourceRange() << DiffType;
- };
-
- DeclarationName FirstName = FirstTD->getDeclName();
- DeclarationName SecondName = SecondTD->getDeclName();
- if (FirstName != SecondName) {
- DiagError(TypedefName) << IsTypeAlias << FirstName;
- DiagNote(TypedefName) << IsTypeAlias << SecondName;
- return true;
- }
-
- QualType FirstType = FirstTD->getUnderlyingType();
- QualType SecondType = SecondTD->getUnderlyingType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagError(TypedefType) << IsTypeAlias << FirstName << FirstType;
- DiagNote(TypedefType) << IsTypeAlias << SecondName << SecondType;
- return true;
- }
-
- return false;
- };
-
- auto ODRDiagVar = [this](NamedDecl *FirstRecord, StringRef FirstModule,
- StringRef SecondModule, const VarDecl *FirstVD,
- const VarDecl *SecondVD) {
- enum ODRVarDifference {
- VarName,
- VarType,
- VarSingleInitializer,
- VarDifferentInitializer,
- VarConstexpr,
- };
-
- auto DiagError = [FirstRecord, FirstVD, FirstModule,
- this](ODRVarDifference DiffType) {
- return Diag(FirstVD->getLocation(),
- diag::err_module_odr_violation_variable)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstVD->getSourceRange() << DiffType;
- };
- auto DiagNote = [SecondVD, SecondModule, this](ODRVarDifference DiffType) {
- return Diag(SecondVD->getLocation(),
- diag::note_module_odr_violation_variable)
- << SecondModule << SecondVD->getSourceRange() << DiffType;
- };
-
- DeclarationName FirstName = FirstVD->getDeclName();
- DeclarationName SecondName = SecondVD->getDeclName();
- if (FirstName != SecondName) {
- DiagError(VarName) << FirstName;
- DiagNote(VarName) << SecondName;
- return true;
- }
-
- QualType FirstType = FirstVD->getType();
- QualType SecondType = SecondVD->getType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagError(VarType) << FirstName << FirstType;
- DiagNote(VarType) << SecondName << SecondType;
- return true;
- }
-
- if (!PP.getLangOpts().CPlusPlus)
- return false;
-
- const Expr *FirstInit = FirstVD->getInit();
- const Expr *SecondInit = SecondVD->getInit();
- if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
- DiagError(VarSingleInitializer)
- << FirstName << (FirstInit == nullptr)
- << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
- DiagNote(VarSingleInitializer)
- << SecondName << (SecondInit == nullptr)
- << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
- return true;
- }
-
- if (FirstInit && SecondInit &&
- computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
- DiagError(VarDifferentInitializer)
- << FirstName << FirstInit->getSourceRange();
- DiagNote(VarDifferentInitializer)
- << SecondName << SecondInit->getSourceRange();
- return true;
- }
-
- const bool FirstIsConstexpr = FirstVD->isConstexpr();
- const bool SecondIsConstexpr = SecondVD->isConstexpr();
- if (FirstIsConstexpr != SecondIsConstexpr) {
- DiagError(VarConstexpr) << FirstName << FirstIsConstexpr;
- DiagNote(VarConstexpr) << SecondName << SecondIsConstexpr;
- return true;
- }
- return false;
- };
-
- using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>;
- auto PopulateHashes = [](DeclHashes &Hashes, RecordDecl *Record,
- const DeclContext *DC) {
- for (auto *D : Record->decls()) {
- if (!ODRHash::isDeclToBeProcessed(D, DC))
- continue;
- Hashes.emplace_back(D, computeODRHash(D));
- }
- };
-
- struct DiffResult {
- Decl *FirstDecl = nullptr, *SecondDecl = nullptr;
- ODRMismatchDecl FirstDiffType = Other, SecondDiffType = Other;
- };
-
- // If there is a diagnoseable difference, FirstDiffType and
- // SecondDiffType will not be Other and FirstDecl and SecondDecl will be
- // filled in if not EndOfClass.
- auto FindTypeDiffs = [](DeclHashes &FirstHashes, DeclHashes &SecondHashes) {
- auto DifferenceSelector = [](Decl *D) {
- assert(D && "valid Decl required");
- switch (D->getKind()) {
- default:
- return Other;
- case Decl::AccessSpec:
- switch (D->getAccess()) {
- case AS_public:
- return PublicSpecifer;
- case AS_private:
- return PrivateSpecifer;
- case AS_protected:
- return ProtectedSpecifer;
- case AS_none:
- break;
- }
- llvm_unreachable("Invalid access specifier");
- case Decl::StaticAssert:
- return StaticAssert;
- case Decl::Field:
- return Field;
- case Decl::CXXMethod:
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- return CXXMethod;
- case Decl::TypeAlias:
- return TypeAlias;
- case Decl::Typedef:
- return TypeDef;
- case Decl::Var:
- return Var;
- case Decl::Friend:
- return Friend;
- case Decl::FunctionTemplate:
- return FunctionTemplate;
- }
- };
-
- DiffResult DR;
- auto FirstIt = FirstHashes.begin();
- auto SecondIt = SecondHashes.begin();
- while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) {
- if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() &&
- FirstIt->second == SecondIt->second) {
- ++FirstIt;
- ++SecondIt;
- continue;
- }
-
- DR.FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first;
- DR.SecondDecl =
- SecondIt == SecondHashes.end() ? nullptr : SecondIt->first;
-
- DR.FirstDiffType =
- DR.FirstDecl ? DifferenceSelector(DR.FirstDecl) : EndOfClass;
- DR.SecondDiffType =
- DR.SecondDecl ? DifferenceSelector(DR.SecondDecl) : EndOfClass;
- return DR;
- }
- return DR;
- };
-
- // Use this to diagnose that an unexpected Decl was encountered
- // or no difference was detected. This causes a generic error
- // message to be emitted.
- auto DiagnoseODRUnexpected = [this](DiffResult &DR, NamedDecl *FirstRecord,
- StringRef FirstModule,
- NamedDecl *SecondRecord,
- StringRef SecondModule) {
- Diag(FirstRecord->getLocation(),
- diag::err_module_odr_violation_different_definitions)
- << FirstRecord << FirstModule.empty() << FirstModule;
-
- if (DR.FirstDecl) {
- Diag(DR.FirstDecl->getLocation(), diag::note_first_module_difference)
- << FirstRecord << DR.FirstDecl->getSourceRange();
- }
-
- Diag(SecondRecord->getLocation(),
- diag::note_module_odr_violation_different_definitions)
- << SecondModule;
-
- if (DR.SecondDecl) {
- Diag(DR.SecondDecl->getLocation(), diag::note_second_module_difference)
- << DR.SecondDecl->getSourceRange();
- }
- };
-
- auto DiagnoseODRMismatch = [this](DiffResult &DR, NamedDecl *FirstRecord,
- StringRef FirstModule,
- NamedDecl *SecondRecord,
- StringRef SecondModule) {
- auto GetMismatchedDeclLoc = [](const NamedDecl *Container,
- ODRMismatchDecl DiffType, const Decl *D) {
- SourceLocation Loc;
- SourceRange Range;
- auto *Tag = dyn_cast<TagDecl>(Container);
- if (DiffType == EndOfClass && Tag) {
- Loc = Tag->getBraceRange().getEnd();
- } else {
- Loc = D->getLocation();
- Range = D->getSourceRange();
- }
- return std::make_pair(Loc, Range);
- };
-
- auto FirstDiagInfo =
- GetMismatchedDeclLoc(FirstRecord, DR.FirstDiffType, DR.FirstDecl);
- Diag(FirstDiagInfo.first, diag::err_module_odr_violation_mismatch_decl)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstDiagInfo.second << DR.FirstDiffType;
-
- auto SecondDiagInfo =
- GetMismatchedDeclLoc(SecondRecord, DR.SecondDiffType, DR.SecondDecl);
- Diag(SecondDiagInfo.first, diag::note_module_odr_violation_mismatch_decl)
- << SecondModule << SecondDiagInfo.second << DR.SecondDiffType;
- };
+ ODRDiagsEmitter DiagsEmitter(Diags, getContext(),
+ getPreprocessor().getLangOpts());
// Issue any pending ODR-failure diagnostics.
for (auto &Merge : OdrMergeFailures) {
@@ -9997,986 +9688,12 @@ void ASTReader::diagnoseOdrViolations() {
bool Diagnosed = false;
CXXRecordDecl *FirstRecord = Merge.first;
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
for (auto &RecordPair : Merge.second) {
- CXXRecordDecl *SecondRecord = RecordPair.first;
- // Multiple different declarations got merged together; tell the user
- // where they came from.
- if (FirstRecord == SecondRecord)
- continue;
-
- std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
-
- auto *FirstDD = FirstRecord->DefinitionData;
- auto *SecondDD = RecordPair.second;
-
- assert(FirstDD && SecondDD && "Definitions without DefinitionData");
-
- // Diagnostics from DefinitionData are emitted here.
- if (FirstDD != SecondDD) {
- enum ODRDefinitionDataDifference {
- NumBases,
- NumVBases,
- BaseType,
- BaseVirtual,
- BaseAccess,
- };
- auto ODRDiagBaseError = [FirstRecord, &FirstModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRDefinitionDataDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_definition_data)
- << FirstRecord << FirstModule.empty() << FirstModule << Range
- << DiffType;
- };
- auto ODRDiagBaseNote = [&SecondModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRDefinitionDataDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_definition_data)
- << SecondModule << Range << DiffType;
- };
- auto GetSourceRange = [](struct CXXRecordDecl::DefinitionData *DD) {
- unsigned NumBases = DD->NumBases;
- if (NumBases == 0) return SourceRange();
- ArrayRef<CXXBaseSpecifier> bases = DD->bases();
- return SourceRange(bases[0].getBeginLoc(),
- bases[NumBases - 1].getEndLoc());
- };
-
- unsigned FirstNumBases = FirstDD->NumBases;
- unsigned FirstNumVBases = FirstDD->NumVBases;
- unsigned SecondNumBases = SecondDD->NumBases;
- unsigned SecondNumVBases = SecondDD->NumVBases;
- if (FirstNumBases != SecondNumBases) {
- ODRDiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
- NumBases)
- << FirstNumBases;
- ODRDiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
- NumBases)
- << SecondNumBases;
- Diagnosed = true;
- break;
- }
-
- if (FirstNumVBases != SecondNumVBases) {
- ODRDiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
- NumVBases)
- << FirstNumVBases;
- ODRDiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
- NumVBases)
- << SecondNumVBases;
- Diagnosed = true;
- break;
- }
-
- ArrayRef<CXXBaseSpecifier> FirstBases = FirstDD->bases();
- ArrayRef<CXXBaseSpecifier> SecondBases = SecondDD->bases();
- unsigned I = 0;
- for (I = 0; I < FirstNumBases; ++I) {
- const CXXBaseSpecifier FirstBase = FirstBases[I];
- const CXXBaseSpecifier SecondBase = SecondBases[I];
- if (computeODRHash(FirstBase.getType()) !=
- computeODRHash(SecondBase.getType())) {
- ODRDiagBaseError(FirstRecord->getLocation(),
- FirstBase.getSourceRange(), BaseType)
- << (I + 1) << FirstBase.getType();
- ODRDiagBaseNote(SecondRecord->getLocation(),
- SecondBase.getSourceRange(), BaseType)
- << (I + 1) << SecondBase.getType();
- break;
- }
-
- if (FirstBase.isVirtual() != SecondBase.isVirtual()) {
- ODRDiagBaseError(FirstRecord->getLocation(),
- FirstBase.getSourceRange(), BaseVirtual)
- << (I + 1) << FirstBase.isVirtual() << FirstBase.getType();
- ODRDiagBaseNote(SecondRecord->getLocation(),
- SecondBase.getSourceRange(), BaseVirtual)
- << (I + 1) << SecondBase.isVirtual() << SecondBase.getType();
- break;
- }
-
- if (FirstBase.getAccessSpecifierAsWritten() !=
- SecondBase.getAccessSpecifierAsWritten()) {
- ODRDiagBaseError(FirstRecord->getLocation(),
- FirstBase.getSourceRange(), BaseAccess)
- << (I + 1) << FirstBase.getType()
- << (int)FirstBase.getAccessSpecifierAsWritten();
- ODRDiagBaseNote(SecondRecord->getLocation(),
- SecondBase.getSourceRange(), BaseAccess)
- << (I + 1) << SecondBase.getType()
- << (int)SecondBase.getAccessSpecifierAsWritten();
- break;
- }
- }
-
- if (I != FirstNumBases) {
- Diagnosed = true;
- break;
- }
- }
-
- const ClassTemplateDecl *FirstTemplate =
- FirstRecord->getDescribedClassTemplate();
- const ClassTemplateDecl *SecondTemplate =
- SecondRecord->getDescribedClassTemplate();
-
- assert(!FirstTemplate == !SecondTemplate &&
- "Both pointers should be null or non-null");
-
- if (FirstTemplate && SecondTemplate) {
- DeclHashes FirstTemplateHashes;
- DeclHashes SecondTemplateHashes;
-
- auto PopulateTemplateParameterHashs = [](DeclHashes &Hashes,
- const ClassTemplateDecl *TD) {
- for (auto *D : TD->getTemplateParameters()->asArray()) {
- Hashes.emplace_back(D, computeODRHash(D));
- }
- };
-
- PopulateTemplateParameterHashs(FirstTemplateHashes, FirstTemplate);
- PopulateTemplateParameterHashs(SecondTemplateHashes, SecondTemplate);
-
- assert(FirstTemplateHashes.size() == SecondTemplateHashes.size() &&
- "Number of template parameters should be equal.");
-
- auto FirstIt = FirstTemplateHashes.begin();
- auto FirstEnd = FirstTemplateHashes.end();
- auto SecondIt = SecondTemplateHashes.begin();
- for (; FirstIt != FirstEnd; ++FirstIt, ++SecondIt) {
- if (FirstIt->second == SecondIt->second)
- continue;
-
- const NamedDecl* FirstDecl = cast<NamedDecl>(FirstIt->first);
- const NamedDecl* SecondDecl = cast<NamedDecl>(SecondIt->first);
-
- assert(FirstDecl->getKind() == SecondDecl->getKind() &&
- "Parameter Decl's should be the same kind.");
-
- enum ODRTemplateDifference {
- ParamEmptyName,
- ParamName,
- ParamSingleDefaultArgument,
- ParamDifferentDefaultArgument,
- };
-
- auto hasDefaultArg = [](const NamedDecl *D) {
- if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
- return TTP->hasDefaultArgument() &&
- !TTP->defaultArgumentWasInherited();
- if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
- return NTTP->hasDefaultArgument() &&
- !NTTP->defaultArgumentWasInherited();
- auto *TTP = cast<TemplateTemplateParmDecl>(D);
- return TTP->hasDefaultArgument() &&
- !TTP->defaultArgumentWasInherited();
- };
- bool hasFirstArg = hasDefaultArg(FirstDecl);
- bool hasSecondArg = hasDefaultArg(SecondDecl);
-
- ODRTemplateDifference ErrDiffType;
- ODRTemplateDifference NoteDiffType;
-
- DeclarationName FirstName = FirstDecl->getDeclName();
- DeclarationName SecondName = SecondDecl->getDeclName();
-
- if (FirstName != SecondName) {
- bool FirstNameEmpty =
- FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo();
- bool SecondNameEmpty = SecondName.isIdentifier() &&
- !SecondName.getAsIdentifierInfo();
- ErrDiffType = FirstNameEmpty ? ParamEmptyName : ParamName;
- NoteDiffType = SecondNameEmpty ? ParamEmptyName : ParamName;
- } else if (hasFirstArg == hasSecondArg)
- ErrDiffType = NoteDiffType = ParamDifferentDefaultArgument;
- else
- ErrDiffType = NoteDiffType = ParamSingleDefaultArgument;
-
- Diag(FirstDecl->getLocation(),
- diag::err_module_odr_violation_template_parameter)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstDecl->getSourceRange() << ErrDiffType << hasFirstArg
- << FirstName;
- Diag(SecondDecl->getLocation(),
- diag::note_module_odr_violation_template_parameter)
- << SecondModule << SecondDecl->getSourceRange() << NoteDiffType
- << hasSecondArg << SecondName;
- break;
- }
-
- if (FirstIt != FirstEnd) {
- Diagnosed = true;
- break;
- }
- }
-
- DeclHashes FirstHashes;
- DeclHashes SecondHashes;
- const DeclContext *DC = FirstRecord;
- PopulateHashes(FirstHashes, FirstRecord, DC);
- PopulateHashes(SecondHashes, SecondRecord, DC);
-
- DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
- ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
- ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
- const Decl *FirstDecl = DR.FirstDecl;
- const Decl *SecondDecl = DR.SecondDecl;
-
- if (FirstDiffType == Other || SecondDiffType == Other) {
- DiagnoseODRUnexpected(DR, FirstRecord, FirstModule, SecondRecord,
- SecondModule);
- Diagnosed = true;
- break;
- }
-
- if (FirstDiffType != SecondDiffType) {
- DiagnoseODRMismatch(DR, FirstRecord, FirstModule, SecondRecord,
- SecondModule);
- Diagnosed = true;
- break;
- }
-
- // Used with err_module_odr_violation_record and
- // note_module_odr_violation_record
- enum ODRCXXRecordDifference {
- StaticAssertCondition,
- StaticAssertMessage,
- StaticAssertOnlyMessage,
- MethodName,
- MethodDeleted,
- MethodDefaulted,
- MethodVirtual,
- MethodStatic,
- MethodVolatile,
- MethodConst,
- MethodInline,
- MethodNumberParameters,
- MethodParameterType,
- MethodParameterName,
- MethodParameterSingleDefaultArgument,
- MethodParameterDifferentDefaultArgument,
- MethodNoTemplateArguments,
- MethodDifferentNumberTemplateArguments,
- MethodDifferentTemplateArgument,
- MethodSingleBody,
- MethodDifferentBody,
- FriendTypeFunction,
- FriendType,
- FriendFunction,
- FunctionTemplateDifferentNumberParameters,
- FunctionTemplateParameterDifferentKind,
- FunctionTemplateParameterName,
- FunctionTemplateParameterSingleDefaultArgument,
- FunctionTemplateParameterDifferentDefaultArgument,
- FunctionTemplateParameterDifferentType,
- FunctionTemplatePackParameter,
- };
- auto ODRDiagDeclError = [FirstRecord, &FirstModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRCXXRecordDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_record)
- << FirstRecord << FirstModule.empty() << FirstModule << Range
- << DiffType;
- };
- auto ODRDiagDeclNote = [&SecondModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRCXXRecordDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_record)
- << SecondModule << Range << DiffType;
- };
-
- assert(FirstDiffType == SecondDiffType);
- switch (FirstDiffType) {
- case Other:
- case EndOfClass:
- case PublicSpecifer:
- case PrivateSpecifer:
- case ProtectedSpecifer:
- llvm_unreachable("Invalid diff type");
-
- case StaticAssert: {
- const StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl);
- const StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl);
-
- const Expr *FirstExpr = FirstSA->getAssertExpr();
- const Expr *SecondExpr = SecondSA->getAssertExpr();
- unsigned FirstODRHash = computeODRHash(FirstExpr);
- unsigned SecondODRHash = computeODRHash(SecondExpr);
- if (FirstODRHash != SecondODRHash) {
- ODRDiagDeclError(FirstExpr->getBeginLoc(),
- FirstExpr->getSourceRange(), StaticAssertCondition);
- ODRDiagDeclNote(SecondExpr->getBeginLoc(),
- SecondExpr->getSourceRange(), StaticAssertCondition);
- Diagnosed = true;
- break;
- }
-
- const StringLiteral *FirstStr = FirstSA->getMessage();
- const StringLiteral *SecondStr = SecondSA->getMessage();
- assert((FirstStr || SecondStr) && "Both messages cannot be empty");
- if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) {
- SourceLocation FirstLoc, SecondLoc;
- SourceRange FirstRange, SecondRange;
- if (FirstStr) {
- FirstLoc = FirstStr->getBeginLoc();
- FirstRange = FirstStr->getSourceRange();
- } else {
- FirstLoc = FirstSA->getBeginLoc();
- FirstRange = FirstSA->getSourceRange();
- }
- if (SecondStr) {
- SecondLoc = SecondStr->getBeginLoc();
- SecondRange = SecondStr->getSourceRange();
- } else {
- SecondLoc = SecondSA->getBeginLoc();
- SecondRange = SecondSA->getSourceRange();
- }
- ODRDiagDeclError(FirstLoc, FirstRange, StaticAssertOnlyMessage)
- << (FirstStr == nullptr);
- ODRDiagDeclNote(SecondLoc, SecondRange, StaticAssertOnlyMessage)
- << (SecondStr == nullptr);
- Diagnosed = true;
- break;
- }
-
- if (FirstStr && SecondStr &&
- FirstStr->getString() != SecondStr->getString()) {
- ODRDiagDeclError(FirstStr->getBeginLoc(), FirstStr->getSourceRange(),
- StaticAssertMessage);
- ODRDiagDeclNote(SecondStr->getBeginLoc(), SecondStr->getSourceRange(),
- StaticAssertMessage);
- Diagnosed = true;
- break;
- }
- break;
- }
- case Field: {
- Diagnosed = ODRDiagField(FirstRecord, FirstModule, SecondModule,
- cast<FieldDecl>(FirstDecl),
- cast<FieldDecl>(SecondDecl));
- break;
- }
- case CXXMethod: {
- enum {
- DiagMethod,
- DiagConstructor,
- DiagDestructor,
- } FirstMethodType,
- SecondMethodType;
- auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl* D) {
- if (isa<CXXConstructorDecl>(D)) return DiagConstructor;
- if (isa<CXXDestructorDecl>(D)) return DiagDestructor;
- return DiagMethod;
- };
- const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl);
- const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl);
- FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod);
- SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod);
- DeclarationName FirstName = FirstMethod->getDeclName();
- DeclarationName SecondName = SecondMethod->getDeclName();
- auto DiagMethodError = [&ODRDiagDeclError, FirstMethod, FirstMethodType,
- FirstName](ODRCXXRecordDifference DiffType) {
- return ODRDiagDeclError(FirstMethod->getLocation(),
- FirstMethod->getSourceRange(), DiffType)
- << FirstMethodType << FirstName;
- };
- auto DiagMethodNote = [&ODRDiagDeclNote, SecondMethod, SecondMethodType,
- SecondName](ODRCXXRecordDifference DiffType) {
- return ODRDiagDeclNote(SecondMethod->getLocation(),
- SecondMethod->getSourceRange(), DiffType)
- << SecondMethodType << SecondName;
- };
-
- if (FirstMethodType != SecondMethodType || FirstName != SecondName) {
- DiagMethodError(MethodName);
- DiagMethodNote(MethodName);
- Diagnosed = true;
- break;
- }
-
- const bool FirstDeleted = FirstMethod->isDeletedAsWritten();
- const bool SecondDeleted = SecondMethod->isDeletedAsWritten();
- if (FirstDeleted != SecondDeleted) {
- DiagMethodError(MethodDeleted) << FirstDeleted;
- DiagMethodNote(MethodDeleted) << SecondDeleted;
- Diagnosed = true;
- break;
- }
-
- const bool FirstDefaulted = FirstMethod->isExplicitlyDefaulted();
- const bool SecondDefaulted = SecondMethod->isExplicitlyDefaulted();
- if (FirstDefaulted != SecondDefaulted) {
- DiagMethodError(MethodDefaulted) << FirstDefaulted;
- DiagMethodNote(MethodDefaulted) << SecondDefaulted;
- Diagnosed = true;
- break;
- }
-
- const bool FirstVirtual = FirstMethod->isVirtualAsWritten();
- const bool SecondVirtual = SecondMethod->isVirtualAsWritten();
- const bool FirstPure = FirstMethod->isPure();
- const bool SecondPure = SecondMethod->isPure();
- if ((FirstVirtual || SecondVirtual) &&
- (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) {
- DiagMethodError(MethodVirtual) << FirstPure << FirstVirtual;
- DiagMethodNote(MethodVirtual) << SecondPure << SecondVirtual;
- Diagnosed = true;
- break;
- }
-
- // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging,
- // FirstDecl is the canonical Decl of SecondDecl, so the storage
- // class needs to be checked instead.
- StorageClass FirstStorage = FirstMethod->getStorageClass();
- StorageClass SecondStorage = SecondMethod->getStorageClass();
- const bool FirstStatic = FirstStorage == SC_Static;
- const bool SecondStatic = SecondStorage == SC_Static;
- if (FirstStatic != SecondStatic) {
- DiagMethodError(MethodStatic) << FirstStatic;
- DiagMethodNote(MethodStatic) << SecondStatic;
- Diagnosed = true;
- break;
- }
-
- const bool FirstVolatile = FirstMethod->isVolatile();
- const bool SecondVolatile = SecondMethod->isVolatile();
- if (FirstVolatile != SecondVolatile) {
- DiagMethodError(MethodVolatile) << FirstVolatile;
- DiagMethodNote(MethodVolatile) << SecondVolatile;
- Diagnosed = true;
- break;
- }
-
- const bool FirstConst = FirstMethod->isConst();
- const bool SecondConst = SecondMethod->isConst();
- if (FirstConst != SecondConst) {
- DiagMethodError(MethodConst) << FirstConst;
- DiagMethodNote(MethodConst) << SecondConst;
- Diagnosed = true;
- break;
- }
-
- const bool FirstInline = FirstMethod->isInlineSpecified();
- const bool SecondInline = SecondMethod->isInlineSpecified();
- if (FirstInline != SecondInline) {
- DiagMethodError(MethodInline) << FirstInline;
- DiagMethodNote(MethodInline) << SecondInline;
- Diagnosed = true;
- break;
- }
-
- const unsigned FirstNumParameters = FirstMethod->param_size();
- const unsigned SecondNumParameters = SecondMethod->param_size();
- if (FirstNumParameters != SecondNumParameters) {
- DiagMethodError(MethodNumberParameters) << FirstNumParameters;
- DiagMethodNote(MethodNumberParameters) << SecondNumParameters;
- Diagnosed = true;
- break;
- }
-
- // Need this status boolean to know when break out of the switch.
- bool ParameterMismatch = false;
- for (unsigned I = 0; I < FirstNumParameters; ++I) {
- const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
- const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
-
- QualType FirstParamType = FirstParam->getType();
- QualType SecondParamType = SecondParam->getType();
- if (FirstParamType != SecondParamType &&
- computeODRHash(FirstParamType) !=
- computeODRHash(SecondParamType)) {
- if (const DecayedType *ParamDecayedType =
- FirstParamType->getAs<DecayedType>()) {
- DiagMethodError(MethodParameterType)
- << (I + 1) << FirstParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagMethodError(MethodParameterType)
- << (I + 1) << FirstParamType << false;
- }
-
- if (const DecayedType *ParamDecayedType =
- SecondParamType->getAs<DecayedType>()) {
- DiagMethodNote(MethodParameterType)
- << (I + 1) << SecondParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagMethodNote(MethodParameterType)
- << (I + 1) << SecondParamType << false;
- }
- ParameterMismatch = true;
- break;
- }
-
- DeclarationName FirstParamName = FirstParam->getDeclName();
- DeclarationName SecondParamName = SecondParam->getDeclName();
- if (FirstParamName != SecondParamName) {
- DiagMethodError(MethodParameterName) << (I + 1) << FirstParamName;
- DiagMethodNote(MethodParameterName) << (I + 1) << SecondParamName;
- ParameterMismatch = true;
- break;
- }
-
- const Expr *FirstInit = FirstParam->getInit();
- const Expr *SecondInit = SecondParam->getInit();
- if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
- DiagMethodError(MethodParameterSingleDefaultArgument)
- << (I + 1) << (FirstInit == nullptr)
- << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
- DiagMethodNote(MethodParameterSingleDefaultArgument)
- << (I + 1) << (SecondInit == nullptr)
- << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
- ParameterMismatch = true;
- break;
- }
-
- if (FirstInit && SecondInit &&
- computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
- DiagMethodError(MethodParameterDifferentDefaultArgument)
- << (I + 1) << FirstInit->getSourceRange();
- DiagMethodNote(MethodParameterDifferentDefaultArgument)
- << (I + 1) << SecondInit->getSourceRange();
- ParameterMismatch = true;
- break;
- }
- }
-
- if (ParameterMismatch) {
- Diagnosed = true;
- break;
- }
-
- const TemplateArgumentList *FirstTemplateArgs =
- FirstMethod->getTemplateSpecializationArgs();
- const TemplateArgumentList *SecondTemplateArgs =
- SecondMethod->getTemplateSpecializationArgs();
-
- if ((FirstTemplateArgs && !SecondTemplateArgs) ||
- (!FirstTemplateArgs && SecondTemplateArgs)) {
- DiagMethodError(MethodNoTemplateArguments)
- << (FirstTemplateArgs != nullptr);
- DiagMethodNote(MethodNoTemplateArguments)
- << (SecondTemplateArgs != nullptr);
- Diagnosed = true;
- break;
- }
-
- if (FirstTemplateArgs && SecondTemplateArgs) {
- // Remove pack expansions from argument list.
- auto ExpandTemplateArgumentList =
- [](const TemplateArgumentList *TAL) {
- llvm::SmallVector<const TemplateArgument *, 8> ExpandedList;
- for (const TemplateArgument &TA : TAL->asArray()) {
- if (TA.getKind() != TemplateArgument::Pack) {
- ExpandedList.push_back(&TA);
- continue;
- }
- llvm::append_range(ExpandedList, llvm::make_pointer_range(
- TA.getPackAsArray()));
- }
- return ExpandedList;
- };
- llvm::SmallVector<const TemplateArgument *, 8> FirstExpandedList =
- ExpandTemplateArgumentList(FirstTemplateArgs);
- llvm::SmallVector<const TemplateArgument *, 8> SecondExpandedList =
- ExpandTemplateArgumentList(SecondTemplateArgs);
-
- if (FirstExpandedList.size() != SecondExpandedList.size()) {
- DiagMethodError(MethodDifferentNumberTemplateArguments)
- << (unsigned)FirstExpandedList.size();
- DiagMethodNote(MethodDifferentNumberTemplateArguments)
- << (unsigned)SecondExpandedList.size();
- Diagnosed = true;
- break;
- }
-
- bool TemplateArgumentMismatch = false;
- for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) {
- const TemplateArgument &FirstTA = *FirstExpandedList[i],
- &SecondTA = *SecondExpandedList[i];
- if (computeODRHash(FirstTA) == computeODRHash(SecondTA)) {
- continue;
- }
-
- DiagMethodError(MethodDifferentTemplateArgument)
- << FirstTA << i + 1;
- DiagMethodNote(MethodDifferentTemplateArgument)
- << SecondTA << i + 1;
- TemplateArgumentMismatch = true;
- break;
- }
-
- if (TemplateArgumentMismatch) {
- Diagnosed = true;
- break;
- }
- }
-
- // Compute the hash of the method as if it has no body.
- auto ComputeCXXMethodODRHash = [](const CXXMethodDecl *D) {
- ODRHash Hasher;
- Hasher.AddFunctionDecl(D, true /*SkipBody*/);
- return Hasher.CalculateHash();
- };
-
- // Compare the hash generated to the hash stored. A difference means
- // that a body was present in the original source. Due to merging,
- // the standard way of detecting a body will not work.
- const bool HasFirstBody =
- ComputeCXXMethodODRHash(FirstMethod) != FirstMethod->getODRHash();
- const bool HasSecondBody =
- ComputeCXXMethodODRHash(SecondMethod) != SecondMethod->getODRHash();
-
- if (HasFirstBody != HasSecondBody) {
- DiagMethodError(MethodSingleBody) << HasFirstBody;
- DiagMethodNote(MethodSingleBody) << HasSecondBody;
- Diagnosed = true;
- break;
- }
-
- if (HasFirstBody && HasSecondBody) {
- DiagMethodError(MethodDifferentBody);
- DiagMethodNote(MethodDifferentBody);
- Diagnosed = true;
- break;
- }
-
- break;
- }
- case TypeAlias:
- case TypeDef: {
- Diagnosed = ODRDiagTypeDefOrAlias(
- FirstRecord, FirstModule, SecondModule,
- cast<TypedefNameDecl>(FirstDecl), cast<TypedefNameDecl>(SecondDecl),
- FirstDiffType == TypeAlias);
- break;
- }
- case Var: {
- Diagnosed =
- ODRDiagVar(FirstRecord, FirstModule, SecondModule,
- cast<VarDecl>(FirstDecl), cast<VarDecl>(SecondDecl));
- break;
- }
- case Friend: {
- const FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl);
- const FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl);
-
- const NamedDecl *FirstND = FirstFriend->getFriendDecl();
- const NamedDecl *SecondND = SecondFriend->getFriendDecl();
-
- TypeSourceInfo *FirstTSI = FirstFriend->getFriendType();
- TypeSourceInfo *SecondTSI = SecondFriend->getFriendType();
-
- if (FirstND && SecondND) {
- ODRDiagDeclError(FirstFriend->getFriendLoc(),
- FirstFriend->getSourceRange(), FriendFunction)
- << FirstND;
- ODRDiagDeclNote(SecondFriend->getFriendLoc(),
- SecondFriend->getSourceRange(), FriendFunction)
- << SecondND;
- Diagnosed = true;
- break;
- }
-
- if (FirstTSI && SecondTSI) {
- QualType FirstFriendType = FirstTSI->getType();
- QualType SecondFriendType = SecondTSI->getType();
- assert(computeODRHash(FirstFriendType) !=
- computeODRHash(SecondFriendType));
- ODRDiagDeclError(FirstFriend->getFriendLoc(),
- FirstFriend->getSourceRange(), FriendType)
- << FirstFriendType;
- ODRDiagDeclNote(SecondFriend->getFriendLoc(),
- SecondFriend->getSourceRange(), FriendType)
- << SecondFriendType;
- Diagnosed = true;
- break;
- }
-
- ODRDiagDeclError(FirstFriend->getFriendLoc(),
- FirstFriend->getSourceRange(), FriendTypeFunction)
- << (FirstTSI == nullptr);
- ODRDiagDeclNote(SecondFriend->getFriendLoc(),
- SecondFriend->getSourceRange(), FriendTypeFunction)
- << (SecondTSI == nullptr);
+ if (DiagsEmitter.diagnoseMismatch(FirstRecord, RecordPair.first,
+ RecordPair.second)) {
Diagnosed = true;
break;
}
- case FunctionTemplate: {
- const FunctionTemplateDecl *FirstTemplate =
- cast<FunctionTemplateDecl>(FirstDecl);
- const FunctionTemplateDecl *SecondTemplate =
- cast<FunctionTemplateDecl>(SecondDecl);
-
- TemplateParameterList *FirstTPL =
- FirstTemplate->getTemplateParameters();
- TemplateParameterList *SecondTPL =
- SecondTemplate->getTemplateParameters();
-
- auto DiagTemplateError = [&ODRDiagDeclError, FirstTemplate](
- ODRCXXRecordDifference DiffType) {
- return ODRDiagDeclError(FirstTemplate->getLocation(),
- FirstTemplate->getSourceRange(), DiffType)
- << FirstTemplate;
- };
- auto DiagTemplateNote = [&ODRDiagDeclNote, SecondTemplate](
- ODRCXXRecordDifference DiffType) {
- return ODRDiagDeclNote(SecondTemplate->getLocation(),
- SecondTemplate->getSourceRange(), DiffType)
- << SecondTemplate;
- };
-
- if (FirstTPL->size() != SecondTPL->size()) {
- DiagTemplateError(FunctionTemplateDifferentNumberParameters)
- << FirstTPL->size();
- DiagTemplateNote(FunctionTemplateDifferentNumberParameters)
- << SecondTPL->size();
- Diagnosed = true;
- break;
- }
-
- bool ParameterMismatch = false;
- for (unsigned i = 0, e = FirstTPL->size(); i != e; ++i) {
- NamedDecl *FirstParam = FirstTPL->getParam(i);
- NamedDecl *SecondParam = SecondTPL->getParam(i);
-
- if (FirstParam->getKind() != SecondParam->getKind()) {
- enum {
- TemplateTypeParameter,
- NonTypeTemplateParameter,
- TemplateTemplateParameter,
- };
- auto GetParamType = [](NamedDecl *D) {
- switch (D->getKind()) {
- default:
- llvm_unreachable("Unexpected template parameter type");
- case Decl::TemplateTypeParm:
- return TemplateTypeParameter;
- case Decl::NonTypeTemplateParm:
- return NonTypeTemplateParameter;
- case Decl::TemplateTemplateParm:
- return TemplateTemplateParameter;
- }
- };
-
- DiagTemplateError(FunctionTemplateParameterDifferentKind)
- << (i + 1) << GetParamType(FirstParam);
- DiagTemplateNote(FunctionTemplateParameterDifferentKind)
- << (i + 1) << GetParamType(SecondParam);
- ParameterMismatch = true;
- break;
- }
-
- if (FirstParam->getName() != SecondParam->getName()) {
- DiagTemplateError(FunctionTemplateParameterName)
- << (i + 1) << (bool)FirstParam->getIdentifier() << FirstParam;
- DiagTemplateNote(FunctionTemplateParameterName)
- << (i + 1) << (bool)SecondParam->getIdentifier() << SecondParam;
- ParameterMismatch = true;
- break;
- }
-
- if (isa<TemplateTypeParmDecl>(FirstParam) &&
- isa<TemplateTypeParmDecl>(SecondParam)) {
- TemplateTypeParmDecl *FirstTTPD =
- cast<TemplateTypeParmDecl>(FirstParam);
- TemplateTypeParmDecl *SecondTTPD =
- cast<TemplateTypeParmDecl>(SecondParam);
- bool HasFirstDefaultArgument =
- FirstTTPD->hasDefaultArgument() &&
- !FirstTTPD->defaultArgumentWasInherited();
- bool HasSecondDefaultArgument =
- SecondTTPD->hasDefaultArgument() &&
- !SecondTTPD->defaultArgumentWasInherited();
- if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
- DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasFirstDefaultArgument;
- DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasSecondDefaultArgument;
- ParameterMismatch = true;
- break;
- }
-
- if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
- QualType FirstType = FirstTTPD->getDefaultArgument();
- QualType SecondType = SecondTTPD->getDefaultArgument();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagTemplateError(
- FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << FirstType;
- DiagTemplateNote(
- FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << SecondType;
- ParameterMismatch = true;
- break;
- }
- }
-
- if (FirstTTPD->isParameterPack() !=
- SecondTTPD->isParameterPack()) {
- DiagTemplateError(FunctionTemplatePackParameter)
- << (i + 1) << FirstTTPD->isParameterPack();
- DiagTemplateNote(FunctionTemplatePackParameter)
- << (i + 1) << SecondTTPD->isParameterPack();
- ParameterMismatch = true;
- break;
- }
- }
-
- if (isa<TemplateTemplateParmDecl>(FirstParam) &&
- isa<TemplateTemplateParmDecl>(SecondParam)) {
- TemplateTemplateParmDecl *FirstTTPD =
- cast<TemplateTemplateParmDecl>(FirstParam);
- TemplateTemplateParmDecl *SecondTTPD =
- cast<TemplateTemplateParmDecl>(SecondParam);
-
- TemplateParameterList *FirstTPL =
- FirstTTPD->getTemplateParameters();
- TemplateParameterList *SecondTPL =
- SecondTTPD->getTemplateParameters();
-
- auto ComputeTemplateParameterListODRHash =
- [](const TemplateParameterList *TPL) {
- assert(TPL);
- ODRHash Hasher;
- Hasher.AddTemplateParameterList(TPL);
- return Hasher.CalculateHash();
- };
-
- if (ComputeTemplateParameterListODRHash(FirstTPL) !=
- ComputeTemplateParameterListODRHash(SecondTPL)) {
- DiagTemplateError(FunctionTemplateParameterDifferentType)
- << (i + 1);
- DiagTemplateNote(FunctionTemplateParameterDifferentType)
- << (i + 1);
- ParameterMismatch = true;
- break;
- }
-
- bool HasFirstDefaultArgument =
- FirstTTPD->hasDefaultArgument() &&
- !FirstTTPD->defaultArgumentWasInherited();
- bool HasSecondDefaultArgument =
- SecondTTPD->hasDefaultArgument() &&
- !SecondTTPD->defaultArgumentWasInherited();
- if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
- DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasFirstDefaultArgument;
- DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasSecondDefaultArgument;
- ParameterMismatch = true;
- break;
- }
-
- if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
- TemplateArgument FirstTA =
- FirstTTPD->getDefaultArgument().getArgument();
- TemplateArgument SecondTA =
- SecondTTPD->getDefaultArgument().getArgument();
- if (computeODRHash(FirstTA) != computeODRHash(SecondTA)) {
- DiagTemplateError(
- FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << FirstTA;
- DiagTemplateNote(
- FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << SecondTA;
- ParameterMismatch = true;
- break;
- }
- }
-
- if (FirstTTPD->isParameterPack() !=
- SecondTTPD->isParameterPack()) {
- DiagTemplateError(FunctionTemplatePackParameter)
- << (i + 1) << FirstTTPD->isParameterPack();
- DiagTemplateNote(FunctionTemplatePackParameter)
- << (i + 1) << SecondTTPD->isParameterPack();
- ParameterMismatch = true;
- break;
- }
- }
-
- if (isa<NonTypeTemplateParmDecl>(FirstParam) &&
- isa<NonTypeTemplateParmDecl>(SecondParam)) {
- NonTypeTemplateParmDecl *FirstNTTPD =
- cast<NonTypeTemplateParmDecl>(FirstParam);
- NonTypeTemplateParmDecl *SecondNTTPD =
- cast<NonTypeTemplateParmDecl>(SecondParam);
-
- QualType FirstType = FirstNTTPD->getType();
- QualType SecondType = SecondNTTPD->getType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagTemplateError(FunctionTemplateParameterDifferentType)
- << (i + 1);
- DiagTemplateNote(FunctionTemplateParameterDifferentType)
- << (i + 1);
- ParameterMismatch = true;
- break;
- }
-
- bool HasFirstDefaultArgument =
- FirstNTTPD->hasDefaultArgument() &&
- !FirstNTTPD->defaultArgumentWasInherited();
- bool HasSecondDefaultArgument =
- SecondNTTPD->hasDefaultArgument() &&
- !SecondNTTPD->defaultArgumentWasInherited();
- if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
- DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasFirstDefaultArgument;
- DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasSecondDefaultArgument;
- ParameterMismatch = true;
- break;
- }
-
- if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
- Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument();
- Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument();
- if (computeODRHash(FirstDefaultArgument) !=
- computeODRHash(SecondDefaultArgument)) {
- DiagTemplateError(
- FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << FirstDefaultArgument;
- DiagTemplateNote(
- FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << SecondDefaultArgument;
- ParameterMismatch = true;
- break;
- }
- }
-
- if (FirstNTTPD->isParameterPack() !=
- SecondNTTPD->isParameterPack()) {
- DiagTemplateError(FunctionTemplatePackParameter)
- << (i + 1) << FirstNTTPD->isParameterPack();
- DiagTemplateNote(FunctionTemplatePackParameter)
- << (i + 1) << SecondNTTPD->isParameterPack();
- ParameterMismatch = true;
- break;
- }
- }
- }
-
- if (ParameterMismatch) {
- Diagnosed = true;
- break;
- }
-
- break;
- }
- }
-
- if (Diagnosed)
- continue;
-
- Diag(FirstDecl->getLocation(),
- diag::err_module_odr_violation_mismatch_decl_unknown)
- << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
- << FirstDecl->getSourceRange();
- Diag(SecondDecl->getLocation(),
- diag::note_module_odr_violation_mismatch_decl_unknown)
- << SecondModule << FirstDiffType << SecondDecl->getSourceRange();
- Diagnosed = true;
}
if (!Diagnosed) {
@@ -10988,158 +9705,39 @@ void ASTReader::diagnoseOdrViolations() {
// FIXME: How can this even happen?
Diag(Merge.first->getLocation(),
diag::err_module_odr_violation_different_instantiations)
- << Merge.first;
+ << Merge.first;
}
}
- // Issue ODR failures diagnostics for functions.
- for (auto &Merge : FunctionOdrMergeFailures) {
- enum ODRFunctionDifference {
- ReturnType,
- ParameterName,
- ParameterType,
- ParameterSingleDefaultArgument,
- ParameterDifferentDefaultArgument,
- FunctionBody,
- };
-
- FunctionDecl *FirstFunction = Merge.first;
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstFunction);
+ // Issue any pending ODR-failure diagnostics for RecordDecl in C/ObjC. Note
+ // that in C++ this is done as a part of CXXRecordDecl ODR checking.
+ for (auto &Merge : RecordOdrMergeFailures) {
+ // If we've already pointed out a specific problem with this class, don't
+ // bother issuing a general "something's different" diagnostic.
+ if (!DiagnosedOdrMergeFailures.insert(Merge.first).second)
+ continue;
+ RecordDecl *FirstRecord = Merge.first;
bool Diagnosed = false;
- for (auto &SecondFunction : Merge.second) {
-
- if (FirstFunction == SecondFunction)
- continue;
-
- std::string SecondModule =
- getOwningModuleNameForDiagnostic(SecondFunction);
-
- auto ODRDiagError = [FirstFunction, &FirstModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRFunctionDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_function)
- << FirstFunction << FirstModule.empty() << FirstModule << Range
- << DiffType;
- };
- auto ODRDiagNote = [&SecondModule, this](SourceLocation Loc,
- SourceRange Range,
- ODRFunctionDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_function)
- << SecondModule << Range << DiffType;
- };
-
- if (computeODRHash(FirstFunction->getReturnType()) !=
- computeODRHash(SecondFunction->getReturnType())) {
- ODRDiagError(FirstFunction->getReturnTypeSourceRange().getBegin(),
- FirstFunction->getReturnTypeSourceRange(), ReturnType)
- << FirstFunction->getReturnType();
- ODRDiagNote(SecondFunction->getReturnTypeSourceRange().getBegin(),
- SecondFunction->getReturnTypeSourceRange(), ReturnType)
- << SecondFunction->getReturnType();
+ for (auto *SecondRecord : Merge.second) {
+ if (DiagsEmitter.diagnoseMismatch(FirstRecord, SecondRecord)) {
Diagnosed = true;
break;
}
+ }
+ (void)Diagnosed;
+ assert(Diagnosed && "Unable to emit ODR diagnostic.");
+ }
- assert(FirstFunction->param_size() == SecondFunction->param_size() &&
- "Merged functions with different number of parameters");
-
- size_t ParamSize = FirstFunction->param_size();
- bool ParameterMismatch = false;
- for (unsigned I = 0; I < ParamSize; ++I) {
- const ParmVarDecl *FirstParam = FirstFunction->getParamDecl(I);
- const ParmVarDecl *SecondParam = SecondFunction->getParamDecl(I);
-
- assert(getContext().hasSameType(FirstParam->getType(),
- SecondParam->getType()) &&
- "Merged function has different parameter types.");
-
- if (FirstParam->getDeclName() != SecondParam->getDeclName()) {
- ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
- ParameterName)
- << I + 1 << FirstParam->getDeclName();
- ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
- ParameterName)
- << I + 1 << SecondParam->getDeclName();
- ParameterMismatch = true;
- break;
- };
-
- QualType FirstParamType = FirstParam->getType();
- QualType SecondParamType = SecondParam->getType();
- if (FirstParamType != SecondParamType &&
- computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
- if (const DecayedType *ParamDecayedType =
- FirstParamType->getAs<DecayedType>()) {
- ODRDiagError(FirstParam->getLocation(),
- FirstParam->getSourceRange(), ParameterType)
- << (I + 1) << FirstParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- ODRDiagError(FirstParam->getLocation(),
- FirstParam->getSourceRange(), ParameterType)
- << (I + 1) << FirstParamType << false;
- }
-
- if (const DecayedType *ParamDecayedType =
- SecondParamType->getAs<DecayedType>()) {
- ODRDiagNote(SecondParam->getLocation(),
- SecondParam->getSourceRange(), ParameterType)
- << (I + 1) << SecondParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- ODRDiagNote(SecondParam->getLocation(),
- SecondParam->getSourceRange(), ParameterType)
- << (I + 1) << SecondParamType << false;
- }
- ParameterMismatch = true;
- break;
- }
-
- const Expr *FirstInit = FirstParam->getInit();
- const Expr *SecondInit = SecondParam->getInit();
- if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
- ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
- ParameterSingleDefaultArgument)
- << (I + 1) << (FirstInit == nullptr)
- << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
- ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
- ParameterSingleDefaultArgument)
- << (I + 1) << (SecondInit == nullptr)
- << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
- ParameterMismatch = true;
- break;
- }
-
- if (FirstInit && SecondInit &&
- computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
- ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
- ParameterDifferentDefaultArgument)
- << (I + 1) << FirstInit->getSourceRange();
- ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
- ParameterDifferentDefaultArgument)
- << (I + 1) << SecondInit->getSourceRange();
- ParameterMismatch = true;
- break;
- }
-
- assert(computeODRHash(FirstParam) == computeODRHash(SecondParam) &&
- "Undiagnosed parameter difference.");
- }
-
- if (ParameterMismatch) {
+ // Issue ODR failures diagnostics for functions.
+ for (auto &Merge : FunctionOdrMergeFailures) {
+ FunctionDecl *FirstFunction = Merge.first;
+ bool Diagnosed = false;
+ for (auto &SecondFunction : Merge.second) {
+ if (DiagsEmitter.diagnoseMismatch(FirstFunction, SecondFunction)) {
Diagnosed = true;
break;
}
-
- // If no error has been generated before now, assume the problem is in
- // the body and generate a message.
- ODRDiagError(FirstFunction->getLocation(),
- FirstFunction->getSourceRange(), FunctionBody);
- ODRDiagNote(SecondFunction->getLocation(),
- SecondFunction->getSourceRange(), FunctionBody);
- Diagnosed = true;
- break;
}
(void)Diagnosed;
assert(Diagnosed && "Unable to emit ODR diagnostic.");
@@ -11147,164 +9745,57 @@ void ASTReader::diagnoseOdrViolations() {
// Issue ODR failures diagnostics for enums.
for (auto &Merge : EnumOdrMergeFailures) {
- enum ODREnumDifference {
- SingleScopedEnum,
- EnumTagKeywordMismatch,
- SingleSpecifiedType,
- DifferentSpecifiedTypes,
- DifferentNumberEnumConstants,
- EnumConstantName,
- EnumConstantSingleInitializer,
- EnumConstantDifferentInitializer,
- };
-
// If we've already pointed out a specific problem with this enum, don't
// bother issuing a general "something's different" diagnostic.
if (!DiagnosedOdrMergeFailures.insert(Merge.first).second)
continue;
EnumDecl *FirstEnum = Merge.first;
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstEnum);
-
- using DeclHashes =
- llvm::SmallVector<std::pair<EnumConstantDecl *, unsigned>, 4>;
- auto PopulateHashes = [FirstEnum](DeclHashes &Hashes, EnumDecl *Enum) {
- for (auto *D : Enum->decls()) {
- // Due to decl merging, the first EnumDecl is the parent of
- // Decls in both records.
- if (!ODRHash::isDeclToBeProcessed(D, FirstEnum))
- continue;
- assert(isa<EnumConstantDecl>(D) && "Unexpected Decl kind");
- Hashes.emplace_back(cast<EnumConstantDecl>(D), computeODRHash(D));
- }
- };
- DeclHashes FirstHashes;
- PopulateHashes(FirstHashes, FirstEnum);
bool Diagnosed = false;
for (auto &SecondEnum : Merge.second) {
-
- if (FirstEnum == SecondEnum)
- continue;
-
- std::string SecondModule =
- getOwningModuleNameForDiagnostic(SecondEnum);
-
- auto ODRDiagError = [FirstEnum, &FirstModule,
- this](const auto *DiagAnchor,
- ODREnumDifference DiffType) {
- return Diag(DiagAnchor->getLocation(),
- diag::err_module_odr_violation_enum)
- << FirstEnum << FirstModule.empty() << FirstModule
- << DiagAnchor->getSourceRange() << DiffType;
- };
- auto ODRDiagNote = [&SecondModule, this](const auto *DiagAnchor,
- ODREnumDifference DiffType) {
- return Diag(DiagAnchor->getLocation(),
- diag::note_module_odr_violation_enum)
- << SecondModule << DiagAnchor->getSourceRange() << DiffType;
- };
-
- if (FirstEnum->isScoped() != SecondEnum->isScoped()) {
- ODRDiagError(FirstEnum, SingleScopedEnum) << FirstEnum->isScoped();
- ODRDiagNote(SecondEnum, SingleScopedEnum) << SecondEnum->isScoped();
+ if (DiagsEmitter.diagnoseMismatch(FirstEnum, SecondEnum)) {
Diagnosed = true;
- continue;
+ break;
}
+ }
+ (void)Diagnosed;
+ assert(Diagnosed && "Unable to emit ODR diagnostic.");
+ }
- if (FirstEnum->isScoped() && SecondEnum->isScoped()) {
- if (FirstEnum->isScopedUsingClassTag() !=
- SecondEnum->isScopedUsingClassTag()) {
- ODRDiagError(FirstEnum, EnumTagKeywordMismatch)
- << FirstEnum->isScopedUsingClassTag();
- ODRDiagNote(SecondEnum, EnumTagKeywordMismatch)
- << SecondEnum->isScopedUsingClassTag();
- Diagnosed = true;
- continue;
- }
- }
+ for (auto &Merge : ObjCInterfaceOdrMergeFailures) {
+ // If we've already pointed out a specific problem with this interface,
+ // don't bother issuing a general "something's different" diagnostic.
+ if (!DiagnosedOdrMergeFailures.insert(Merge.first).second)
+ continue;
- QualType FirstUnderlyingType =
- FirstEnum->getIntegerTypeSourceInfo()
- ? FirstEnum->getIntegerTypeSourceInfo()->getType()
- : QualType();
- QualType SecondUnderlyingType =
- SecondEnum->getIntegerTypeSourceInfo()
- ? SecondEnum->getIntegerTypeSourceInfo()->getType()
- : QualType();
- if (FirstUnderlyingType.isNull() != SecondUnderlyingType.isNull()) {
- ODRDiagError(FirstEnum, SingleSpecifiedType)
- << !FirstUnderlyingType.isNull();
- ODRDiagNote(SecondEnum, SingleSpecifiedType)
- << !SecondUnderlyingType.isNull();
+ bool Diagnosed = false;
+ ObjCInterfaceDecl *FirstID = Merge.first;
+ for (auto &InterfacePair : Merge.second) {
+ if (DiagsEmitter.diagnoseMismatch(FirstID, InterfacePair.first,
+ InterfacePair.second)) {
Diagnosed = true;
- continue;
- }
-
- if (!FirstUnderlyingType.isNull() && !SecondUnderlyingType.isNull()) {
- if (computeODRHash(FirstUnderlyingType) !=
- computeODRHash(SecondUnderlyingType)) {
- ODRDiagError(FirstEnum, DifferentSpecifiedTypes)
- << FirstUnderlyingType;
- ODRDiagNote(SecondEnum, DifferentSpecifiedTypes)
- << SecondUnderlyingType;
- Diagnosed = true;
- continue;
- }
+ break;
}
+ }
+ (void)Diagnosed;
+ assert(Diagnosed && "Unable to emit ODR diagnostic.");
+ }
- DeclHashes SecondHashes;
- PopulateHashes(SecondHashes, SecondEnum);
+ for (auto &Merge : ObjCProtocolOdrMergeFailures) {
+ // If we've already pointed out a specific problem with this protocol,
+ // don't bother issuing a general "something's different" diagnostic.
+ if (!DiagnosedOdrMergeFailures.insert(Merge.first).second)
+ continue;
- if (FirstHashes.size() != SecondHashes.size()) {
- ODRDiagError(FirstEnum, DifferentNumberEnumConstants)
- << (int)FirstHashes.size();
- ODRDiagNote(SecondEnum, DifferentNumberEnumConstants)
- << (int)SecondHashes.size();
+ ObjCProtocolDecl *FirstProtocol = Merge.first;
+ bool Diagnosed = false;
+ for (auto &ProtocolPair : Merge.second) {
+ if (DiagsEmitter.diagnoseMismatch(FirstProtocol, ProtocolPair.first,
+ ProtocolPair.second)) {
Diagnosed = true;
- continue;
- }
-
- for (unsigned I = 0; I < FirstHashes.size(); ++I) {
- if (FirstHashes[I].second == SecondHashes[I].second)
- continue;
- const EnumConstantDecl *FirstConstant = FirstHashes[I].first;
- const EnumConstantDecl *SecondConstant = SecondHashes[I].first;
-
- if (FirstConstant->getDeclName() != SecondConstant->getDeclName()) {
-
- ODRDiagError(FirstConstant, EnumConstantName)
- << I + 1 << FirstConstant;
- ODRDiagNote(SecondConstant, EnumConstantName)
- << I + 1 << SecondConstant;
- Diagnosed = true;
- break;
- }
-
- const Expr *FirstInit = FirstConstant->getInitExpr();
- const Expr *SecondInit = SecondConstant->getInitExpr();
- if (!FirstInit && !SecondInit)
- continue;
-
- if (!FirstInit || !SecondInit) {
- ODRDiagError(FirstConstant, EnumConstantSingleInitializer)
- << I + 1 << FirstConstant << (FirstInit != nullptr);
- ODRDiagNote(SecondConstant, EnumConstantSingleInitializer)
- << I + 1 << SecondConstant << (SecondInit != nullptr);
- Diagnosed = true;
- break;
- }
-
- if (computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
- ODRDiagError(FirstConstant, EnumConstantDifferentInitializer)
- << I + 1 << FirstConstant;
- ODRDiagNote(SecondConstant, EnumConstantDifferentInitializer)
- << I + 1 << SecondConstant;
- Diagnosed = true;
- break;
- }
+ break;
}
}
-
(void)Diagnosed;
assert(Diagnosed && "Unable to emit ODR diagnostic.");
}
@@ -11586,7 +10077,16 @@ OMPClause *OMPClauseReader::readClause() {
case llvm::omp::OMPC_atomic_default_mem_order:
C = new (Context) OMPAtomicDefaultMemOrderClause();
break;
- case llvm::omp::OMPC_private:
+ case llvm::omp::OMPC_at:
+ C = new (Context) OMPAtClause();
+ break;
+ case llvm::omp::OMPC_severity:
+ C = new (Context) OMPSeverityClause();
+ break;
+ case llvm::omp::OMPC_message:
+ C = new (Context) OMPMessageClause();
+ break;
+ case llvm::omp::OMPC_private:
C = OMPPrivateClause::CreateEmpty(Context, Record.readInt());
break;
case llvm::omp::OMPC_firstprivate:
@@ -11772,6 +10272,9 @@ OMPClause *OMPClauseReader::readClause() {
case llvm::omp::OMPC_align:
C = new (Context) OMPAlignClause();
break;
+ case llvm::omp::OMPC_ompx_dyn_cgroup_mem:
+ C = new (Context) OMPXDynCGroupMemClause();
+ break;
#define OMP_CLAUSE_NO_CLASS(Enum, Str) \
case llvm::omp::Enum: \
break;
@@ -11988,6 +10491,23 @@ void OMPClauseReader::VisitOMPAtomicDefaultMemOrderClause(
C->setAtomicDefaultMemOrderKindKwLoc(Record.readSourceLocation());
}
+void OMPClauseReader::VisitOMPAtClause(OMPAtClause *C) {
+ C->setAtKind(static_cast<OpenMPAtClauseKind>(Record.readInt()));
+ C->setLParenLoc(Record.readSourceLocation());
+ C->setAtKindKwLoc(Record.readSourceLocation());
+}
+
+void OMPClauseReader::VisitOMPSeverityClause(OMPSeverityClause *C) {
+ C->setSeverityKind(static_cast<OpenMPSeverityClauseKind>(Record.readInt()));
+ C->setLParenLoc(Record.readSourceLocation());
+ C->setSeverityKindKwLoc(Record.readSourceLocation());
+}
+
+void OMPClauseReader::VisitOMPMessageClause(OMPMessageClause *C) {
+ C->setMessageString(Record.readSubExpr());
+ C->setLParenLoc(Record.readSourceLocation());
+}
+
void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
C->setLParenLoc(Record.readSourceLocation());
unsigned NumVars = C->varlist_size();
@@ -12314,10 +10834,13 @@ void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) {
void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) {
C->setLParenLoc(Record.readSourceLocation());
+ bool HasIteratorModifier = false;
for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) {
C->setMapTypeModifier(
I, static_cast<OpenMPMapModifierKind>(Record.readInt()));
C->setMapTypeModifierLoc(I, Record.readSourceLocation());
+ if (C->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_iterator)
+ HasIteratorModifier = true;
}
C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc());
C->setMapperIdInfo(Record.readDeclarationNameInfo());
@@ -12342,6 +10865,9 @@ void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) {
UDMappers.push_back(Record.readExpr());
C->setUDMapperRefs(UDMappers);
+ if (HasIteratorModifier)
+ C->setIteratorModifier(Record.readExpr());
+
SmallVector<ValueDecl *, 16> Decls;
Decls.reserve(UniqueDecls);
for (unsigned i = 0; i < UniqueDecls; ++i)
@@ -12403,13 +10929,17 @@ void OMPClauseReader::VisitOMPPriorityClause(OMPPriorityClause *C) {
void OMPClauseReader::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) {
VisitOMPClauseWithPreInit(C);
+ C->setModifier(Record.readEnum<OpenMPGrainsizeClauseModifier>());
C->setGrainsize(Record.readSubExpr());
+ C->setModifierLoc(Record.readSourceLocation());
C->setLParenLoc(Record.readSourceLocation());
}
void OMPClauseReader::VisitOMPNumTasksClause(OMPNumTasksClause *C) {
VisitOMPClauseWithPreInit(C);
+ C->setModifier(Record.readEnum<OpenMPNumTasksClauseModifier>());
C->setNumTasks(Record.readSubExpr());
+ C->setModifierLoc(Record.readSourceLocation());
C->setLParenLoc(Record.readSourceLocation());
}
@@ -12792,8 +11322,10 @@ void OMPClauseReader::VisitOMPAffinityClause(OMPAffinityClause *C) {
void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) {
C->setKind(Record.readEnum<OpenMPOrderClauseKind>());
+ C->setModifier(Record.readEnum<OpenMPOrderClauseModifier>());
C->setLParenLoc(Record.readSourceLocation());
C->setKindKwLoc(Record.readSourceLocation());
+ C->setModifierKwLoc(Record.readSourceLocation());
}
void OMPClauseReader::VisitOMPFilterClause(OMPFilterClause *C) {
@@ -12813,6 +11345,12 @@ void OMPClauseReader::VisitOMPAlignClause(OMPAlignClause *C) {
C->setLParenLoc(Record.readSourceLocation());
}
+void OMPClauseReader::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) {
+ VisitOMPClauseWithPreInit(C);
+ C->setSize(Record.readSubExpr());
+ C->setLParenLoc(Record.readSourceLocation());
+}
+
OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() {
OMPTraitInfo &TI = getContext().getNewOMPTraitInfo();
TI.Sets.resize(readUInt32());
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 73800191dfc1..8cb513eff13e 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -322,6 +322,7 @@ namespace clang {
void VisitNamedDecl(NamedDecl *ND);
void VisitLabelDecl(LabelDecl *LD);
void VisitNamespaceDecl(NamespaceDecl *D);
+ void VisitHLSLBufferDecl(HLSLBufferDecl *D);
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitTypeDecl(TypeDecl *TD);
@@ -381,8 +382,10 @@ namespace clang {
void VisitDecompositionDecl(DecompositionDecl *DD);
void VisitBindingDecl(BindingDecl *BD);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
- DeclID VisitTemplateDecl(TemplateDecl *D);
+ void VisitTemplateDecl(TemplateDecl *D);
void VisitConceptDecl(ConceptDecl *D);
+ void VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D);
void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
@@ -399,6 +402,7 @@ namespace clang {
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitExportDecl(ExportDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD);
+ void VisitTopLevelStmtDecl(TopLevelStmtDecl *D);
void VisitImportDecl(ImportDecl *D);
void VisitAccessSpecDecl(AccessSpecDecl *D);
void VisitFriendDecl(FriendDecl *D);
@@ -414,14 +418,15 @@ namespace clang {
template<typename T>
RedeclarableResult VisitRedeclarable(Redeclarable<T> *D);
- template<typename T>
- void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl,
- DeclID TemplatePatternID = 0);
+ template <typename T>
+ void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
- template<typename T>
+ void mergeRedeclarableTemplate(RedeclarableTemplateDecl *D,
+ RedeclarableResult &Redecl);
+
+ template <typename T>
void mergeRedeclarable(Redeclarable<T> *D, T *Existing,
- RedeclarableResult &Redecl,
- DeclID TemplatePatternID = 0);
+ RedeclarableResult &Redecl);
template<typename T>
void mergeMergeable(Mergeable<T> *D);
@@ -430,7 +435,7 @@ namespace clang {
void mergeTemplatePattern(RedeclarableTemplateDecl *D,
RedeclarableTemplateDecl *Existing,
- DeclID DsID, bool IsKeyDecl);
+ bool IsKeyDecl);
ObjCTypeParamList *ReadObjCTypeParamList();
@@ -563,7 +568,7 @@ void ASTDeclReader::Visit(Decl *D) {
void ASTDeclReader::VisitDecl(Decl *D) {
if (D->isTemplateParameter() || D->isTemplateParameterPack() ||
- isa<ParmVarDecl>(D) || isa<ObjCTypeParamDecl>(D)) {
+ isa<ParmVarDecl, ObjCTypeParamDecl>(D)) {
// We don't want to deserialize the DeclContext of a template
// parameter or of a parameter of a function template immediately. These
// entities might be used in the formulation of its DeclContext (for
@@ -824,6 +829,7 @@ ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) {
void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
VisitRecordDeclImpl(RD);
+ RD->setODRHash(Record.readInt());
// Maintain the invariant of a redeclaration chain containing only
// a single definition.
@@ -844,6 +850,8 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
Reader.MergedDeclContexts.insert(std::make_pair(RD, OldDef));
RD->demoteThisDefinitionToDeclaration();
Reader.mergeDefinitionVisibility(OldDef, RD);
+ if (OldDef->getODRHash() != RD->getODRHash())
+ Reader.PendingRecordOdrMergeFailures[OldDef].push_back(RD);
} else {
OldDef = RD;
}
@@ -886,88 +894,27 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
RedeclarableResult Redecl = VisitRedeclarable(FD);
- VisitDeclaratorDecl(FD);
-
- // Attach a type to this function. Use the real type if possible, but fall
- // back to the type as written if it involves a deduced return type.
- if (FD->getTypeSourceInfo() &&
- FD->getTypeSourceInfo()->getType()->castAs<FunctionType>()
- ->getReturnType()->getContainedAutoType()) {
- // We'll set up the real type in Visit, once we've finished loading the
- // function.
- FD->setType(FD->getTypeSourceInfo()->getType());
- Reader.PendingFunctionTypes.push_back({FD, DeferredTypeID});
- } else {
- FD->setType(Reader.GetType(DeferredTypeID));
- }
- DeferredTypeID = 0;
-
- FD->DNLoc = Record.readDeclarationNameLoc(FD->getDeclName());
- FD->IdentifierNamespace = Record.readInt();
-
- // FunctionDecl's body is handled last at ASTDeclReader::Visit,
- // after everything else is read.
-
- FD->setStorageClass(static_cast<StorageClass>(Record.readInt()));
- FD->setInlineSpecified(Record.readInt());
- FD->setImplicitlyInline(Record.readInt());
- FD->setVirtualAsWritten(Record.readInt());
- // We defer calling `FunctionDecl::setPure()` here as for methods of
- // `CXXTemplateSpecializationDecl`s, we may not have connected up the
- // definition (which is required for `setPure`).
- const bool Pure = Record.readInt();
- FD->setHasInheritedPrototype(Record.readInt());
- FD->setHasWrittenPrototype(Record.readInt());
- FD->setDeletedAsWritten(Record.readInt());
- FD->setTrivial(Record.readInt());
- FD->setTrivialForCall(Record.readInt());
- FD->setDefaulted(Record.readInt());
- FD->setExplicitlyDefaulted(Record.readInt());
- FD->setHasImplicitReturnZero(Record.readInt());
- FD->setConstexprKind(static_cast<ConstexprSpecKind>(Record.readInt()));
- FD->setUsesSEHTry(Record.readInt());
- FD->setHasSkippedBody(Record.readInt());
- FD->setIsMultiVersion(Record.readInt());
- FD->setLateTemplateParsed(Record.readInt());
-
- FD->setCachedLinkage(static_cast<Linkage>(Record.readInt()));
- FD->EndRangeLoc = readSourceLocation();
- FD->ODRHash = Record.readInt();
- FD->setHasODRHash(true);
-
- if (FD->isDefaulted()) {
- if (unsigned NumLookups = Record.readInt()) {
- SmallVector<DeclAccessPair, 8> Lookups;
- for (unsigned I = 0; I != NumLookups; ++I) {
- NamedDecl *ND = Record.readDeclAs<NamedDecl>();
- AccessSpecifier AS = (AccessSpecifier)Record.readInt();
- Lookups.push_back(DeclAccessPair::make(ND, AS));
- }
- FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create(
- Reader.getContext(), Lookups));
- }
- }
+ FunctionDecl *Existing = nullptr;
switch ((FunctionDecl::TemplatedKind)Record.readInt()) {
case FunctionDecl::TK_NonTemplate:
- mergeRedeclarable(FD, Redecl);
break;
case FunctionDecl::TK_DependentNonTemplate:
- mergeRedeclarable(FD, Redecl);
FD->setInstantiatedFromDecl(readDeclAs<FunctionDecl>());
break;
- case FunctionDecl::TK_FunctionTemplate:
- // Merged when we merge the template.
- FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>());
+ case FunctionDecl::TK_FunctionTemplate: {
+ auto *Template = readDeclAs<FunctionTemplateDecl>();
+ Template->init(FD);
+ FD->setDescribedFunctionTemplate(Template);
break;
+ }
case FunctionDecl::TK_MemberSpecialization: {
auto *InstFD = readDeclAs<FunctionDecl>();
auto TSK = (TemplateSpecializationKind)Record.readInt();
SourceLocation POI = readSourceLocation();
FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK);
FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
- mergeRedeclarable(FD, Redecl);
break;
}
case FunctionDecl::TK_FunctionTemplateSpecialization: {
@@ -1038,7 +985,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
else {
assert(Reader.getContext().getLangOpts().Modules &&
"already deserialized this template specialization");
- mergeRedeclarable(FD, ExistingInfo->getFunction(), Redecl);
+ Existing = ExistingInfo->getFunction();
}
}
break;
@@ -1066,6 +1013,97 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
}
}
+ VisitDeclaratorDecl(FD);
+
+ // Attach a type to this function. Use the real type if possible, but fall
+ // back to the type as written if it involves a deduced return type.
+ if (FD->getTypeSourceInfo() && FD->getTypeSourceInfo()
+ ->getType()
+ ->castAs<FunctionType>()
+ ->getReturnType()
+ ->getContainedAutoType()) {
+ // We'll set up the real type in Visit, once we've finished loading the
+ // function.
+ FD->setType(FD->getTypeSourceInfo()->getType());
+ Reader.PendingFunctionTypes.push_back({FD, DeferredTypeID});
+ } else {
+ FD->setType(Reader.GetType(DeferredTypeID));
+ }
+ DeferredTypeID = 0;
+
+ FD->DNLoc = Record.readDeclarationNameLoc(FD->getDeclName());
+ FD->IdentifierNamespace = Record.readInt();
+
+ // FunctionDecl's body is handled last at ASTDeclReader::Visit,
+ // after everything else is read.
+
+ FD->setStorageClass(static_cast<StorageClass>(Record.readInt()));
+ FD->setInlineSpecified(Record.readInt());
+ FD->setImplicitlyInline(Record.readInt());
+ FD->setVirtualAsWritten(Record.readInt());
+ // We defer calling `FunctionDecl::setPure()` here as for methods of
+ // `CXXTemplateSpecializationDecl`s, we may not have connected up the
+ // definition (which is required for `setPure`).
+ const bool Pure = Record.readInt();
+ FD->setHasInheritedPrototype(Record.readInt());
+ FD->setHasWrittenPrototype(Record.readInt());
+ FD->setDeletedAsWritten(Record.readInt());
+ FD->setTrivial(Record.readInt());
+ FD->setTrivialForCall(Record.readInt());
+ FD->setDefaulted(Record.readInt());
+ FD->setExplicitlyDefaulted(Record.readInt());
+ FD->setIneligibleOrNotSelected(Record.readInt());
+ FD->setHasImplicitReturnZero(Record.readInt());
+ FD->setConstexprKind(static_cast<ConstexprSpecKind>(Record.readInt()));
+ FD->setUsesSEHTry(Record.readInt());
+ FD->setHasSkippedBody(Record.readInt());
+ FD->setIsMultiVersion(Record.readInt());
+ FD->setLateTemplateParsed(Record.readInt());
+ FD->setFriendConstraintRefersToEnclosingTemplate(Record.readInt());
+
+ FD->setCachedLinkage(static_cast<Linkage>(Record.readInt()));
+ FD->EndRangeLoc = readSourceLocation();
+ FD->setDefaultLoc(readSourceLocation());
+
+ FD->ODRHash = Record.readInt();
+ FD->setHasODRHash(true);
+
+ if (FD->isDefaulted()) {
+ if (unsigned NumLookups = Record.readInt()) {
+ SmallVector<DeclAccessPair, 8> Lookups;
+ for (unsigned I = 0; I != NumLookups; ++I) {
+ NamedDecl *ND = Record.readDeclAs<NamedDecl>();
+ AccessSpecifier AS = (AccessSpecifier)Record.readInt();
+ Lookups.push_back(DeclAccessPair::make(ND, AS));
+ }
+ FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create(
+ Reader.getContext(), Lookups));
+ }
+ }
+
+ if (Existing)
+ mergeRedeclarable(FD, Existing, Redecl);
+ else if (auto Kind = FD->getTemplatedKind();
+ Kind == FunctionDecl::TK_FunctionTemplate ||
+ Kind == FunctionDecl::TK_FunctionTemplateSpecialization) {
+ // Function Templates have their FunctionTemplateDecls merged instead of
+ // their FunctionDecls.
+ auto merge = [this, &Redecl, FD](auto &&F) {
+ auto *Existing = cast_or_null<FunctionDecl>(Redecl.getKnownMergeTarget());
+ RedeclarableResult NewRedecl(Existing ? F(Existing) : nullptr,
+ Redecl.getFirstID(), Redecl.isKeyDecl());
+ mergeRedeclarableTemplate(F(FD), NewRedecl);
+ };
+ if (Kind == FunctionDecl::TK_FunctionTemplate)
+ merge(
+ [](FunctionDecl *FD) { return FD->getDescribedFunctionTemplate(); });
+ else
+ merge([](FunctionDecl *FD) {
+ return FD->getTemplateSpecializationInfo()->getTemplate();
+ });
+ } else
+ mergeRedeclarable(FD, Redecl);
+
// Defer calling `setPure` until merging above has guaranteed we've set
// `DefinitionData` (as this will need to access it).
FD->setPure(Pure);
@@ -1169,6 +1207,8 @@ void ASTDeclReader::ReadObjCDefinitionData(
Data.EndLoc = readSourceLocation();
Data.HasDesignatedInitializers = Record.readInt();
+ Data.ODRHash = Record.readInt();
+ Data.HasODRHash = true;
// Read the directly referenced protocols and their SourceLocations.
unsigned NumProtocols = Record.readInt();
@@ -1196,13 +1236,16 @@ void ASTDeclReader::ReadObjCDefinitionData(
void ASTDeclReader::MergeDefinitionData(ObjCInterfaceDecl *D,
struct ObjCInterfaceDecl::DefinitionData &&NewDD) {
struct ObjCInterfaceDecl::DefinitionData &DD = D->data();
- if (DD.Definition != NewDD.Definition) {
- Reader.MergedDeclContexts.insert(
- std::make_pair(NewDD.Definition, DD.Definition));
- Reader.mergeDefinitionVisibility(DD.Definition, NewDD.Definition);
- }
+ if (DD.Definition == NewDD.Definition)
+ return;
+
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(NewDD.Definition, DD.Definition));
+ Reader.mergeDefinitionVisibility(DD.Definition, NewDD.Definition);
- // FIXME: odr checking?
+ if (D->getODRHash() != NewDD.ODRHash)
+ Reader.PendingObjCInterfaceOdrMergeFailures[DD.Definition].push_back(
+ {NewDD.Definition, &NewDD});
}
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
@@ -1297,18 +1340,23 @@ void ASTDeclReader::ReadObjCDefinitionData(
ProtoLocs.push_back(readSourceLocation());
Data.ReferencedProtocols.set(ProtoRefs.data(), NumProtoRefs,
ProtoLocs.data(), Reader.getContext());
+ Data.ODRHash = Record.readInt();
+ Data.HasODRHash = true;
}
-void ASTDeclReader::MergeDefinitionData(ObjCProtocolDecl *D,
- struct ObjCProtocolDecl::DefinitionData &&NewDD) {
+void ASTDeclReader::MergeDefinitionData(
+ ObjCProtocolDecl *D, struct ObjCProtocolDecl::DefinitionData &&NewDD) {
struct ObjCProtocolDecl::DefinitionData &DD = D->data();
- if (DD.Definition != NewDD.Definition) {
- Reader.MergedDeclContexts.insert(
- std::make_pair(NewDD.Definition, DD.Definition));
- Reader.mergeDefinitionVisibility(DD.Definition, NewDD.Definition);
- }
+ if (DD.Definition == NewDD.Definition)
+ return;
+
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(NewDD.Definition, DD.Definition));
+ Reader.mergeDefinitionVisibility(DD.Definition, NewDD.Definition);
- // FIXME: odr checking?
+ if (D->getODRHash() != NewDD.ODRHash)
+ Reader.PendingObjCProtocolOdrMergeFailures[DD.Definition].push_back(
+ {NewDD.Definition, &NewDD});
}
void ASTDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
@@ -1640,6 +1688,11 @@ void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) {
AD->setRParenLoc(readSourceLocation());
}
+void ASTDeclReader::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) {
+ VisitDecl(D);
+ D->Statement = Record.readStmt();
+}
+
void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
VisitDecl(BD);
BD->setBody(cast_or_null<CompoundStmt>(Record.readStmt()));
@@ -1707,6 +1760,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
D->setInline(Record.readInt());
+ D->setNested(Record.readInt());
D->LocStart = readSourceLocation();
D->RBraceLoc = readSourceLocation();
@@ -1720,7 +1774,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
} else {
// Link this namespace back to the first declaration, which has already
// been deserialized.
- D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDecl());
+ D->AnonOrFirstNamespaceAndFlags.setPointer(D->getFirstDecl());
}
mergeRedeclarable(D, Redecl);
@@ -1735,6 +1789,15 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
}
}
+void ASTDeclReader::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
+ VisitNamedDecl(D);
+ VisitDeclContext(D);
+ D->IsCBuffer = Record.readBool();
+ D->KwLoc = readSourceLocation();
+ D->LBraceLoc = readSourceLocation();
+ D->RBraceLoc = readSourceLocation();
+}
+
void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
VisitNamedDecl(D);
@@ -1761,7 +1824,7 @@ void ASTDeclReader::VisitUsingEnumDecl(UsingEnumDecl *D) {
VisitNamedDecl(D);
D->setUsingLoc(readSourceLocation());
D->setEnumLoc(readSourceLocation());
- D->Enum = readDeclAs<EnumDecl>();
+ D->setEnumType(Record.readTypeSourceInfo());
D->FirstUsingShadow.setPointer(readDeclAs<UsingShadowDecl>());
if (auto *Pattern = readDeclAs<UsingEnumDecl>())
Reader.getContext().setInstantiatedFromUsingEnumDecl(D, Pattern);
@@ -1872,9 +1935,12 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.ManglingNumber = Record.readInt();
D->setDeviceLambdaManglingNumber(Record.readInt());
Lambda.ContextDecl = readDeclID();
- Lambda.Captures = (Capture *)Reader.getContext().Allocate(
- sizeof(Capture) * Lambda.NumCaptures);
- Capture *ToCapture = Lambda.Captures;
+ Capture *ToCapture = nullptr;
+ if (Lambda.NumCaptures) {
+ ToCapture = (Capture *)Reader.getContext().Allocate(sizeof(Capture) *
+ Lambda.NumCaptures);
+ Lambda.AddCaptureList(Reader.getContext(), ToCapture);
+ }
Lambda.MethodTyInfo = readTypeSourceInfo();
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
SourceLocation Loc = readSourceLocation();
@@ -1958,8 +2024,26 @@ void ASTDeclReader::MergeDefinitionData(
// lazily load it.
if (DD.IsLambda) {
- // FIXME: ODR-checking for merging lambdas (this happens, for instance,
- // when they occur within the body of a function template specialization).
+ auto &Lambda1 = static_cast<CXXRecordDecl::LambdaDefinitionData &>(DD);
+ auto &Lambda2 = static_cast<CXXRecordDecl::LambdaDefinitionData &>(MergeDD);
+ DetectedOdrViolation |= Lambda1.DependencyKind != Lambda2.DependencyKind;
+ DetectedOdrViolation |= Lambda1.IsGenericLambda != Lambda2.IsGenericLambda;
+ DetectedOdrViolation |= Lambda1.CaptureDefault != Lambda2.CaptureDefault;
+ DetectedOdrViolation |= Lambda1.NumCaptures != Lambda2.NumCaptures;
+ DetectedOdrViolation |=
+ Lambda1.NumExplicitCaptures != Lambda2.NumExplicitCaptures;
+ DetectedOdrViolation |=
+ Lambda1.HasKnownInternalLinkage != Lambda2.HasKnownInternalLinkage;
+ DetectedOdrViolation |= Lambda1.ManglingNumber != Lambda2.ManglingNumber;
+
+ if (Lambda1.NumCaptures && Lambda1.NumCaptures == Lambda2.NumCaptures) {
+ for (unsigned I = 0, N = Lambda1.NumCaptures; I != N; ++I) {
+ LambdaCapture &Cap1 = Lambda1.Captures.front()[I];
+ LambdaCapture &Cap2 = Lambda2.Captures.front()[I];
+ DetectedOdrViolation |= Cap1.getCaptureKind() != Cap2.getCaptureKind();
+ }
+ Lambda1.AddCaptureList(Reader.getContext(), Lambda2.Captures.front());
+ }
}
if (D->getODRHash() != MergeDD.ODRHash) {
@@ -2175,15 +2259,12 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
D->FriendLoc = readSourceLocation();
}
-DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
+void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
VisitNamedDecl(D);
- DeclID PatternID = readDeclID();
- auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
- TemplateParameterList *TemplateParams = Record.readTemplateParameterList();
- D->init(TemplatedDecl, TemplateParams);
-
- return PatternID;
+ assert(!D->TemplateParams && "TemplateParams already set!");
+ D->TemplateParams = Record.readTemplateParameterList();
+ D->init(readDeclAs<NamedDecl>());
}
void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {
@@ -2192,6 +2273,17 @@ void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {
mergeMergeable(D);
}
+void ASTDeclReader::VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D) {
+ // The size of the template list was read during creation of the Decl, so we
+ // don't have to re-read it here.
+ VisitDecl(D);
+ llvm::SmallVector<TemplateArgument, 4> Args;
+ for (unsigned I = 0; I < D->NumTemplateArgs; ++I)
+ Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/true));
+ D->setTemplateArguments(Args);
+}
+
void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
}
@@ -2220,21 +2312,15 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
}
}
- DeclID PatternID = VisitTemplateDecl(D);
+ VisitTemplateDecl(D);
D->IdentifierNamespace = Record.readInt();
- mergeRedeclarable(D, Redecl, PatternID);
-
- // If we merged the template with a prior declaration chain, merge the common
- // pointer.
- // FIXME: Actually merge here, don't just overwrite.
- D->Common = D->getCanonicalDecl()->Common;
-
return Redecl;
}
void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
+ mergeRedeclarableTemplate(D, Redecl);
if (ThisDeclID == Redecl.getFirstID()) {
// This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of
@@ -2262,6 +2348,7 @@ void ASTDeclReader::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
/// VarTemplateDecl beyond TemplateDecl...
void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
+ mergeRedeclarableTemplate(D, Redecl);
if (ThisDeclID == Redecl.getFirstID()) {
// This VarTemplateDecl owns a CommonPtr; read it to keep track of all of
@@ -2390,8 +2477,6 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
VarTemplateSpecializationDecl *D) {
- RedeclarableResult Redecl = VisitVarDeclImpl(D);
-
ASTContext &C = Reader.getContext();
if (Decl *InstD = readDecl()) {
if (auto *VTD = dyn_cast<VarTemplateDecl>(InstD)) {
@@ -2428,6 +2513,8 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
D->IsCompleteDefinition = Record.readInt();
+ RedeclarableResult Redecl = VisitVarDeclImpl(D);
+
bool writtenAsCanonicalDecl = Record.readInt();
if (writtenAsCanonicalDecl) {
auto *CanonPattern = readDeclAs<VarTemplateDecl>();
@@ -2535,7 +2622,8 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
}
void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
- VisitRedeclarableTemplateDecl(D);
+ RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
+ mergeRedeclarableTemplate(D, Redecl);
}
void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
@@ -2632,10 +2720,9 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
/// Attempts to merge the given declaration (D) with another declaration
/// of the same entity.
-template<typename T>
+template <typename T>
void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase,
- RedeclarableResult &Redecl,
- DeclID TemplatePatternID) {
+ RedeclarableResult &Redecl) {
// If modules are not available, there is no reason to perform this merge.
if (!Reader.getContext().getLangOpts().Modules)
return;
@@ -2648,10 +2735,19 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase,
if (auto *Existing = Redecl.getKnownMergeTarget())
// We already know of an existing declaration we should merge with.
- mergeRedeclarable(D, cast<T>(Existing), Redecl, TemplatePatternID);
+ mergeRedeclarable(D, cast<T>(Existing), Redecl);
else if (FindExistingResult ExistingRes = findExisting(D))
if (T *Existing = ExistingRes)
- mergeRedeclarable(D, Existing, Redecl, TemplatePatternID);
+ mergeRedeclarable(D, Existing, Redecl);
+}
+
+void ASTDeclReader::mergeRedeclarableTemplate(RedeclarableTemplateDecl *D,
+ RedeclarableResult &Redecl) {
+ mergeRedeclarable(D, Redecl);
+ // If we merged the template with a prior declaration chain, merge the
+ // common pointer.
+ // FIXME: Actually merge here, don't just overwrite.
+ D->Common = D->getCanonicalDecl()->Common;
}
/// "Cast" to type T, asserting if we don't have an implicit conversion.
@@ -2666,7 +2762,7 @@ template<typename T> static T assert_cast(...) {
/// declarations.
void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D,
RedeclarableTemplateDecl *Existing,
- DeclID DsID, bool IsKeyDecl) {
+ bool IsKeyDecl) {
auto *DPattern = D->getTemplatedDecl();
auto *ExistingPattern = Existing->getTemplatedDecl();
RedeclarableResult Result(/*MergeWith*/ ExistingPattern,
@@ -2706,17 +2802,13 @@ void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D,
/// Attempts to merge the given declaration (D) with another declaration
/// of the same entity.
-template<typename T>
+template <typename T>
void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
- RedeclarableResult &Redecl,
- DeclID TemplatePatternID) {
+ RedeclarableResult &Redecl) {
auto *D = static_cast<T *>(DBase);
T *ExistingCanon = Existing->getCanonicalDecl();
T *DCanon = D->getCanonicalDecl();
if (ExistingCanon != DCanon) {
- assert(DCanon->getGlobalID() == Redecl.getFirstID() &&
- "already merged this declaration");
-
// Have our redeclaration link point back at the canonical declaration
// of the existing declaration, so that this declaration has the
// appropriate canonical declaration.
@@ -2729,14 +2821,14 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
// We cannot have loaded any redeclarations of this declaration yet, so
// there's nothing else that needs to be updated.
if (auto *Namespace = dyn_cast<NamespaceDecl>(D))
- Namespace->AnonOrFirstNamespaceAndInline.setPointer(
- assert_cast<NamespaceDecl*>(ExistingCanon));
+ Namespace->AnonOrFirstNamespaceAndFlags.setPointer(
+ assert_cast<NamespaceDecl *>(ExistingCanon));
// When we merge a template, merge its pattern.
if (auto *DTemplate = dyn_cast<RedeclarableTemplateDecl>(D))
mergeTemplatePattern(
- DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon),
- TemplatePatternID, Redecl.isKeyDecl());
+ DTemplate, assert_cast<RedeclarableTemplateDecl *>(ExistingCanon),
+ Redecl.isKeyDecl());
// If this declaration is a key declaration, make a note of that.
if (Redecl.isKeyDecl())
@@ -2859,6 +2951,8 @@ public:
return Reader.readInt();
}
+ bool readBool() { return Reader.readBool(); }
+
SourceRange readSourceRange() {
return Reader.readSourceRange();
}
@@ -2964,16 +3058,11 @@ static bool isConsumerInterestedIn(ASTContext &Ctx, Decl *D, bool HasBody) {
return false;
}
- if (isa<FileScopeAsmDecl>(D) ||
- isa<ObjCProtocolDecl>(D) ||
- isa<ObjCImplDecl>(D) ||
- isa<ImportDecl>(D) ||
- isa<PragmaCommentDecl>(D) ||
- isa<PragmaDetectMismatchDecl>(D))
+ if (isa<FileScopeAsmDecl, TopLevelStmtDecl, ObjCProtocolDecl, ObjCImplDecl,
+ ImportDecl, PragmaCommentDecl, PragmaDetectMismatchDecl>(D))
return true;
- if (isa<OMPThreadPrivateDecl>(D) || isa<OMPDeclareReductionDecl>(D) ||
- isa<OMPDeclareMapperDecl>(D) || isa<OMPAllocateDecl>(D) ||
- isa<OMPRequiresDecl>(D))
+ if (isa<OMPThreadPrivateDecl, OMPDeclareReductionDecl, OMPDeclareMapperDecl,
+ OMPAllocateDecl, OMPRequiresDecl>(D))
return !D->getDeclContext()->isFunctionOrMethod();
if (const auto *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() &&
@@ -3776,6 +3865,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_FILE_SCOPE_ASM:
D = FileScopeAsmDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_TOP_LEVEL_STMT_DECL:
+ D = TopLevelStmtDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_BLOCK:
D = BlockDecl::CreateDeserialized(Context, ID);
break;
@@ -3853,6 +3945,13 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_OBJC_TYPE_PARAM:
D = ObjCTypeParamDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_HLSL_BUFFER:
+ D = HLSLBufferDecl::CreateDeserialized(Context, ID);
+ break;
+ case DECL_IMPLICIT_CONCEPT_SPECIALIZATION:
+ D = ImplicitConceptSpecializationDecl::CreateDeserialized(Context, ID,
+ Record.readInt());
+ break;
}
assert(D && "Unknown declaration reading AST file");
@@ -3906,8 +4005,7 @@ void ASTReader::PassInterestingDeclsToConsumer() {
// Guard variable to avoid recursively redoing the process of passing
// decls to consumer.
- SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
- true);
+ SaveAndRestore GuardPassingDeclsToConsumer(PassingDeclsToConsumer, true);
// Ensure that we've loaded all potentially-interesting declarations
// that need to be eagerly loaded.
@@ -3985,7 +4083,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
}
// Add the lazy specializations to the template.
assert((PendingLazySpecializationIDs.empty() || isa<ClassTemplateDecl>(D) ||
- isa<FunctionTemplateDecl>(D) || isa<VarTemplateDecl>(D)) &&
+ isa<FunctionTemplateDecl, VarTemplateDecl>(D)) &&
"Must not have pending specializations");
if (auto *CTD = dyn_cast<ClassTemplateDecl>(D))
ASTDeclReader::AddLazySpecializations(CTD, PendingLazySpecializationIDs);
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index e0ae019bf803..46d653c7f940 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -61,6 +61,7 @@
#include <algorithm>
#include <cassert>
#include <cstdint>
+#include <optional>
#include <string>
using namespace clang;
@@ -772,6 +773,7 @@ static ConstraintSatisfaction
readConstraintSatisfaction(ASTRecordReader &Record) {
ConstraintSatisfaction Satisfaction;
Satisfaction.IsSatisfied = Record.readInt();
+ Satisfaction.ContainsErrors = Record.readInt();
if (!Satisfaction.IsSatisfied) {
unsigned NumDetailRecords = Record.readInt();
for (unsigned i = 0; i != NumDetailRecords; ++i) {
@@ -793,17 +795,13 @@ readConstraintSatisfaction(ASTRecordReader &Record) {
void ASTStmtReader::VisitConceptSpecializationExpr(
ConceptSpecializationExpr *E) {
VisitExpr(E);
- unsigned NumTemplateArgs = Record.readInt();
E->NestedNameSpec = Record.readNestedNameSpecifierLoc();
E->TemplateKWLoc = Record.readSourceLocation();
E->ConceptName = Record.readDeclarationNameInfo();
E->NamedConcept = readDeclAs<ConceptDecl>();
E->FoundDecl = Record.readDeclAs<NamedDecl>();
+ E->SpecDecl = Record.readDeclAs<ImplicitConceptSpecializationDecl>();
E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
- llvm::SmallVector<TemplateArgument, 4> Args;
- for (unsigned I = 0; I < NumTemplateArgs; ++I)
- Args.push_back(Record.readTemplateArgument());
- E->setTemplateArguments(Args);
E->Satisfaction = E->isValueDependent() ? nullptr :
ASTConstraintSatisfaction::Create(Record.getContext(),
readConstraintSatisfaction(Record));
@@ -860,7 +858,7 @@ void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) {
} else
E = Record.readExpr();
- llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> Req;
+ std::optional<concepts::ExprRequirement::ReturnTypeRequirement> Req;
ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr;
SourceLocation NoexceptLoc;
if (RK == concepts::Requirement::RK_Simple) {
@@ -898,9 +896,17 @@ void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) {
std::move(*Req));
} break;
case concepts::Requirement::RK_Nested: {
- if (/* IsSubstitutionDiagnostic */Record.readInt()) {
+ bool HasInvalidConstraint = Record.readInt();
+ if (HasInvalidConstraint) {
+ std::string InvalidConstraint = Record.readString();
+ char *InvalidConstraintBuf =
+ new (Record.getContext()) char[InvalidConstraint.size()];
+ std::copy(InvalidConstraint.begin(), InvalidConstraint.end(),
+ InvalidConstraintBuf);
R = new (Record.getContext()) concepts::NestedRequirement(
- readSubstitutionDiagnostic(Record));
+ Record.getContext(),
+ StringRef(InvalidConstraintBuf, InvalidConstraint.size()),
+ readConstraintSatisfaction(Record));
break;
}
Expr *E = Record.readExpr();
@@ -1827,13 +1833,19 @@ void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
E->Param = readDeclAs<ParmVarDecl>();
E->UsedContext = readDeclAs<DeclContext>();
E->CXXDefaultArgExprBits.Loc = readSourceLocation();
+ E->CXXDefaultArgExprBits.HasRewrittenInit = Record.readInt();
+ if (E->CXXDefaultArgExprBits.HasRewrittenInit)
+ *E->getTrailingObjects<Expr *>() = Record.readSubExpr();
}
void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
VisitExpr(E);
+ E->CXXDefaultInitExprBits.HasRewrittenInit = Record.readInt();
E->Field = readDeclAs<FieldDecl>();
E->UsedContext = readDeclAs<DeclContext>();
E->CXXDefaultInitExprBits.Loc = readSourceLocation();
+ if (E->CXXDefaultInitExprBits.HasRewrittenInit)
+ *E->getTrailingObjects<Expr *>() = Record.readSubExpr();
}
void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
@@ -2117,8 +2129,10 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
- E->ParamAndRef.setPointer(readDeclAs<NonTypeTemplateParmDecl>());
- E->ParamAndRef.setInt(Record.readInt());
+ E->AssociatedDeclAndRef.setPointer(readDeclAs<Decl>());
+ E->AssociatedDeclAndRef.setInt(Record.readInt());
+ E->Index = Record.readInt();
+ E->PackIndex = Record.readInt();
E->SubstNonTypeTemplateParmExprBits.NameLoc = readSourceLocation();
E->Replacement = Record.readSubExpr();
}
@@ -2126,7 +2140,8 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E) {
VisitExpr(E);
- E->Param = readDeclAs<NonTypeTemplateParmDecl>();
+ E->AssociatedDecl = readDeclAs<Decl>();
+ E->Index = Record.readInt();
TemplateArgument ArgPack = Record.readTemplateArgument();
if (ArgPack.getKind() != TemplateArgument::Pack)
return;
@@ -2167,6 +2182,31 @@ void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) {
E->Opcode = (BinaryOperatorKind)Record.readInt();
}
+void ASTStmtReader::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
+ VisitExpr(E);
+ unsigned ExpectedNumExprs = Record.readInt();
+ assert(E->NumExprs == ExpectedNumExprs &&
+ "expected number of expressions does not equal the actual number of "
+ "serialized expressions.");
+ E->NumUserSpecifiedExprs = Record.readInt();
+ E->InitLoc = readSourceLocation();
+ E->LParenLoc = readSourceLocation();
+ E->RParenLoc = readSourceLocation();
+ for (unsigned I = 0; I < ExpectedNumExprs; I++)
+ E->getTrailingObjects<Expr *>()[I] = Record.readSubExpr();
+
+ bool HasArrayFillerOrUnionDecl = Record.readBool();
+ if (HasArrayFillerOrUnionDecl) {
+ bool HasArrayFiller = Record.readBool();
+ if (HasArrayFiller) {
+ E->setArrayFiller(Record.readSubExpr());
+ } else {
+ E->setInitializedFieldInUnion(readDeclAs<FieldDecl>());
+ }
+ }
+ E->updateDependence();
+}
+
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
E->SourceExpr = Record.readSubExpr();
@@ -2412,6 +2452,13 @@ void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
VisitOMPExecutableDirective(D);
}
+void ASTStmtReader::VisitOMPErrorDirective(OMPErrorDirective *D) {
+ VisitStmt(D);
+ // The NumClauses field was read in ReadStmtFromStream.
+ Record.skipInts(1);
+ VisitOMPExecutableDirective(D);
+}
+
void ASTStmtReader::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) {
VisitStmt(D);
VisitOMPExecutableDirective(D);
@@ -3359,6 +3406,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Context, Record[ASTStmtReader::NumStmtFields], Empty);
break;
+ case STMT_OMP_ERROR_DIRECTIVE:
+ S = OMPErrorDirective::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields], Empty);
+ break;
+
case STMT_OMP_TASKGROUP_DIRECTIVE:
S = OMPTaskgroupDirective::CreateEmpty(
Context, Record[ASTStmtReader::NumStmtFields], Empty);
@@ -3817,11 +3869,13 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_CXX_DEFAULT_ARG:
- S = new (Context) CXXDefaultArgExpr(Empty);
+ S = CXXDefaultArgExpr::CreateEmpty(
+ Context, /*HasRewrittenInit=*/Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_DEFAULT_INIT:
- S = new (Context) CXXDefaultInitExpr(Empty);
+ S = CXXDefaultInitExpr::CreateEmpty(
+ Context, /*HasRewrittenInit=*/Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_BIND_TEMPORARY:
@@ -3946,6 +4000,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) CXXFoldExpr(Empty);
break;
+ case EXPR_CXX_PAREN_LIST_INIT:
+ S = CXXParenListInitExpr::CreateEmpty(
+ Context, /*numExprs=*/Record[ASTStmtReader::NumExprFields], Empty);
+ break;
+
case EXPR_OPAQUE_VALUE:
S = new (Context) OpaqueValueExpr(Empty);
break;
@@ -3999,8 +4058,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_CONCEPT_SPECIALIZATION: {
- unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields];
- S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs);
+ S = new (Context) ConceptSpecializationExpr(Empty);
break;
}
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 0739dcc1ce60..bdf11001473e 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -77,7 +77,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Hashing.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
@@ -100,6 +99,7 @@
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SHA1.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/VersionTuple.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -108,9 +108,9 @@
#include <cstdlib>
#include <cstring>
#include <ctime>
-#include <deque>
#include <limits>
#include <memory>
+#include <optional>
#include <queue>
#include <tuple>
#include <utility>
@@ -161,12 +161,14 @@ static TypeCode getTypeCodeForTypeClass(Type::TypeClass id) {
namespace {
-std::set<const FileEntry *> GetAllModuleMaps(const HeaderSearch &HS,
- Module *RootModule) {
+std::set<const FileEntry *> GetAffectingModuleMaps(const Preprocessor &PP,
+ Module *RootModule) {
std::set<const FileEntry *> ModuleMaps{};
std::set<const Module *> ProcessedModules;
SmallVector<const Module *> ModulesToProcess{RootModule};
+ const HeaderSearch &HS = PP.getHeaderSearchInfo();
+
SmallVector<const FileEntry *, 16> FilesByUID;
HS.getFileMgr().GetUniqueIDMapping(FilesByUID);
@@ -190,30 +192,36 @@ std::set<const FileEntry *> GetAllModuleMaps(const HeaderSearch &HS,
}
}
- while (!ModulesToProcess.empty()) {
- auto *CurrentModule = ModulesToProcess.pop_back_val();
- ProcessedModules.insert(CurrentModule);
+ const ModuleMap &MM = HS.getModuleMap();
+ SourceManager &SourceMgr = PP.getSourceManager();
- auto *ModuleMapFile =
- HS.getModuleMap().getModuleMapFileForUniquing(CurrentModule);
- if (!ModuleMapFile) {
- continue;
+ auto ForIncludeChain = [&](FileEntryRef F,
+ llvm::function_ref<void(FileEntryRef)> CB) {
+ CB(F);
+ FileID FID = SourceMgr.translateFile(F);
+ SourceLocation Loc = SourceMgr.getIncludeLoc(FID);
+ while (Loc.isValid()) {
+ FID = SourceMgr.getFileID(Loc);
+ CB(*SourceMgr.getFileEntryRefForID(FID));
+ Loc = SourceMgr.getIncludeLoc(FID);
}
+ };
- ModuleMaps.insert(ModuleMapFile);
-
- for (auto *ImportedModule : (CurrentModule)->Imports) {
- if (!ImportedModule ||
- ProcessedModules.find(ImportedModule) != ProcessedModules.end()) {
- continue;
- }
- ModulesToProcess.push_back(ImportedModule);
- }
+ auto ProcessModuleOnce = [&](const Module *M) {
+ for (const Module *Mod = M; Mod; Mod = Mod->Parent)
+ if (ProcessedModules.insert(Mod).second)
+ if (auto ModuleMapFile = MM.getModuleMapFileForUniquing(Mod))
+ ForIncludeChain(*ModuleMapFile, [&](FileEntryRef F) {
+ ModuleMaps.insert(F);
+ });
+ };
+ for (const Module *CurrentModule : ModulesToProcess) {
+ ProcessModuleOnce(CurrentModule);
+ for (const Module *ImportedModule : CurrentModule->Imports)
+ ProcessModuleOnce(ImportedModule);
for (const Module *UndeclaredModule : CurrentModule->UndeclaredUses)
- if (UndeclaredModule &&
- ProcessedModules.find(UndeclaredModule) == ProcessedModules.end())
- ModulesToProcess.push_back(UndeclaredModule);
+ ProcessModuleOnce(UndeclaredModule);
}
return ModuleMaps;
@@ -437,7 +445,7 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
addSourceLocation(TL.getTypeofLoc());
addSourceLocation(TL.getLParenLoc());
addSourceLocation(TL.getRParenLoc());
- Record.AddTypeSourceInfo(TL.getUnderlyingTInfo());
+ Record.AddTypeSourceInfo(TL.getUnmodifiedTInfo());
}
void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
@@ -463,8 +471,9 @@ void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
addSourceLocation(TL.getLAngleLoc());
addSourceLocation(TL.getRAngleLoc());
for (unsigned I = 0; I < TL.getNumArgs(); ++I)
- Record.AddTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(),
- TL.getArgLocInfo(I));
+ Record.AddTemplateArgumentLocInfo(
+ TL.getTypePtr()->getTypeConstraintArguments()[I].getKind(),
+ TL.getArgLocInfo(I));
}
Record.push_back(TL.isDecltypeAuto());
if (TL.isDecltypeAuto())
@@ -560,6 +569,7 @@ void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) {
void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
addSourceLocation(TL.getNameLoc());
+ addSourceLocation(TL.getNameEndLoc());
}
void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
@@ -734,6 +744,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_USER_DEFINED_LITERAL);
RECORD(EXPR_CXX_STD_INITIALIZER_LIST);
RECORD(EXPR_CXX_BOOL_LITERAL);
+ RECORD(EXPR_CXX_PAREN_LIST_INIT);
RECORD(EXPR_CXX_NULL_PTR_LITERAL);
RECORD(EXPR_CXX_TYPEID_EXPR);
RECORD(EXPR_CXX_TYPEID_TYPE);
@@ -786,7 +797,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(MODULE_MAP_FILE);
RECORD(IMPORTS);
RECORD(ORIGINAL_FILE);
- RECORD(ORIGINAL_PCH_DIR);
RECORD(ORIGINAL_FILE_ID);
RECORD(INPUT_FILE_OFFSETS);
@@ -884,6 +894,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(SUBMODULE_TOPHEADER);
RECORD(SUBMODULE_UMBRELLA_DIR);
RECORD(SUBMODULE_IMPORTS);
+ RECORD(SUBMODULE_AFFECTING_MODULES);
RECORD(SUBMODULE_EXPORTS);
RECORD(SUBMODULE_REQUIRES);
RECORD(SUBMODULE_EXCLUDED_HEADER);
@@ -1017,6 +1028,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_PRAGMA_DETECT_MISMATCH);
RECORD(DECL_OMP_DECLARE_REDUCTION);
RECORD(DECL_OMP_ALLOCATE);
+ RECORD(DECL_HLSL_BUFFER);
// Statements and Exprs can occur in the Decls and Types block.
AddStmtsExprs(Stream, Record);
@@ -1034,6 +1046,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(SIGNATURE);
RECORD(AST_BLOCK_HASH);
RECORD(DIAGNOSTIC_OPTIONS);
+ RECORD(HEADER_SEARCH_PATHS);
RECORD(DIAG_PRAGMA_MAPPINGS);
#undef RECORD
@@ -1164,6 +1177,35 @@ ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP,
Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record);
Record.clear();
+ // Header search paths.
+ Record.clear();
+ const HeaderSearchOptions &HSOpts =
+ PP.getHeaderSearchInfo().getHeaderSearchOpts();
+
+ // Include entries.
+ Record.push_back(HSOpts.UserEntries.size());
+ for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) {
+ const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
+ AddString(Entry.Path, Record);
+ Record.push_back(static_cast<unsigned>(Entry.Group));
+ Record.push_back(Entry.IsFramework);
+ Record.push_back(Entry.IgnoreSysRoot);
+ }
+
+ // System header prefixes.
+ Record.push_back(HSOpts.SystemHeaderPrefixes.size());
+ for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) {
+ AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record);
+ Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader);
+ }
+
+ // VFS overlay files.
+ Record.push_back(HSOpts.VFSOverlayFiles.size());
+ for (StringRef VFSOverlayFile : HSOpts.VFSOverlayFiles)
+ AddString(VFSOverlayFile, Record);
+
+ Stream.EmitRecord(HEADER_SEARCH_PATHS, Record);
+
// Write out the diagnostic/pragma mappings.
WritePragmaDiagnosticMappings(Diags, /* isModule = */ WritingModule);
@@ -1187,8 +1229,7 @@ ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP,
/// Write the control block.
void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
- StringRef isysroot,
- const std::string &OutputFile) {
+ StringRef isysroot) {
using namespace llvm;
Stream.EnterSubblock(CONTROL_BLOCK_ID, 5);
@@ -1283,7 +1324,12 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
if (auto *AdditionalModMaps =
Map.getAdditionalModuleMapFiles(WritingModule)) {
Record.push_back(AdditionalModMaps->size());
- for (const FileEntry *F : *AdditionalModMaps)
+ SmallVector<const FileEntry *, 1> ModMaps(AdditionalModMaps->begin(),
+ AdditionalModMaps->end());
+ llvm::sort(ModMaps, [](const FileEntry *A, const FileEntry *B) {
+ return A->getName() < B->getName();
+ });
+ for (const FileEntry *F : ModMaps)
AddPath(F->getName(), Record);
} else {
Record.push_back(0);
@@ -1385,27 +1431,10 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
// Header search options.
Record.clear();
- const HeaderSearchOptions &HSOpts
- = PP.getHeaderSearchInfo().getHeaderSearchOpts();
- AddString(HSOpts.Sysroot, Record);
-
- // Include entries.
- Record.push_back(HSOpts.UserEntries.size());
- for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) {
- const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
- AddString(Entry.Path, Record);
- Record.push_back(static_cast<unsigned>(Entry.Group));
- Record.push_back(Entry.IsFramework);
- Record.push_back(Entry.IgnoreSysRoot);
- }
-
- // System header prefixes.
- Record.push_back(HSOpts.SystemHeaderPrefixes.size());
- for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) {
- AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record);
- Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader);
- }
+ const HeaderSearchOptions &HSOpts =
+ PP.getHeaderSearchInfo().getHeaderSearchOpts();
+ AddString(HSOpts.Sysroot, Record);
AddString(HSOpts.ResourceDir, Record);
AddString(HSOpts.ModuleCachePath, Record);
AddString(HSOpts.ModuleUserBuildPath, Record);
@@ -1463,38 +1492,16 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Record.clear();
Record.push_back(ORIGINAL_FILE);
- Record.push_back(SM.getMainFileID().getOpaqueValue());
+ AddFileID(SM.getMainFileID(), Record);
EmitRecordWithPath(FileAbbrevCode, Record, MainFile->getName());
}
Record.clear();
- Record.push_back(SM.getMainFileID().getOpaqueValue());
+ AddFileID(SM.getMainFileID(), Record);
Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
- // Original PCH directory
- if (!OutputFile.empty() && OutputFile != "-") {
- auto Abbrev = std::make_shared<BitCodeAbbrev>();
- Abbrev->Add(BitCodeAbbrevOp(ORIGINAL_PCH_DIR));
- Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
- unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
-
- SmallString<128> OutputPath(OutputFile);
- PreparePathForOutput(OutputPath);
- StringRef origDir = llvm::sys::path::parent_path(OutputPath);
-
- RecordData::value_type Record[] = {ORIGINAL_PCH_DIR};
- Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
- }
-
- std::set<const FileEntry *> AffectingModuleMaps;
- if (WritingModule) {
- AffectingModuleMaps =
- GetAllModuleMaps(PP.getHeaderSearchInfo(), WritingModule);
- }
-
WriteInputFiles(Context.SourceMgr,
- PP.getHeaderSearchInfo().getHeaderSearchOpts(),
- AffectingModuleMaps);
+ PP.getHeaderSearchInfo().getHeaderSearchOpts());
Stream.ExitBlock();
}
@@ -1502,19 +1509,20 @@ namespace {
/// An input file.
struct InputFileEntry {
- const FileEntry *File;
+ FileEntryRef File;
bool IsSystemFile;
bool IsTransient;
bool BufferOverridden;
bool IsTopLevelModuleMap;
uint32_t ContentHash[2];
+
+ InputFileEntry(FileEntryRef File) : File(File) {}
};
} // namespace
-void ASTWriter::WriteInputFiles(
- SourceManager &SourceMgr, HeaderSearchOptions &HSOpts,
- std::set<const FileEntry *> &AffectingModuleMaps) {
+void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
+ HeaderSearchOptions &HSOpts) {
using namespace llvm;
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
@@ -1538,9 +1546,9 @@ void ASTWriter::WriteInputFiles(
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;
+ // Get all ContentCache objects for files.
+ std::vector<InputFileEntry> UserFiles;
+ std::vector<InputFileEntry> SystemFiles;
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
// Get this source location entry.
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
@@ -1554,18 +1562,11 @@ void ASTWriter::WriteInputFiles(
if (!Cache->OrigEntry)
continue;
- if (isModuleMap(File.getFileCharacteristic()) &&
- !isSystem(File.getFileCharacteristic()) &&
- !AffectingModuleMaps.empty() &&
- AffectingModuleMaps.find(Cache->OrigEntry) ==
- AffectingModuleMaps.end()) {
- SkippedModuleMaps.insert(Cache->OrigEntry);
- // Do not emit modulemaps that do not affect current module.
+ // Do not emit input files that do not affect current module.
+ if (!IsSLocAffecting[I])
continue;
- }
- InputFileEntry Entry;
- Entry.File = Cache->OrigEntry;
+ InputFileEntry Entry(*Cache->OrigEntry);
Entry.IsSystemFile = isSystem(File.getFileCharacteristic());
Entry.IsTransient = Cache->IsTransient;
Entry.BufferOverridden = Cache->BufferOverridden;
@@ -1580,9 +1581,8 @@ void ASTWriter::WriteInputFiles(
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();
+ << Entry.File.getName();
}
auto CH = llvm::APInt(64, ContentHash);
Entry.ContentHash[0] =
@@ -1591,11 +1591,15 @@ void ASTWriter::WriteInputFiles(
static_cast<uint32_t>(CH.getHiBits(32).getZExtValue());
if (Entry.IsSystemFile)
- SortedFiles.push_back(Entry);
+ SystemFiles.push_back(Entry);
else
- SortedFiles.push_front(Entry);
+ UserFiles.push_back(Entry);
}
+ // User files go at the front, system files at the back.
+ auto SortedFiles = llvm::concat<InputFileEntry>(std::move(UserFiles),
+ std::move(SystemFiles));
+
unsigned UserFilesNum = 0;
// Write out all of the input files.
std::vector<uint64_t> InputFileOffsets;
@@ -1618,14 +1622,13 @@ void ASTWriter::WriteInputFiles(
RecordData::value_type Record[] = {
INPUT_FILE,
InputFileOffsets.size(),
- (uint64_t)Entry.File->getSize(),
+ (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.getNameAsRequested());
}
// Emit content hash for this file.
@@ -1830,14 +1833,12 @@ namespace {
auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) {
if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) {
- uint32_t Value = (ModID << 2) | (unsigned)Role;
- assert((Value >> 2) == ModID && "overflow in header module info");
+ uint32_t Value = (ModID << 3) | (unsigned)Role;
+ assert((Value >> 3) == ModID && "overflow in header module info");
LE.write<uint32_t>(Value);
}
};
- // FIXME: If the header is excluded, we should write out some
- // record of that fact.
for (auto ModInfo : Data.KnownHeaders)
EmitModule(ModInfo.getModule(), ModInfo.getRole());
if (Data.Unresolved.getPointer())
@@ -1879,7 +1880,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
// headers list when emitting resolved headers in the first loop below.
// FIXME: It'd be preferable to avoid doing this if we were given
// sufficient stat information in the module map.
- HS.getModuleMap().resolveHeaderDirectives(M, /*File=*/llvm::None);
+ HS.getModuleMap().resolveHeaderDirectives(M, /*File=*/std::nullopt);
// If the file didn't exist, we can still create a module if we were given
// enough information in the module map.
@@ -2001,6 +2002,14 @@ static void emitBlob(llvm::BitstreamWriter &Stream, StringRef Blob,
// Compress the buffer if possible. We expect that almost all PCM
// consumers will not want its contents.
SmallVector<uint8_t, 0> CompressedBuffer;
+ if (llvm::compression::zstd::isAvailable()) {
+ llvm::compression::zstd::compress(
+ llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer, 9);
+ RecordDataType Record[] = {SM_SLOC_BUFFER_BLOB_COMPRESSED, Blob.size() - 1};
+ Stream.EmitRecordWithBlob(SLocBufferBlobCompressedAbbrv, Record,
+ llvm::toStringRef(CompressedBuffer));
+ return;
+ }
if (llvm::compression::zlib::isAvailable()) {
llvm::compression::zlib::compress(
llvm::arrayRefFromStringRef(Blob.drop_back(1)), CompressedBuffer);
@@ -2054,7 +2063,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Record the offset of this source-location entry.
uint64_t Offset = Stream.GetCurrentBitNo() - SLocEntryOffsetsBase;
assert((Offset >> 32) == 0 && "SLocEntry offset too large");
- SLocEntryOffsets.push_back(Offset);
// Figure out which record code to use.
unsigned Code;
@@ -2069,17 +2077,15 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
Record.clear();
Record.push_back(Code);
- // Starting offset of this entry within this module, so skip the dummy.
- Record.push_back(SLoc->getOffset() - 2);
if (SLoc->isFile()) {
const SrcMgr::FileInfo &File = SLoc->getFile();
const SrcMgr::ContentCache *Content = &File.getContentCache();
- if (Content->OrigEntry && !SkippedModuleMaps.empty() &&
- SkippedModuleMaps.find(Content->OrigEntry) !=
- SkippedModuleMaps.end()) {
- // Do not emit files that were not listed as inputs.
+ // Do not emit files that were not listed as inputs.
+ if (!IsSLocAffecting[I])
continue;
- }
+ SLocEntryOffsets.push_back(Offset);
+ // Starting offset of this entry within this module, so skip the dummy.
+ Record.push_back(getAdjustedOffset(SLoc->getOffset()) - 2);
AddSourceLocation(File.getIncludeLoc(), Record);
Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding
Record.push_back(File.hasLineDirectives());
@@ -2093,7 +2099,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
assert(InputFileIDs[Content->OrigEntry] != 0 && "Missed file entry");
Record.push_back(InputFileIDs[Content->OrigEntry]);
- Record.push_back(File.NumCreatedFIDs);
+ Record.push_back(getAdjustedNumCreatedFIDs(FID));
FileDeclIDsTy::iterator FDI = FileDeclIDs.find(FID);
if (FDI != FileDeclIDs.end()) {
@@ -2115,7 +2121,7 @@ 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).
- llvm::Optional<llvm::MemoryBufferRef> Buffer =
+ std::optional<llvm::MemoryBufferRef> Buffer =
Content->getBufferOrNone(PP.getDiagnostics(), PP.getFileManager());
StringRef Name = Buffer ? Buffer->getBufferIdentifier() : "";
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
@@ -2129,7 +2135,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
if (EmitBlob) {
// Include the implicit terminating null character in the on-disk buffer
// if we're writing it uncompressed.
- llvm::Optional<llvm::MemoryBufferRef> Buffer =
+ std::optional<llvm::MemoryBufferRef> Buffer =
Content->getBufferOrNone(PP.getDiagnostics(), PP.getFileManager());
if (!Buffer)
Buffer = llvm::MemoryBufferRef("<<<INVALID BUFFER>>>", "");
@@ -2140,6 +2146,9 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
} else {
// The source location entry is a macro expansion.
const SrcMgr::ExpansionInfo &Expansion = SLoc->getExpansion();
+ SLocEntryOffsets.push_back(Offset);
+ // Starting offset of this entry within this module, so skip the dummy.
+ Record.push_back(getAdjustedOffset(SLoc->getOffset()) - 2);
LocSeq::State Seq;
AddSourceLocation(Expansion.getSpellingLoc(), Record, Seq);
AddSourceLocation(Expansion.getExpansionLocStart(), Record, Seq);
@@ -2153,7 +2162,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
SourceLocation::UIntTy NextOffset = SourceMgr.getNextLocalOffset();
if (I + 1 != N)
NextOffset = SourceMgr.getLocalSLocEntry(I + 1).getOffset();
- Record.push_back(NextOffset - SLoc->getOffset() - 1);
+ Record.push_back(getAdjustedOffset(NextOffset - SLoc->getOffset()) - 1);
Stream.EmitRecordWithAbbrev(SLocExpansionAbbrv, Record);
}
}
@@ -2177,7 +2186,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
{
RecordData::value_type Record[] = {
SOURCE_LOCATION_OFFSETS, SLocEntryOffsets.size(),
- SourceMgr.getNextLocalOffset() - 1 /* skip dummy */,
+ getAdjustedOffset(SourceMgr.getNextLocalOffset()) - 1 /* skip dummy */,
SLocEntryOffsetsBase - SourceManagerBlockOffset};
Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record,
bytes(SLocEntryOffsets));
@@ -2213,8 +2222,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
if (L.first.ID < 0)
continue;
- // Emit the file ID
- Record.push_back(L.first.ID);
+ AddFileID(L.first, Record);
// Emit the line entries
Record.push_back(L.second.size());
@@ -2341,11 +2349,14 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
// Construct the list of identifiers with macro directives that need to be
// serialized.
SmallVector<const IdentifierInfo *, 128> MacroIdentifiers;
- for (auto &Id : PP.getIdentifierTable())
- if (Id.second->hadMacroDefinition() &&
- (!Id.second->isFromAST() ||
- Id.second->hasChangedSinceDeserialization()))
- MacroIdentifiers.push_back(Id.second);
+ // It is meaningless to emit macros for named modules. It only wastes times
+ // and spaces.
+ if (!isWritingStdCXXNamedModules())
+ for (auto &Id : PP.getIdentifierTable())
+ if (Id.second->hadMacroDefinition() &&
+ (!Id.second->isFromAST() ||
+ Id.second->hasChangedSinceDeserialization()))
+ 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::deref<std::less<>>());
@@ -2577,7 +2588,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec,
uint64_t Offset = Stream.GetCurrentBitNo() - MacroOffsetsBase;
assert((Offset >> 32) == 0 && "Preprocessed entity offset too large");
PreprocessedEntityOffsets.push_back(
- PPEntityOffset((*E)->getSourceRange(), Offset));
+ PPEntityOffset(getAdjustedRange((*E)->getSourceRange()), Offset));
if (auto *MD = dyn_cast<MacroDefinitionRecord>(*E)) {
// Record this macro definition's ID.
@@ -2677,12 +2688,12 @@ unsigned ASTWriter::getLocalOrImportedSubmoduleID(const Module *Mod) {
}
unsigned ASTWriter::getSubmoduleID(Module *Mod) {
+ unsigned ID = getLocalOrImportedSubmoduleID(Mod);
// FIXME: This can easily happen, if we have a reference to a submodule that
// did not result in us loading a module file for that submodule. For
// instance, a cross-top-level-module 'conflict' declaration will hit this.
- unsigned ID = getLocalOrImportedSubmoduleID(Mod);
- assert((ID || !Mod) &&
- "asked for module ID for non-local, non-imported module");
+ // assert((ID || !Mod) &&
+ // "asked for module ID for non-local, non-imported module");
return ID;
}
@@ -2882,6 +2893,14 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
}
+ // Emit the modules affecting compilation that were not imported.
+ if (!Mod->AffectingClangModules.empty()) {
+ RecordData Record;
+ for (auto *I : Mod->AffectingClangModules)
+ Record.push_back(getSubmoduleID(I));
+ Stream.EmitRecord(SUBMODULE_AFFECTING_MODULES, Record);
+ }
+
// Emit the exports.
if (!Mod->Exports.empty()) {
RecordData Record;
@@ -3016,7 +3035,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
Record.push_back(FileIDAndFile.second.StateTransitions.size());
for (auto &StatePoint : FileIDAndFile.second.StateTransitions) {
- Record.push_back(StatePoint.Offset);
+ Record.push_back(getAdjustedOffset(StatePoint.Offset));
AddDiagState(StatePoint.State, false);
}
}
@@ -4350,7 +4369,8 @@ void ASTRecordWriter::AddAttr(const Attr *A) {
// FIXME: Clang can't handle the serialization/deserialization of
// preferred_name properly now. See
// https://github.com/llvm/llvm-project/issues/56490 for example.
- if (!A || (isa<PreferredNameAttr>(A) && Writer->isWritingNamedModules()))
+ if (!A || (isa<PreferredNameAttr>(A) &&
+ Writer->isWritingStdCXXNamedModules()))
return Record.push_back(0);
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
@@ -4375,15 +4395,37 @@ void ASTRecordWriter::AddAttributes(ArrayRef<const Attr *> Attrs) {
void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) {
AddSourceLocation(Tok.getLocation(), Record);
- Record.push_back(Tok.getLength());
-
- // FIXME: When reading literal tokens, reconstruct the literal pointer
- // if it is needed.
- AddIdentifierRef(Tok.getIdentifierInfo(), Record);
// FIXME: Should translate token kind to a stable encoding.
Record.push_back(Tok.getKind());
// FIXME: Should translate token flags to a stable encoding.
Record.push_back(Tok.getFlags());
+
+ if (Tok.isAnnotation()) {
+ AddSourceLocation(Tok.getAnnotationEndLoc(), Record);
+ switch (Tok.getKind()) {
+ case tok::annot_pragma_loop_hint: {
+ auto *Info = static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
+ AddToken(Info->PragmaName, Record);
+ AddToken(Info->Option, Record);
+ Record.push_back(Info->Toks.size());
+ for (const auto &T : Info->Toks)
+ AddToken(T, Record);
+ break;
+ }
+ // Some annotation tokens do not use the PtrData field.
+ case tok::annot_pragma_openmp:
+ case tok::annot_pragma_openmp_end:
+ case tok::annot_pragma_unused:
+ break;
+ default:
+ llvm_unreachable("missing serialization code for annotation token");
+ }
+ } else {
+ Record.push_back(Tok.getLength());
+ // FIXME: When reading literal tokens, reconstruct the literal pointer if it
+ // is needed.
+ AddIdentifierRef(Tok.getIdentifierInfo(), Record);
+ }
}
void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
@@ -4425,11 +4467,11 @@ void ASTWriter::EmitRecordWithPath(unsigned Abbrev, RecordDataRef Record,
void ASTWriter::AddVersionTuple(const VersionTuple &Version,
RecordDataImpl &Record) {
Record.push_back(Version.getMajor());
- if (Optional<unsigned> Minor = Version.getMinor())
+ if (std::optional<unsigned> Minor = Version.getMinor())
Record.push_back(*Minor + 1);
else
Record.push_back(0);
- if (Optional<unsigned> Subminor = Version.getSubminor())
+ if (std::optional<unsigned> Subminor = Version.getSubminor())
Record.push_back(*Subminor + 1);
else
Record.push_back(0);
@@ -4481,11 +4523,11 @@ time_t ASTWriter::getTimestampForOutput(const FileEntry *E) const {
return IncludeTimestamps ? E->getModificationTime() : 0;
}
-ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef,
- const std::string &OutputFile,
+ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef, StringRef OutputFile,
Module *WritingModule, StringRef isysroot,
bool hasErrors,
bool ShouldCacheASTInMemory) {
+ llvm::TimeTraceScope scope("WriteAST", OutputFile);
WritingAST = true;
ASTHasCompilerErrors = hasErrors;
@@ -4501,8 +4543,7 @@ ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef,
Context = &SemaRef.Context;
PP = &SemaRef.PP;
this->WritingModule = WritingModule;
- ASTFileSignature Signature =
- WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule);
+ ASTFileSignature Signature = WriteASTCore(SemaRef, isysroot, WritingModule);
Context = nullptr;
PP = nullptr;
this->WritingModule = nullptr;
@@ -4527,8 +4568,69 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
}
}
+void ASTWriter::collectNonAffectingInputFiles() {
+ SourceManager &SrcMgr = PP->getSourceManager();
+ unsigned N = SrcMgr.local_sloc_entry_size();
+
+ IsSLocAffecting.resize(N, true);
+
+ if (!WritingModule)
+ return;
+
+ auto AffectingModuleMaps = GetAffectingModuleMaps(*PP, WritingModule);
+
+ unsigned FileIDAdjustment = 0;
+ unsigned OffsetAdjustment = 0;
+
+ NonAffectingFileIDAdjustments.reserve(N);
+ NonAffectingOffsetAdjustments.reserve(N);
+
+ NonAffectingFileIDAdjustments.push_back(FileIDAdjustment);
+ NonAffectingOffsetAdjustments.push_back(OffsetAdjustment);
+
+ for (unsigned I = 1; I != N; ++I) {
+ const SrcMgr::SLocEntry *SLoc = &SrcMgr.getLocalSLocEntry(I);
+ FileID FID = FileID::get(I);
+ assert(&SrcMgr.getSLocEntry(FID) == SLoc);
+
+ if (!SLoc->isFile())
+ continue;
+ const SrcMgr::FileInfo &File = SLoc->getFile();
+ const SrcMgr::ContentCache *Cache = &File.getContentCache();
+ if (!Cache->OrigEntry)
+ continue;
+
+ if (!isModuleMap(File.getFileCharacteristic()) ||
+ AffectingModuleMaps.empty() ||
+ AffectingModuleMaps.find(Cache->OrigEntry) != AffectingModuleMaps.end())
+ continue;
+
+ IsSLocAffecting[I] = false;
+
+ FileIDAdjustment += 1;
+ // Even empty files take up one element in the offset table.
+ OffsetAdjustment += SrcMgr.getFileIDSize(FID) + 1;
+
+ // If the previous file was non-affecting as well, just extend its entry
+ // with our information.
+ if (!NonAffectingFileIDs.empty() &&
+ NonAffectingFileIDs.back().ID == FID.ID - 1) {
+ NonAffectingFileIDs.back() = FID;
+ NonAffectingRanges.back().setEnd(SrcMgr.getLocForEndOfFile(FID));
+ NonAffectingFileIDAdjustments.back() = FileIDAdjustment;
+ NonAffectingOffsetAdjustments.back() = OffsetAdjustment;
+ continue;
+ }
+
+ NonAffectingFileIDs.push_back(FID);
+ NonAffectingRanges.emplace_back(SrcMgr.getLocForStartOfFile(FID),
+ SrcMgr.getLocForEndOfFile(FID));
+ NonAffectingFileIDAdjustments.push_back(FileIDAdjustment);
+ NonAffectingOffsetAdjustments.push_back(OffsetAdjustment);
+ }
+}
+
ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
- const std::string &OutputFile,
Module *WritingModule) {
using namespace llvm;
@@ -4541,6 +4643,8 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
ASTContext &Context = SemaRef.Context;
Preprocessor &PP = SemaRef.PP;
+ collectNonAffectingInputFiles();
+
// Set up predefined declaration IDs.
auto RegisterPredefDecl = [&] (Decl *D, PredefinedDeclIDs ID) {
if (D) {
@@ -4682,7 +4786,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
}
// Write the control block
- WriteControlBlock(PP, Context, isysroot, OutputFile);
+ WriteControlBlock(PP, Context, isysroot);
// Write the remaining AST contents.
Stream.FlushToWord();
@@ -5205,7 +5309,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
break;
case UPD_ADDED_ATTR_TO_RECORD:
- Record.AddAttributes(llvm::makeArrayRef(Update.getAttr()));
+ Record.AddAttributes(llvm::ArrayRef(Update.getAttr()));
break;
}
}
@@ -5229,8 +5333,75 @@ void ASTWriter::AddAlignPackInfo(const Sema::AlignPackInfo &Info,
Record.push_back(Raw);
}
+FileID ASTWriter::getAdjustedFileID(FileID FID) const {
+ if (FID.isInvalid() || PP->getSourceManager().isLoadedFileID(FID) ||
+ NonAffectingFileIDs.empty())
+ return FID;
+ auto It = llvm::lower_bound(NonAffectingFileIDs, FID);
+ unsigned Idx = std::distance(NonAffectingFileIDs.begin(), It);
+ unsigned Offset = NonAffectingFileIDAdjustments[Idx];
+ return FileID::get(FID.getOpaqueValue() - Offset);
+}
+
+unsigned ASTWriter::getAdjustedNumCreatedFIDs(FileID FID) const {
+ unsigned NumCreatedFIDs = PP->getSourceManager()
+ .getLocalSLocEntry(FID.ID)
+ .getFile()
+ .NumCreatedFIDs;
+
+ unsigned AdjustedNumCreatedFIDs = 0;
+ for (unsigned I = FID.ID, N = I + NumCreatedFIDs; I != N; ++I)
+ if (IsSLocAffecting[I])
+ ++AdjustedNumCreatedFIDs;
+ return AdjustedNumCreatedFIDs;
+}
+
+SourceLocation ASTWriter::getAdjustedLocation(SourceLocation Loc) const {
+ if (Loc.isInvalid())
+ return Loc;
+ return Loc.getLocWithOffset(-getAdjustment(Loc.getOffset()));
+}
+
+SourceRange ASTWriter::getAdjustedRange(SourceRange Range) const {
+ return SourceRange(getAdjustedLocation(Range.getBegin()),
+ getAdjustedLocation(Range.getEnd()));
+}
+
+SourceLocation::UIntTy
+ASTWriter::getAdjustedOffset(SourceLocation::UIntTy Offset) const {
+ return Offset - getAdjustment(Offset);
+}
+
+SourceLocation::UIntTy
+ASTWriter::getAdjustment(SourceLocation::UIntTy Offset) const {
+ if (NonAffectingRanges.empty())
+ return 0;
+
+ if (PP->getSourceManager().isLoadedOffset(Offset))
+ return 0;
+
+ if (Offset > NonAffectingRanges.back().getEnd().getOffset())
+ return NonAffectingOffsetAdjustments.back();
+
+ if (Offset < NonAffectingRanges.front().getBegin().getOffset())
+ return 0;
+
+ auto Contains = [](const SourceRange &Range, SourceLocation::UIntTy Offset) {
+ return Range.getEnd().getOffset() < Offset;
+ };
+
+ auto It = llvm::lower_bound(NonAffectingRanges, Offset, Contains);
+ unsigned Idx = std::distance(NonAffectingRanges.begin(), It);
+ return NonAffectingOffsetAdjustments[Idx];
+}
+
+void ASTWriter::AddFileID(FileID FID, RecordDataImpl &Record) {
+ Record.push_back(getAdjustedFileID(FID).getOpaqueValue());
+}
+
void ASTWriter::AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record,
SourceLocationSequence *Seq) {
+ Loc = getAdjustedLocation(Loc);
Record.push_back(SourceLocationEncoding::encode(Loc, Seq));
}
@@ -5472,7 +5643,7 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
// a function/objc method, should not have TU as lexical context.
// TemplateTemplateParmDecls that are part of an alias template, should not
// have TU as lexical context.
- if (isa<ParmVarDecl>(D) || isa<TemplateTemplateParmDecl>(D))
+ if (isa<ParmVarDecl, TemplateTemplateParmDecl>(D))
return;
SourceManager &SM = Context->getSourceManager();
@@ -5484,6 +5655,7 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) {
if (FID.isInvalid())
return;
assert(SM.getSLocEntry(FID).isFile());
+ assert(IsSLocAffecting[FID.ID]);
std::unique_ptr<DeclIDInFileInfo> &Info = FileDeclIDs[FID];
if (!Info)
@@ -5775,7 +5947,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
AddDeclRef(D->getLambdaContextDecl());
AddTypeSourceInfo(Lambda.MethodTyInfo);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
- const LambdaCapture &Capture = Lambda.Captures[I];
+ const LambdaCapture &Capture = Lambda.Captures.front()[I];
AddSourceLocation(Capture.getLocation());
Record->push_back(Capture.isImplicit());
Record->push_back(Capture.getCaptureKind());
@@ -5786,7 +5958,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
break;
case LCK_ByCopy:
case LCK_ByRef:
- VarDecl *Var =
+ ValueDecl *Var =
Capture.capturesVariable() ? Capture.getCapturedVar() : nullptr;
AddDeclRef(Var);
AddSourceLocation(Capture.isPackExpansion() ? Capture.getEllipsisLoc()
@@ -6618,9 +6790,12 @@ void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) {
Record.push_back(C->getTotalComponentListNum());
Record.push_back(C->getTotalComponentsNum());
Record.AddSourceLocation(C->getLParenLoc());
+ bool HasIteratorModifier = false;
for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) {
Record.push_back(C->getMapTypeModifier(I));
Record.AddSourceLocation(C->getMapTypeModifierLoc(I));
+ if (C->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_iterator)
+ HasIteratorModifier = true;
}
Record.AddNestedNameSpecifierLoc(C->getMapperQualifierLoc());
Record.AddDeclarationNameInfo(C->getMapperIdInfo());
@@ -6631,6 +6806,8 @@ void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) {
Record.AddStmt(E);
for (auto *E : C->mapperlists())
Record.AddStmt(E);
+ if (HasIteratorModifier)
+ Record.AddStmt(C->getIteratorModifier());
for (auto *D : C->all_decls())
Record.AddDeclRef(D);
for (auto N : C->all_num_lists())
@@ -6672,13 +6849,17 @@ void OMPClauseWriter::VisitOMPPriorityClause(OMPPriorityClause *C) {
void OMPClauseWriter::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) {
VisitOMPClauseWithPreInit(C);
+ Record.writeEnum(C->getModifier());
Record.AddStmt(C->getGrainsize());
+ Record.AddSourceLocation(C->getModifierLoc());
Record.AddSourceLocation(C->getLParenLoc());
}
void OMPClauseWriter::VisitOMPNumTasksClause(OMPNumTasksClause *C) {
VisitOMPClauseWithPreInit(C);
+ Record.writeEnum(C->getModifier());
Record.AddStmt(C->getNumTasks());
+ Record.AddSourceLocation(C->getModifierLoc());
Record.AddSourceLocation(C->getLParenLoc());
}
@@ -6866,6 +7047,23 @@ void OMPClauseWriter::VisitOMPAtomicDefaultMemOrderClause(
Record.AddSourceLocation(C->getAtomicDefaultMemOrderKindKwLoc());
}
+void OMPClauseWriter::VisitOMPAtClause(OMPAtClause *C) {
+ Record.push_back(C->getAtKind());
+ Record.AddSourceLocation(C->getLParenLoc());
+ Record.AddSourceLocation(C->getAtKindKwLoc());
+}
+
+void OMPClauseWriter::VisitOMPSeverityClause(OMPSeverityClause *C) {
+ Record.push_back(C->getSeverityKind());
+ Record.AddSourceLocation(C->getLParenLoc());
+ Record.AddSourceLocation(C->getSeverityKindKwLoc());
+}
+
+void OMPClauseWriter::VisitOMPMessageClause(OMPMessageClause *C) {
+ Record.AddStmt(C->getMessageString());
+ Record.AddSourceLocation(C->getLParenLoc());
+}
+
void OMPClauseWriter::VisitOMPNontemporalClause(OMPNontemporalClause *C) {
Record.push_back(C->varlist_size());
Record.AddSourceLocation(C->getLParenLoc());
@@ -6891,8 +7089,10 @@ void OMPClauseWriter::VisitOMPExclusiveClause(OMPExclusiveClause *C) {
void OMPClauseWriter::VisitOMPOrderClause(OMPOrderClause *C) {
Record.writeEnum(C->getKind());
+ Record.writeEnum(C->getModifier());
Record.AddSourceLocation(C->getLParenLoc());
Record.AddSourceLocation(C->getKindKwLoc());
+ Record.AddSourceLocation(C->getModifierKwLoc());
}
void OMPClauseWriter::VisitOMPUsesAllocatorsClause(OMPUsesAllocatorsClause *C) {
@@ -6922,6 +7122,12 @@ void OMPClauseWriter::VisitOMPBindClause(OMPBindClause *C) {
Record.AddSourceLocation(C->getBindKindLoc());
}
+void OMPClauseWriter::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) {
+ VisitOMPClauseWithPreInit(C);
+ Record.AddStmt(C->getSize());
+ Record.AddSourceLocation(C->getLParenLoc());
+}
+
void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) {
writeUInt32(TI->Sets.size());
for (const auto &Set : TI->Sets) {
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 35b8db27bd0e..a58e0d796b31 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -23,6 +23,7 @@
#include "clang/Serialization/ASTRecordWriter.h"
#include "llvm/Bitstream/BitstreamWriter.h"
#include "llvm/Support/ErrorHandling.h"
+#include <optional>
using namespace clang;
using namespace serialization;
@@ -107,6 +108,8 @@ namespace clang {
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
void VisitConceptDecl(ConceptDecl *D);
+ void VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D);
void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
@@ -122,6 +125,7 @@ namespace clang {
void VisitLinkageSpecDecl(LinkageSpecDecl *D);
void VisitExportDecl(ExportDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitTopLevelStmtDecl(TopLevelStmtDecl *D);
void VisitImportDecl(ImportDecl *D);
void VisitAccessSpecDecl(AccessSpecDecl *D);
void VisitFriendDecl(FriendDecl *D);
@@ -131,10 +135,9 @@ namespace clang {
void VisitCapturedDecl(CapturedDecl *D);
void VisitEmptyDecl(EmptyDecl *D);
void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
-
void VisitDeclContext(DeclContext *DC);
template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
-
+ void VisitHLSLBufferDecl(HLSLBufferDecl *D);
// FIXME: Put in the same order is DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
@@ -167,7 +170,7 @@ namespace clang {
}
Record.push_back(typeParams->size());
- for (auto typeParam : *typeParams) {
+ for (auto *typeParam : *typeParams) {
Record.AddDeclRef(typeParam);
}
Record.AddSourceLocation(typeParams->getLAngleLoc());
@@ -203,7 +206,7 @@ namespace clang {
return Common->PartialSpecializations;
}
ArrayRef<Decl> getPartialSpecializations(FunctionTemplateDecl::Common *) {
- return None;
+ return std::nullopt;
}
template<typename DeclTy>
@@ -221,7 +224,7 @@ namespace clang {
ArrayRef<DeclID> LazySpecializations;
if (auto *LS = Common->LazySpecializations)
- LazySpecializations = llvm::makeArrayRef(LS + 1, LS[0]);
+ LazySpecializations = llvm::ArrayRef(LS + 1, LS[0]);
// Add a slot to the record for the number of specializations.
unsigned I = Record.size();
@@ -488,6 +491,10 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
Record.push_back(D->hasNonTrivialToPrimitiveCopyCUnion());
Record.push_back(D->isParamDestroyedInCallee());
Record.push_back(D->getArgPassingRestrictions());
+ // Only compute this for C/Objective-C, in C++ this is computed as part
+ // of CXXRecordDecl.
+ if (!isa<CXXRecordDecl>(D))
+ Record.push_back(D->getODRHash());
if (D->getDeclContext() == D->getLexicalDeclContext() &&
!D->hasAttrs() &&
@@ -540,46 +547,6 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) {
void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
VisitRedeclarable(D);
- VisitDeclaratorDecl(D);
- Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName());
- Record.push_back(D->getIdentifierNamespace());
-
- // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
- // after everything else is written.
- Record.push_back(static_cast<int>(D->getStorageClass())); // FIXME: stable encoding
- Record.push_back(D->isInlineSpecified());
- Record.push_back(D->isInlined());
- Record.push_back(D->isVirtualAsWritten());
- Record.push_back(D->isPure());
- Record.push_back(D->hasInheritedPrototype());
- Record.push_back(D->hasWrittenPrototype());
- Record.push_back(D->isDeletedBit());
- Record.push_back(D->isTrivial());
- Record.push_back(D->isTrivialForCall());
- Record.push_back(D->isDefaulted());
- Record.push_back(D->isExplicitlyDefaulted());
- Record.push_back(D->hasImplicitReturnZero());
- Record.push_back(static_cast<uint64_t>(D->getConstexprKind()));
- Record.push_back(D->usesSEHTry());
- Record.push_back(D->hasSkippedBody());
- Record.push_back(D->isMultiVersion());
- Record.push_back(D->isLateTemplateParsed());
- Record.push_back(D->getLinkageInternal());
- Record.AddSourceLocation(D->getEndLoc());
-
- Record.push_back(D->getODRHash());
-
- if (D->isDefaulted()) {
- if (auto *FDI = D->getDefaultedFunctionInfo()) {
- Record.push_back(FDI->getUnqualifiedLookups().size());
- for (DeclAccessPair P : FDI->getUnqualifiedLookups()) {
- Record.AddDeclRef(P.getDecl());
- Record.push_back(P.getAccess());
- }
- } else {
- Record.push_back(0);
- }
- }
Record.push_back(D->getTemplatedKind());
switch (D->getTemplatedKind()) {
@@ -660,8 +627,53 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
}
}
+ VisitDeclaratorDecl(D);
+ Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName());
+ Record.push_back(D->getIdentifierNamespace());
+
+ // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
+ // after everything else is written.
+ Record.push_back(
+ static_cast<int>(D->getStorageClass())); // FIXME: stable encoding
+ Record.push_back(D->isInlineSpecified());
+ Record.push_back(D->isInlined());
+ Record.push_back(D->isVirtualAsWritten());
+ Record.push_back(D->isPure());
+ Record.push_back(D->hasInheritedPrototype());
+ Record.push_back(D->hasWrittenPrototype());
+ Record.push_back(D->isDeletedBit());
+ Record.push_back(D->isTrivial());
+ Record.push_back(D->isTrivialForCall());
+ Record.push_back(D->isDefaulted());
+ Record.push_back(D->isExplicitlyDefaulted());
+ Record.push_back(D->isIneligibleOrNotSelected());
+ Record.push_back(D->hasImplicitReturnZero());
+ Record.push_back(static_cast<uint64_t>(D->getConstexprKind()));
+ Record.push_back(D->usesSEHTry());
+ Record.push_back(D->hasSkippedBody());
+ Record.push_back(D->isMultiVersion());
+ Record.push_back(D->isLateTemplateParsed());
+ Record.push_back(D->FriendConstraintRefersToEnclosingTemplate());
+ Record.push_back(D->getLinkageInternal());
+ Record.AddSourceLocation(D->getEndLoc());
+ Record.AddSourceLocation(D->getDefaultLoc());
+
+ Record.push_back(D->getODRHash());
+
+ if (D->isDefaulted()) {
+ if (auto *FDI = D->getDefaultedFunctionInfo()) {
+ Record.push_back(FDI->getUnqualifiedLookups().size());
+ for (DeclAccessPair P : FDI->getUnqualifiedLookups()) {
+ Record.AddDeclRef(P.getDecl());
+ Record.push_back(P.getAccess());
+ }
+ } else {
+ Record.push_back(0);
+ }
+ }
+
Record.push_back(D->param_size());
- for (auto P : D->parameters())
+ for (auto *P : D->parameters())
Record.AddDeclRef(P);
Code = serialization::DECL_FUNCTION;
}
@@ -763,6 +775,7 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
Record.AddTypeSourceInfo(D->getSuperClassTInfo());
Record.AddSourceLocation(D->getEndOfDefinitionLoc());
Record.push_back(Data.HasDesignatedInitializers);
+ Record.push_back(D->getODRHash());
// Write out the protocols that are directly referenced by the @interface.
Record.push_back(Data.ReferencedProtocols.size());
@@ -825,6 +838,7 @@ void ASTDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
Record.AddDeclRef(I);
for (const auto &PL : D->protocol_locs())
Record.AddSourceLocation(PL);
+ Record.push_back(D->getODRHash());
}
Code = serialization::DECL_OBJC_PROTOCOL;
@@ -900,7 +914,7 @@ void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
Record.push_back(D->NumIvarInitializers);
if (D->NumIvarInitializers)
Record.AddCXXCtorInitializers(
- llvm::makeArrayRef(D->init_begin(), D->init_end()));
+ llvm::ArrayRef(D->init_begin(), D->init_end()));
Code = serialization::DECL_OBJC_IMPLEMENTATION;
}
@@ -1030,8 +1044,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
if (D->getStorageDuration() == SD_Static) {
bool ModulesCodegen = false;
if (Writer.WritingModule &&
- !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() &&
- !isa<VarTemplateSpecializationDecl>(D)) {
+ !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo()) {
// When building a C++20 module interface unit or a partition unit, a
// strong definition in the module interface is provided by the
// compilation of that unit, not by its users. (Inline variables are still
@@ -1165,6 +1178,12 @@ void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Code = serialization::DECL_FILE_SCOPE_ASM;
}
+void ASTDeclWriter::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) {
+ VisitDecl(D);
+ Record.AddStmt(D->getStmt());
+ Code = serialization::DECL_TOP_LEVEL_STMT_DECL;
+}
+
void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) {
VisitDecl(D);
Code = serialization::DECL_EMPTY;
@@ -1246,6 +1265,7 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
VisitRedeclarable(D);
VisitNamedDecl(D);
Record.push_back(D->isInline());
+ Record.push_back(D->isNested());
Record.AddSourceLocation(D->getBeginLoc());
Record.AddSourceLocation(D->getRBraceLoc());
@@ -1293,7 +1313,7 @@ void ASTDeclWriter::VisitUsingEnumDecl(UsingEnumDecl *D) {
VisitNamedDecl(D);
Record.AddSourceLocation(D->getUsingLoc());
Record.AddSourceLocation(D->getEnumLoc());
- Record.AddDeclRef(D->getEnumDecl());
+ Record.AddTypeSourceInfo(D->getEnumType());
Record.AddDeclRef(D->FirstUsingShadow.getPointer());
Record.AddDeclRef(Context.getInstantiatedFromUsingEnumDecl(D));
Code = serialization::DECL_USING_ENUM;
@@ -1404,14 +1424,12 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
}
if (D->getDeclContext() == D->getLexicalDeclContext() &&
- D->getFirstDecl() == D->getMostRecentDecl() &&
- !D->isInvalidDecl() &&
- !D->hasAttrs() &&
- !D->isTopLevelDeclInObjCContainer() &&
+ D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() &&
+ !D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
- !D->hasExtInfo() &&
- !D->hasInheritedPrototype() &&
- D->hasWrittenPrototype())
+ !D->hasExtInfo() && !D->hasInheritedPrototype() &&
+ D->hasWrittenPrototype() &&
+ D->getTemplatedKind() == FunctionDecl::TK_NonTemplate)
AbbrevToUse = Writer.getDeclCXXMethodAbbrev();
Code = serialization::DECL_CXX_METHOD;
@@ -1505,8 +1523,8 @@ void ASTDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
void ASTDeclWriter::VisitTemplateDecl(TemplateDecl *D) {
VisitNamedDecl(D);
- Record.AddDeclRef(D->getTemplatedDecl());
Record.AddTemplateParameterList(D->getTemplateParameters());
+ Record.AddDeclRef(D->getTemplatedDecl());
}
void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {
@@ -1515,6 +1533,15 @@ void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {
Code = serialization::DECL_CONCEPT;
}
+void ASTDeclWriter::VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D) {
+ Record.push_back(D->getTemplateArguments().size());
+ VisitDecl(D);
+ for (const TemplateArgument &Arg : D->getTemplateArguments())
+ Record.AddTemplateArgument(Arg);
+ Code = serialization::DECL_IMPLICIT_CONCEPT_SPECIALIZATION;
+}
+
void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
Code = serialization::DECL_REQUIRES_EXPR_BODY;
}
@@ -1607,8 +1634,6 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *D) {
RegisterTemplateSpecialization(D->getSpecializedTemplate(), D);
- VisitVarDecl(D);
-
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
InstFrom = D->getSpecializedTemplateOrPartial();
if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) {
@@ -1629,6 +1654,9 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl(
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Record.push_back(D->IsCompleteDefinition);
+
+ VisitVarDecl(D);
+
Record.push_back(D->isCanonicalDecl());
if (D->isCanonicalDecl()) {
@@ -1864,6 +1892,17 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
}
}
+void ASTDeclWriter::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
+ VisitNamedDecl(D);
+ VisitDeclContext(D);
+ Record.push_back(D->isCBuffer());
+ Record.AddSourceLocation(D->getLocStart());
+ Record.AddSourceLocation(D->getLBraceLoc());
+ Record.AddSourceLocation(D->getRBraceLoc());
+
+ Code = serialization::DECL_HLSL_BUFFER;
+}
+
void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
Record.writeOMPChildren(D->Data);
VisitDecl(D);
@@ -2093,6 +2132,8 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
// getArgPassingRestrictions
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2));
+ // ODRHash
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 26));
// DC
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
@@ -2233,6 +2274,8 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CXX_METHOD));
// RedeclarableDecl
Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl
+ // FIXME: Implement abbreviation for other template kinds.
+ Abv->Add(BitCodeAbbrevOp(FunctionDecl::TK_NonTemplate)); // TemplateKind
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(0)); // LexicalDeclContext
@@ -2269,20 +2312,22 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // TrivialForCall
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Defaulted
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitlyDefaulted
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsIneligibleOrNotSelected
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ImplicitReturnZero
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Constexpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // UsesSEHTry
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // MultiVersion
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FriendConstraintRefersToEnclosingTemplate
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Default
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // ODRHash
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // TemplateKind
// This Array slurps the rest of the record. Fortunately we want to encode
// (nearly) all the remaining (variable number of) fields in the same way.
//
- // This is the function template information if any, then
+ // This is:
// NumParams and Params[] from FunctionDecl, and
// NumOverriddenMethods, OverriddenMethods[] from CXXMethodDecl.
//
@@ -2389,7 +2434,7 @@ static bool isRequiredDecl(const Decl *D, ASTContext &Context,
// File scoped assembly or obj-c or OMP declare target implementation must be
// seen.
- if (isa<FileScopeAsmDecl>(D) || isa<ObjCImplDecl>(D))
+ if (isa<FileScopeAsmDecl, TopLevelStmtDecl, ObjCImplDecl>(D))
return true;
if (WritingModule && isPartOfPerModuleInitializer(D)) {
@@ -2429,11 +2474,12 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
SourceLocation Loc = D->getLocation();
unsigned Index = ID - FirstDeclID;
if (DeclOffsets.size() == Index)
- DeclOffsets.emplace_back(Loc, Offset, DeclTypesBlockStartOffset);
+ DeclOffsets.emplace_back(getAdjustedLocation(Loc), Offset,
+ DeclTypesBlockStartOffset);
else if (DeclOffsets.size() < Index) {
// FIXME: Can/should this happen?
DeclOffsets.resize(Index+1);
- DeclOffsets[Index].setLocation(Loc);
+ DeclOffsets[Index].setLocation(getAdjustedLocation(Loc));
DeclOffsets[Index].setBitOffset(Offset, DeclTypesBlockStartOffset);
} else {
llvm_unreachable("declarations should be emitted in ID order");
@@ -2456,7 +2502,7 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
assert(FD->doesThisDeclarationHaveABody());
bool ModulesCodegen = false;
if (!FD->isDependentContext()) {
- Optional<GVALinkage> Linkage;
+ std::optional<GVALinkage> Linkage;
if (Writer->WritingModule &&
Writer->WritingModule->isInterfaceOrPartition()) {
// When building a C++20 module interface unit or a partition unit, a
@@ -2486,8 +2532,7 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
Record->push_back(CD->getNumCtorInitializers());
if (CD->getNumCtorInitializers())
- AddCXXCtorInitializers(
- llvm::makeArrayRef(CD->init_begin(), CD->init_end()));
+ AddCXXCtorInitializers(llvm::ArrayRef(CD->init_begin(), CD->init_end()));
}
AddStmt(FD->getBody());
}
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 5e5a86ee01a2..b35a7cee5af2 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -402,6 +402,7 @@ static void
addConstraintSatisfaction(ASTRecordWriter &Record,
const ASTConstraintSatisfaction &Satisfaction) {
Record.push_back(Satisfaction.IsSatisfied);
+ Record.push_back(Satisfaction.ContainsErrors);
if (!Satisfaction.IsSatisfied) {
Record.push_back(Satisfaction.NumRecords);
for (const auto &DetailRecord : Satisfaction) {
@@ -432,16 +433,13 @@ addSubstitutionDiagnostic(
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.AddDeclarationNameInfo(E->getConceptNameInfo());
Record.AddDeclRef(E->getNamedConcept());
Record.AddDeclRef(E->getFoundDecl());
+ Record.AddDeclRef(E->getSpecializationDecl());
Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten());
- for (const TemplateArgument &Arg : TemplateArgs)
- Record.AddTemplateArgument(Arg);
if (!E->isValueDependent())
addConstraintSatisfaction(Record, E->getSatisfaction());
@@ -495,12 +493,12 @@ void ASTStmtWriter::VisitRequiresExpr(RequiresExpr *E) {
} else {
auto *NestedReq = cast<concepts::NestedRequirement>(R);
Record.push_back(concepts::Requirement::RK_Nested);
- Record.push_back(NestedReq->isSubstitutionFailure());
- if (NestedReq->isSubstitutionFailure()){
- addSubstitutionDiagnostic(Record,
- NestedReq->getSubstitutionDiagnostic());
+ Record.push_back(NestedReq->hasInvalidConstraint());
+ if (NestedReq->hasInvalidConstraint()) {
+ Record.AddString(NestedReq->getInvalidConstraintEntity());
+ addConstraintSatisfaction(Record, *NestedReq->Satisfaction);
} else {
- Record.AddStmt(NestedReq->Value.get<Expr *>());
+ Record.AddStmt(NestedReq->getConstraintExpr());
if (!NestedReq->isDependent())
addConstraintSatisfaction(Record, *NestedReq->Satisfaction);
}
@@ -1747,14 +1745,20 @@ void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
Record.AddDeclRef(E->getParam());
Record.AddDeclRef(cast_or_null<Decl>(E->getUsedContext()));
Record.AddSourceLocation(E->getUsedLocation());
+ Record.push_back(E->hasRewrittenInit());
+ if (E->hasRewrittenInit())
+ Record.AddStmt(E->getRewrittenExpr());
Code = serialization::EXPR_CXX_DEFAULT_ARG;
}
void ASTStmtWriter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
VisitExpr(E);
+ Record.push_back(E->hasRewrittenInit());
Record.AddDeclRef(E->getField());
Record.AddDeclRef(cast_or_null<Decl>(E->getUsedContext()));
Record.AddSourceLocation(E->getExprLoc());
+ if (E->hasRewrittenInit())
+ Record.AddStmt(E->getRewrittenExpr());
Code = serialization::EXPR_CXX_DEFAULT_INIT;
}
@@ -2027,8 +2031,13 @@ void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
void ASTStmtWriter::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
- Record.AddDeclRef(E->getParameter());
+ Record.AddDeclRef(E->getAssociatedDecl());
Record.push_back(E->isReferenceParameter());
+ Record.push_back(E->getIndex());
+ if (auto PackIndex = E->getPackIndex())
+ Record.push_back(*PackIndex + 1);
+ else
+ Record.push_back(0);
Record.AddSourceLocation(E->getNameLoc());
Record.AddStmt(E->getReplacement());
Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM;
@@ -2037,7 +2046,8 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmExpr(
void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr(
SubstNonTypeTemplateParmPackExpr *E) {
VisitExpr(E);
- Record.AddDeclRef(E->getParameterPack());
+ Record.AddDeclRef(E->getAssociatedDecl());
+ Record.push_back(E->getIndex());
Record.AddTemplateArgument(E->getArgumentPack());
Record.AddSourceLocation(E->getParameterPackLocation());
Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK;
@@ -2077,6 +2087,30 @@ void ASTStmtWriter::VisitCXXFoldExpr(CXXFoldExpr *E) {
Code = serialization::EXPR_CXX_FOLD;
}
+void ASTStmtWriter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
+ VisitExpr(E);
+ ArrayRef<Expr *> InitExprs = E->getInitExprs();
+ Record.push_back(InitExprs.size());
+ Record.push_back(E->getUserSpecifiedInitExprs().size());
+ Record.AddSourceLocation(E->getInitLoc());
+ Record.AddSourceLocation(E->getBeginLoc());
+ Record.AddSourceLocation(E->getEndLoc());
+ for (Expr *InitExpr : E->getInitExprs())
+ Record.AddStmt(InitExpr);
+ Expr *ArrayFiller = E->getArrayFiller();
+ FieldDecl *UnionField = E->getInitializedFieldInUnion();
+ bool HasArrayFillerOrUnionDecl = ArrayFiller || UnionField;
+ Record.push_back(HasArrayFillerOrUnionDecl);
+ if (HasArrayFillerOrUnionDecl) {
+ Record.push_back(static_cast<bool>(ArrayFiller));
+ if (ArrayFiller)
+ Record.AddStmt(ArrayFiller);
+ else
+ Record.AddDeclRef(UnionField);
+ }
+ Code = serialization::EXPR_CXX_PAREN_LIST_INIT;
+}
+
void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
VisitExpr(E);
Record.AddStmt(E->getSourceExpr());
@@ -2392,6 +2426,13 @@ void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
Code = serialization::STMT_OMP_TASKWAIT_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPErrorDirective(OMPErrorDirective *D) {
+ VisitStmt(D);
+ Record.push_back(D->getNumClauses());
+ VisitOMPExecutableDirective(D);
+ Code = serialization::STMT_OMP_ERROR_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *D) {
VisitStmt(D);
VisitOMPExecutableDirective(D);
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index 4fd217cf7a6e..81dd54692d77 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -249,7 +249,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
return NewlyLoaded;
}
-void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) {
+void ModuleManager::removeModules(ModuleIterator First) {
auto Last = end();
if (First == Last)
return;
@@ -280,19 +280,10 @@ void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) {
}
}
- // Delete the modules and erase them from the various structures.
- for (ModuleIterator victim = First; victim != Last; ++victim) {
+ // Delete the modules.
+ for (ModuleIterator victim = First; victim != Last; ++victim)
Modules.erase(victim->File);
- if (modMap) {
- StringRef ModuleName = victim->ModuleName;
- if (Module *mod = modMap->findModule(ModuleName)) {
- mod->setASTFile(None);
- }
- }
- }
-
- // Delete the modules.
Chain.erase(Chain.begin() + (First - begin()), Chain.end());
}
@@ -453,14 +444,14 @@ void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
bool ModuleManager::lookupModuleFile(StringRef FileName, off_t ExpectedSize,
time_t ExpectedModTime,
- Optional<FileEntryRef> &File) {
- File = None;
+ OptionalFileEntryRef &File) {
+ File = std::nullopt;
if (FileName == "-")
return false;
// Open the file immediately to ensure there is no race between stat'ing and
// opening the file.
- Optional<FileEntryRef> FileOrErr =
+ OptionalFileEntryRef FileOrErr =
expectedToOptional(FileMgr.getFileRef(FileName, /*OpenFile=*/true,
/*CacheFailure=*/false));
if (!FileOrErr)
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index 6154eeb3419c..45783729e142 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -59,7 +60,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
if (D != P.getLocationContext()->getDecl())
continue;
- if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
+ if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
const CFGBlock *CB = BE->getBlock();
reachable.insert(CB);
}
@@ -123,7 +124,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
if (Exit->empty())
continue;
const CFGElement &CE = Exit->front();
- if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
SmallString<128> bufI;
llvm::raw_svector_ostream outputI(bufI);
outputI << "(" << NameOfRootFunction << ")" <<
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 5be5bcde4d6e..986b0add93df 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -23,6 +23,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -84,7 +85,7 @@ static SVal computeExtentBegin(SValBuilder &svalBuilder,
static std::pair<NonLoc, nonloc::ConcreteInt>
getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent,
SValBuilder &svalBuilder) {
- Optional<nonloc::SymbolVal> SymVal = offset.getAs<nonloc::SymbolVal>();
+ std::optional<nonloc::SymbolVal> SymVal = offset.getAs<nonloc::SymbolVal>();
if (SymVal && SymVal->isExpression()) {
if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SymVal->getSymbol())) {
llvm::APSInt constant =
@@ -143,7 +144,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion());
- if (Optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) {
if (auto ConcreteNV = NV->getAs<nonloc::ConcreteInt>()) {
std::pair<NonLoc, nonloc::ConcreteInt> simplifiedOffsets =
getSimplifiedOffsets(rawOffset.getByteOffset(), *ConcreteNV,
@@ -155,7 +156,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
SVal lowerBound = svalBuilder.evalBinOpNN(state, BO_LT, rawOffsetVal, *NV,
svalBuilder.getConditionType());
- Optional<NonLoc> lowerBoundToCheck = lowerBound.getAs<NonLoc>();
+ std::optional<NonLoc> lowerBoundToCheck = lowerBound.getAs<NonLoc>();
if (!lowerBoundToCheck)
return;
@@ -194,7 +195,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
Size.castAs<NonLoc>(),
svalBuilder.getConditionType());
- Optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>();
+ std::optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>();
if (!upperboundToCheck)
break;
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index ca76e2d83381..44166aaf5b85 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -33,6 +33,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -369,7 +370,7 @@ enum CFNumberType {
kCFNumberCGFloatType = 16
};
-static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
+static std::optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
if (i < kCFNumberCharType)
@@ -390,7 +391,7 @@ static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
case kCFNumberCGFloatType:
// FIXME: We need a way to map from names to Type*.
default:
- return None;
+ return std::nullopt;
}
return Ctx.getTypeSize(T);
@@ -442,12 +443,13 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
// FIXME: We really should allow ranges of valid theType values, and
// bifurcate the state appropriately.
- Optional<nonloc::ConcreteInt> V = dyn_cast<nonloc::ConcreteInt>(TheTypeVal);
+ std::optional<nonloc::ConcreteInt> V =
+ dyn_cast<nonloc::ConcreteInt>(TheTypeVal);
if (!V)
return;
uint64_t NumberKind = V->getValue().getLimitedValue();
- Optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
+ std::optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
// FIXME: In some cases we can emit an error.
if (!OptCFNumberSize)
@@ -462,7 +464,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
// FIXME: Eventually we should handle arbitrary locations. We can do this
// by having an enhanced memory model that does low-level typing.
- Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
+ std::optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
if (!LV)
return;
@@ -531,10 +533,10 @@ namespace {
class CFRetainReleaseChecker : public Checker<check::PreCall> {
mutable APIMisuse BT{this, "null passed to CF memory management function"};
const CallDescriptionSet ModelledCalls = {
- {"CFRetain", 1},
- {"CFRelease", 1},
- {"CFMakeCollectable", 1},
- {"CFAutorelease", 1},
+ {{"CFRetain"}, 1},
+ {{"CFRelease"}, 1},
+ {{"CFMakeCollectable"}, 1},
+ {{"CFAutorelease"}, 1},
};
public:
@@ -554,7 +556,7 @@ void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
// Get the argument's value.
SVal ArgVal = Call.getArgSVal(0);
- Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
if (!DefArgVal)
return;
@@ -742,7 +744,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
// Verify that all arguments have Objective-C types.
- Optional<ExplodedNode*> errorNode;
+ std::optional<ExplodedNode *> errorNode;
for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
QualType ArgTy = msg.getArgExpr(I)->getType();
@@ -769,7 +771,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (!errorNode)
errorNode = C.generateNonFatalErrorNode();
- if (!errorNode.value())
+ if (!*errorNode)
continue;
SmallString<128> sbuf;
@@ -786,8 +788,8 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
ArgTy.print(os, C.getLangOpts());
os << "'";
- auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(),
- errorNode.value());
+ auto R =
+ std::make_unique<PathSensitiveBugReport>(*BT, os.str(), *errorNode);
R->addRange(msg.getArgSourceRange(I));
C.emitReport(std::move(R));
}
@@ -857,7 +859,8 @@ static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
return nullptr;
SVal CollectionVal = C.getSVal(FCS->getCollection());
- Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> KnownCollection =
+ CollectionVal.getAs<DefinedSVal>();
if (!KnownCollection)
return State;
@@ -889,7 +892,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
const Stmt *Element = FCS->getElement();
// FIXME: Copied from ExprEngineObjC.
- Optional<Loc> ElementLoc;
+ std::optional<Loc> ElementLoc;
if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
assert(ElemDecl->getInit() == nullptr);
@@ -928,8 +931,8 @@ assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
nonloc::SymbolVal(*CountS),
SvalBuilder.makeIntVal(0, (*CountS)->getType()),
SvalBuilder.getConditionType());
- Optional<DefinedSVal> CountGreaterThanZero =
- CountGreaterThanZeroVal.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> CountGreaterThanZero =
+ CountGreaterThanZeroVal.getAs<DefinedSVal>();
if (!CountGreaterThanZero) {
// The SValBuilder cannot construct a valid SVal for this condition.
// This means we cannot properly reason about it.
@@ -957,7 +960,7 @@ static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
return false;
ProgramPoint P = N->getLocation();
- if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
+ if (std::optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
return BE->getSrc()->getLoopTarget() == FCS;
}
@@ -1092,7 +1095,7 @@ ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
PointerEscapeKind Kind) const {
SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
- // Remove the invalidated symbols form the collection count map.
+ // Remove the invalidated symbols from the collection count map.
for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
E = Escaped.end();
I != E; ++I) {
@@ -1174,7 +1177,8 @@ ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
ProgramStateRef State,
CheckerContext &C) const {
SVal Val = C.getSVal(NonNullExpr);
- if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
+ if (std::optional<DefinedOrUnknownSVal> DV =
+ Val.getAs<DefinedOrUnknownSVal>())
return State->assume(*DV, true);
return State;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 8416ab39e194..76f091562cd5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -64,19 +64,15 @@ public:
REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
- : IILockGuard(nullptr), IIUniqueLock(nullptr),
- LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
- FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"),
- PthreadLockFn("pthread_mutex_lock"),
- PthreadTryLockFn("pthread_mutex_trylock"),
- PthreadUnlockFn("pthread_mutex_unlock"),
- MtxLock("mtx_lock"),
- MtxTimedLock("mtx_timedlock"),
- MtxTryLock("mtx_trylock"),
- MtxUnlock("mtx_unlock"),
- ClassLockGuard("lock_guard"),
- ClassUniqueLock("unique_lock"),
- IdentifierInfoInitialized(false) {
+ : IILockGuard(nullptr), IIUniqueLock(nullptr), LockFn({"lock"}),
+ UnlockFn({"unlock"}), SleepFn({"sleep"}), GetcFn({"getc"}),
+ FgetsFn({"fgets"}), ReadFn({"read"}), RecvFn({"recv"}),
+ PthreadLockFn({"pthread_mutex_lock"}),
+ PthreadTryLockFn({"pthread_mutex_trylock"}),
+ PthreadUnlockFn({"pthread_mutex_unlock"}), MtxLock({"mtx_lock"}),
+ MtxTimedLock({"mtx_timedlock"}), MtxTryLock({"mtx_trylock"}),
+ MtxUnlock({"mtx_unlock"}), ClassLockGuard("lock_guard"),
+ ClassUniqueLock("unique_lock"), IdentifierInfoInitialized(false) {
// Initialize the bug type.
BlockInCritSectionBugType.reset(
new BugType(this, "Call to blocking function in critical section",
diff --git a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index dad25d6f853b..2d20e394681d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -74,7 +75,7 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// Get the value of the right-hand side. We only care about values
// that are defined (UnknownVals and UndefinedVals are handled by other
// checkers).
- Optional<NonLoc> NV = val.getAs<NonLoc>();
+ std::optional<NonLoc> NV = val.getAs<NonLoc>();
if (!NV)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 9a6c013bcf66..12b948a65261 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -27,6 +27,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -75,6 +76,16 @@ static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
}
enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
+
+enum class CharKind { Regular = 0, Wide };
+constexpr CharKind CK_Regular = CharKind::Regular;
+constexpr CharKind CK_Wide = CharKind::Wide;
+
+static QualType getCharPtrType(ASTContext &Ctx, CharKind CK) {
+ return Ctx.getPointerType(CK == CharKind::Regular ? Ctx.CharTy
+ : Ctx.WideCharTy);
+}
+
class CStringChecker : public Checker< eval::Call,
check::PreStmt<DeclStmt>,
check::LiveSymbols,
@@ -124,35 +135,46 @@ public:
const CallExpr *)>;
CallDescriptionMap<FnCheck> Callbacks = {
- {{CDF_MaybeBuiltin, "memcpy", 3},
- std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, false)},
- {{CDF_MaybeBuiltin, "wmemcpy", 3},
- std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, true)},
- {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy},
- {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp},
- {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove},
- {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset},
- {{CDF_MaybeBuiltin, "explicit_memset", 3}, &CStringChecker::evalMemset},
- {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy},
- {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy},
- {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy},
- {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy},
- {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat},
- {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat},
- {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat},
- {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength},
- {{CDF_MaybeBuiltin, "wcslen", 1}, &CStringChecker::evalstrLength},
- {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength},
- {{CDF_MaybeBuiltin, "wcsnlen", 2}, &CStringChecker::evalstrnLength},
- {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp},
- {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp},
- {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp},
- {{CDF_MaybeBuiltin, "strncasecmp", 3}, &CStringChecker::evalStrncasecmp},
- {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep},
- {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy},
- {{CDF_MaybeBuiltin, "bcmp", 3}, &CStringChecker::evalMemcmp},
- {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero},
- {{CDF_MaybeBuiltin, "explicit_bzero", 2}, &CStringChecker::evalBzero},
+ {{CDF_MaybeBuiltin, {"memcpy"}, 3},
+ std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Regular)},
+ {{CDF_MaybeBuiltin, {"wmemcpy"}, 3},
+ std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Wide)},
+ {{CDF_MaybeBuiltin, {"mempcpy"}, 3},
+ std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Regular)},
+ {{CDF_None, {"wmempcpy"}, 3},
+ std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Wide)},
+ {{CDF_MaybeBuiltin, {"memcmp"}, 3},
+ std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
+ {{CDF_MaybeBuiltin, {"wmemcmp"}, 3},
+ std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Wide)},
+ {{CDF_MaybeBuiltin, {"memmove"}, 3},
+ std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Regular)},
+ {{CDF_MaybeBuiltin, {"wmemmove"}, 3},
+ std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Wide)},
+ {{CDF_MaybeBuiltin, {"memset"}, 3}, &CStringChecker::evalMemset},
+ {{CDF_MaybeBuiltin, {"explicit_memset"}, 3}, &CStringChecker::evalMemset},
+ {{CDF_MaybeBuiltin, {"strcpy"}, 2}, &CStringChecker::evalStrcpy},
+ {{CDF_MaybeBuiltin, {"strncpy"}, 3}, &CStringChecker::evalStrncpy},
+ {{CDF_MaybeBuiltin, {"stpcpy"}, 2}, &CStringChecker::evalStpcpy},
+ {{CDF_MaybeBuiltin, {"strlcpy"}, 3}, &CStringChecker::evalStrlcpy},
+ {{CDF_MaybeBuiltin, {"strcat"}, 2}, &CStringChecker::evalStrcat},
+ {{CDF_MaybeBuiltin, {"strncat"}, 3}, &CStringChecker::evalStrncat},
+ {{CDF_MaybeBuiltin, {"strlcat"}, 3}, &CStringChecker::evalStrlcat},
+ {{CDF_MaybeBuiltin, {"strlen"}, 1}, &CStringChecker::evalstrLength},
+ {{CDF_MaybeBuiltin, {"wcslen"}, 1}, &CStringChecker::evalstrLength},
+ {{CDF_MaybeBuiltin, {"strnlen"}, 2}, &CStringChecker::evalstrnLength},
+ {{CDF_MaybeBuiltin, {"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
+ {{CDF_MaybeBuiltin, {"strcmp"}, 2}, &CStringChecker::evalStrcmp},
+ {{CDF_MaybeBuiltin, {"strncmp"}, 3}, &CStringChecker::evalStrncmp},
+ {{CDF_MaybeBuiltin, {"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
+ {{CDF_MaybeBuiltin, {"strncasecmp"}, 3},
+ &CStringChecker::evalStrncasecmp},
+ {{CDF_MaybeBuiltin, {"strsep"}, 2}, &CStringChecker::evalStrsep},
+ {{CDF_MaybeBuiltin, {"bcopy"}, 3}, &CStringChecker::evalBcopy},
+ {{CDF_MaybeBuiltin, {"bcmp"}, 3},
+ std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
+ {{CDF_MaybeBuiltin, {"bzero"}, 2}, &CStringChecker::evalBzero},
+ {{CDF_MaybeBuiltin, {"explicit_bzero"}, 2}, &CStringChecker::evalBzero},
};
// These require a bit of special handling.
@@ -160,16 +182,16 @@ public:
StdCopyBackward{{"std", "copy_backward"}, 3};
FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const;
- void evalMemcpy(CheckerContext &C, const CallExpr *CE, bool IsWide) const;
- void evalMempcpy(CheckerContext &C, const CallExpr *CE) const;
- void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemcpy(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
+ void evalMempcpy(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
+ void evalMemmove(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest, SourceArgExpr Source,
- bool Restricted, bool IsMempcpy, bool IsWide) const;
+ bool Restricted, bool IsMempcpy, CharKind CK) const;
- void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemcmp(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
@@ -248,14 +270,16 @@ public:
AnyArgExpr Arg, SVal l) const;
ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
- AccessKind Access, bool IsWide = false) const;
+ AccessKind Access,
+ CharKind CK = CharKind::Regular) const;
ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Buffer, SizeArgExpr Size,
AccessKind Access,
- bool IsWide = false) const;
+ CharKind CK = CharKind::Regular) const;
ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state,
SizeArgExpr Size, AnyArgExpr First,
- AnyArgExpr Second, bool IsWide = false) const;
+ AnyArgExpr Second,
+ CharKind CK = CharKind::Regular) const;
void emitOverlapBug(CheckerContext &C,
ProgramStateRef state,
const Stmt *First,
@@ -295,7 +319,7 @@ REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
std::pair<ProgramStateRef , ProgramStateRef >
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
QualType Ty) {
- Optional<DefinedSVal> val = V.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> val = V.getAs<DefinedSVal>();
if (!val)
return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
@@ -339,7 +363,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
AccessKind Access,
- bool IsWide) const {
+ CharKind CK) const {
// If a previous check has failed, propagate the failure.
if (!state)
@@ -360,7 +384,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
// Get the index of the accessed element.
NonLoc Idx = ER->getIndex();
- if (!IsWide) {
+ if (CK == CharKind::Regular) {
if (ER->getValueType() != Ctx.CharTy)
return state;
} else {
@@ -417,7 +441,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef
CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Buffer, SizeArgExpr Size,
- AccessKind Access, bool IsWide) const {
+ AccessKind Access, CharKind CK) const {
// If a previous check has failed, propagate the failure.
if (!State)
return nullptr;
@@ -426,7 +450,7 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
ASTContext &Ctx = svalBuilder.getContext();
QualType SizeTy = Size.Expression->getType();
- QualType PtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
+ QualType PtrTy = getCharPtrType(Ctx, CK);
// Check that the first buffer is non-null.
SVal BufVal = C.getSVal(Buffer.Expression);
@@ -442,7 +466,7 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
// FIXME: This assumes the caller has already checked that the access length
// is positive. And that it's unsigned.
SVal LengthVal = C.getSVal(Size.Expression);
- Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
+ std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return State;
@@ -456,11 +480,11 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
// Check that the first buffer is sufficiently long.
SVal BufStart =
svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
- if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
+ if (std::optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
SVal BufEnd =
svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
- State = CheckLocation(C, State, Buffer, BufEnd, Access, IsWide);
+ State = CheckLocation(C, State, Buffer, BufEnd, Access, CK);
// If the buffer isn't large enough, abort.
if (!State)
@@ -475,7 +499,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
ProgramStateRef state,
SizeArgExpr Size, AnyArgExpr First,
AnyArgExpr Second,
- bool IsWide) const {
+ CharKind CK) const {
if (!Filter.CheckCStringBufferOverlap)
return state;
@@ -499,11 +523,11 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
SVal firstVal = state->getSVal(First.Expression, LCtx);
SVal secondVal = state->getSVal(Second.Expression, LCtx);
- Optional<Loc> firstLoc = firstVal.getAs<Loc>();
+ std::optional<Loc> firstLoc = firstVal.getAs<Loc>();
if (!firstLoc)
return state;
- Optional<Loc> secondLoc = secondVal.getAs<Loc>();
+ std::optional<Loc> secondLoc = secondVal.getAs<Loc>();
if (!secondLoc)
return state;
@@ -526,7 +550,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
QualType cmpTy = svalBuilder.getConditionType();
SVal reverse =
svalBuilder.evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
- Optional<DefinedOrUnknownSVal> reverseTest =
+ std::optional<DefinedOrUnknownSVal> reverseTest =
reverse.getAs<DefinedOrUnknownSVal>();
if (!reverseTest)
return state;
@@ -547,31 +571,31 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
// Get the length, and make sure it too is known.
SVal LengthVal = state->getSVal(Size.Expression, LCtx);
- Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
+ std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return state;
// Convert the first buffer's start address to char*.
// Bail out if the cast fails.
ASTContext &Ctx = svalBuilder.getContext();
- QualType CharPtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
+ QualType CharPtrTy = getCharPtrType(Ctx, CK);
SVal FirstStart =
svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType());
- Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
+ std::optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
if (!FirstStartLoc)
return state;
// Compute the end of the first buffer. Bail out if THAT fails.
SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, *FirstStartLoc,
*Length, CharPtrTy);
- Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>();
+ std::optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>();
if (!FirstEndLoc)
return state;
// Is the end of the first buffer past the start of the second buffer?
SVal Overlap =
svalBuilder.evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
- Optional<DefinedOrUnknownSVal> OverlapTest =
+ std::optional<DefinedOrUnknownSVal> OverlapTest =
Overlap.getAs<DefinedOrUnknownSVal>();
if (!OverlapTest)
return state;
@@ -736,7 +760,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
left = right;
}
- if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) {
QualType cmpTy = svalBuilder.getConditionType();
// If left > max - right, we have an overflow.
SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
@@ -822,7 +846,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
C.blockCount());
if (!hypothetical) {
- if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> strLn = strLength.getAs<NonLoc>()) {
// In case of unbounded calls strlen etc bound the range to SIZE_MAX/4
BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
@@ -848,7 +872,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
// If we can't get a region, see if it's something we /know/ isn't a
// C string. In the context of locations, the only time we can issue such
// a warning is for labels.
- if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) {
+ if (std::optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) {
if (Filter.CheckCStringNotNullTerm) {
SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
@@ -953,7 +977,7 @@ bool CStringChecker::IsFirstBufInBound(CheckerContext &C,
SVal BufVal = state->getSVal(FirstBuf, LCtx);
SVal LengthVal = state->getSVal(Size, LCtx);
- Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
+ std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return true; // cf top comment.
@@ -966,7 +990,7 @@ bool CStringChecker::IsFirstBufInBound(CheckerContext &C,
// Check that the first buffer is sufficiently long.
SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
- Optional<Loc> BufLoc = BufStart.getAs<Loc>();
+ std::optional<Loc> BufLoc = BufStart.getAs<Loc>();
if (!BufLoc)
return true; // cf top comment.
@@ -1004,14 +1028,14 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
const Expr *E, SVal V,
bool IsSourceBuffer,
const Expr *Size) {
- Optional<Loc> L = V.getAs<Loc>();
+ std::optional<Loc> L = V.getAs<Loc>();
if (!L)
return state;
// FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes
// some assumptions about the value that CFRefCount can't. Even so, it should
// probably be refactored.
- if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
const MemRegion *R = MR->getRegion()->StripCasts();
// Are we dealing with an ElementRegion? If so, we should be invalidating
@@ -1111,7 +1135,7 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal,
RegionOffset Offset = MR->getAsOffset();
const MemRegion *BR = Offset.getRegion();
- Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>();
+ std::optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>();
if (!SizeNL)
return false;
@@ -1190,7 +1214,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest,
SourceArgExpr Source, bool Restricted,
- bool IsMempcpy, bool IsWide) const {
+ bool IsMempcpy, CharKind CK) const {
CurrentFunctionDescription = "memory copy function";
// See if the size argument is zero.
@@ -1233,11 +1257,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
return;
// Ensure the accesses are valid and that the buffers do not overlap.
- state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, IsWide);
- state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, IsWide);
+ state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, CK);
+ state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, CK);
if (Restricted)
- state = CheckOverlap(C, state, Size, Dest, Source, IsWide);
+ state = CheckOverlap(C, state, Size, Dest, Source, CK);
if (!state)
return;
@@ -1248,7 +1272,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
// Get the byte after the last byte copied.
SValBuilder &SvalBuilder = C.getSValBuilder();
ASTContext &Ctx = SvalBuilder.getContext();
- QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
+ QualType CharPtrTy = getCharPtrType(Ctx, CK);
SVal DestRegCharVal =
SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType());
SVal lastElement = C.getSValBuilder().evalBinOp(
@@ -1288,7 +1312,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
}
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
- bool IsWide) const {
+ CharKind CK) const {
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
DestinationArgExpr Dest = {CE->getArg(0), 0};
@@ -1299,11 +1323,11 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = false;
- evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy,
- IsWide);
+ evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
}
-void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
+void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE,
+ CharKind CK) const {
// void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is a pointer to the byte following the last written byte.
DestinationArgExpr Dest = {CE->getArg(0), 0};
@@ -1313,10 +1337,11 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = true;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
- false);
+ CK);
}
-void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
+void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE,
+ CharKind CK) const {
// void *memmove(void *dst, const void *src, size_t n);
// The return value is the address of the destination buffer.
DestinationArgExpr Dest = {CE->getArg(0), 0};
@@ -1326,7 +1351,7 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
- false);
+ CK);
}
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
@@ -1338,10 +1363,11 @@ void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
- false);
+ CharKind::Regular);
}
-void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
+void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE,
+ CharKind CK) const {
// int memcmp(const void *s1, const void *s2, size_t n);
CurrentFunctionDescription = "memory comparison function";
@@ -1401,8 +1427,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// If the two arguments might be different buffers, we have to check
// the size of both of them.
assert(NotSameBuffer);
- State = CheckBufferAccess(C, State, Right, Size, AccessKind::read);
- State = CheckBufferAccess(C, State, Left, Size, AccessKind::read);
+ State = CheckBufferAccess(C, State, Right, Size, AccessKind::read, CK);
+ State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
if (State) {
// The return value is the comparison result, which we don't know.
SVal CmpV = Builder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
@@ -1481,8 +1507,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
const Expr *maxlenExpr = CE->getArg(1);
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
- Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
- Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
+ std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+ std::optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
if (strLengthNL && maxlenValNL) {
ProgramStateRef stateStringTooLong, stateStringNotTooLong;
@@ -1630,11 +1656,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Get the string length of the source.
SVal strLength = getCStringLength(C, state, srcExpr.Expression, srcVal);
- Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+ std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
// Get the string length of the destination buffer.
SVal dstStrLength = getCStringLength(C, state, Dst.Expression, DstVal);
- Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
+ std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
// If the source isn't a valid C string, give up.
if (strLength.isUndef())
@@ -1672,7 +1698,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
lenVal =
svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
- Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
+ std::optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
// If we know both values, we might be able to figure out how much
// we're copying.
@@ -1714,7 +1740,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
freeSpace =
svalBuilder.evalBinOp(state, BO_Sub, freeSpace,
svalBuilder.makeIntVal(1, sizeTy), sizeTy);
- Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>();
+ std::optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>();
// While unlikely, it is possible that the subtraction is
// too complex to compute, let's check whether it succeeded.
@@ -1839,7 +1865,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
*dstStrLengthNL, sizeTy);
}
- Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>();
+ std::optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>();
// If we know both string lengths, we might know the final string length.
if (amountCopiedNL && dstStrLengthNL) {
@@ -1860,7 +1886,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
finalStrLength = getCStringLength(C, state, CE, DstVal, true);
assert(!finalStrLength.isUndef());
- if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> finalStrLengthNL =
+ finalStrLength.getAs<NonLoc>()) {
if (amountCopiedNL && appendK == ConcatFnKind::none) {
// we overwrite dst string with the src
// finalStrLength >= srcStrLength
@@ -1911,13 +1938,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If the destination is a MemRegion, try to check for a buffer overflow and
// record the new string length.
- if (Optional<loc::MemRegionVal> dstRegVal =
- DstVal.getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> dstRegVal =
+ DstVal.getAs<loc::MemRegionVal>()) {
QualType ptrTy = Dst.Expression->getType();
// If we have an exact value on a bounded copy, use that to check for
// overflows, rather than our estimate about how much is actually copied.
- if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
SVal maxLastElement =
svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
@@ -1927,7 +1954,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
}
// Then, if the final length is known...
- if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
*knownStrLength, ptrTy);
@@ -2119,7 +2146,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType());
// Constrain strcmp's result range based on the result of StringRef's
// comparison methods.
- BinaryOperatorKind op = (compareRes == 1) ? BO_GT : BO_LT;
+ BinaryOperatorKind op = (compareRes > 0) ? BO_GT : BO_LT;
SVal compareWithZero =
svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
svalBuilder.getConditionType());
@@ -2165,7 +2192,7 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
SValBuilder &SVB = C.getSValBuilder();
SVal Result;
- if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
+ if (std::optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
// Get the current value of the search string pointer, as a char*.
Result = State->getSVal(*SearchStrLoc, CharPtrTy);
diff --git a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
index 45f9a82a9d0a..f02d20d45678 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -24,7 +24,7 @@
#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 <optional>
#include <utility>
using namespace clang;
@@ -472,7 +472,7 @@ bool CastValueChecker::evalCall(const CallEvent &Call,
const CastCheck &Check = Lookup->first;
CallKind Kind = Lookup->second;
- Optional<DefinedOrUnknownSVal> DV;
+ std::optional<DefinedOrUnknownSVal> DV;
switch (Kind) {
case CallKind::Function: {
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 2d2ddcdf3890..3fcf6f435a43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -45,6 +45,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -282,7 +283,7 @@ void ObjCDeallocChecker::checkBeginFunction(
continue;
SVal LVal = State->getLValue(PropImpl->getPropertyIvarDecl(), SelfVal);
- Optional<Loc> LValLoc = LVal.getAs<Loc>();
+ std::optional<Loc> LValLoc = LVal.getAs<Loc>();
if (!LValLoc)
continue;
@@ -953,7 +954,7 @@ ObjCDeallocChecker::getValueReleasedByNillingOut(const ObjCMethodCall &M,
ProgramStateRef State = C.getState();
SVal LVal = State->getLValue(PropIvarDecl, ReceiverVal);
- Optional<Loc> LValLoc = LVal.getAs<Loc>();
+ std::optional<Loc> LValLoc = LVal.getAs<Loc>();
if (!LValLoc)
return nullptr;
@@ -1004,7 +1005,7 @@ bool ObjCDeallocChecker::instanceDeallocIsOnStack(const CheckerContext &C,
return false;
}
-/// Returns true if the ID is a class in which which is known to have
+/// Returns true if the ID is a class in which is known to have
/// a separate teardown lifecycle. In this case, -dealloc warnings
/// about missing releases should be suppressed.
bool ObjCDeallocChecker::classHasSeparateTeardown(
diff --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index ce8d6c879870..9ace1583eb53 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -43,7 +43,7 @@ class ChrootChecker : public Checker<eval::Call, check::PreCall> {
// This bug refers to possibly break out of a chroot() jail.
mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
- const CallDescription Chroot{"chroot", 1}, Chdir{"chdir", 1};
+ const CallDescription Chroot{{"chroot"}, 1}, Chdir{{"chdir"}, 1};
public:
ChrootChecker() {}
diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
index 77a3218f55fb..67962f75f9bf 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -72,26 +72,26 @@ public:
SVal) const;
CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
- {{"clear", 0}, &ContainerModeling::handleClear},
- {{"assign", 2}, &ContainerModeling::handleAssign},
- {{"push_back", 1}, &ContainerModeling::handlePushBack},
- {{"emplace_back", 1}, &ContainerModeling::handlePushBack},
- {{"pop_back", 0}, &ContainerModeling::handlePopBack},
- {{"push_front", 1}, &ContainerModeling::handlePushFront},
- {{"emplace_front", 1}, &ContainerModeling::handlePushFront},
- {{"pop_front", 0}, &ContainerModeling::handlePopFront},
+ {{{"clear"}, 0}, &ContainerModeling::handleClear},
+ {{{"assign"}, 2}, &ContainerModeling::handleAssign},
+ {{{"push_back"}, 1}, &ContainerModeling::handlePushBack},
+ {{{"emplace_back"}, 1}, &ContainerModeling::handlePushBack},
+ {{{"pop_back"}, 0}, &ContainerModeling::handlePopBack},
+ {{{"push_front"}, 1}, &ContainerModeling::handlePushFront},
+ {{{"emplace_front"}, 1}, &ContainerModeling::handlePushFront},
+ {{{"pop_front"}, 0}, &ContainerModeling::handlePopFront},
};
CallDescriptionMap<OneItParamFn> OneIterParamFunctions = {
- {{"insert", 2}, &ContainerModeling::handleInsert},
- {{"emplace", 2}, &ContainerModeling::handleInsert},
- {{"erase", 1}, &ContainerModeling::handleErase},
- {{"erase_after", 1}, &ContainerModeling::handleEraseAfter},
+ {{{"insert"}, 2}, &ContainerModeling::handleInsert},
+ {{{"emplace"}, 2}, &ContainerModeling::handleInsert},
+ {{{"erase"}, 1}, &ContainerModeling::handleErase},
+ {{{"erase_after"}, 1}, &ContainerModeling::handleEraseAfter},
};
CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = {
- {{"erase", 2}, &ContainerModeling::handleErase},
- {{"erase_after", 2}, &ContainerModeling::handleEraseAfter},
+ {{{"erase"}, 2}, &ContainerModeling::handleErase},
+ {{{"erase_after"}, 2}, &ContainerModeling::handleEraseAfter},
};
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 2102f9233bc1..01b662064d7b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -38,17 +38,17 @@ public:
llvm::DenseSet<const VarDecl *> &S;
bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
- SaveAndRestore<bool> inFinally(inEH, true);
+ SaveAndRestore inFinally(inEH, true);
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
}
bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
- SaveAndRestore<bool> inCatch(inEH, true);
+ SaveAndRestore inCatch(inEH, true);
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
}
bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
- SaveAndRestore<bool> inCatch(inEH, true);
+ SaveAndRestore inCatch(inEH, true);
return TraverseStmt(S->getHandlerBlock());
}
@@ -103,8 +103,8 @@ void ReachableCode::computeReachableBlocks() {
static const Expr *
LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
while (Ex) {
- const BinaryOperator *BO =
- dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
+ Ex = Ex->IgnoreParenCasts();
+ const BinaryOperator *BO = dyn_cast<BinaryOperator>(Ex);
if (!BO)
break;
BinaryOperatorKind Op = BO->getOpcode();
@@ -240,7 +240,7 @@ public:
case DeadIncrement:
BugType = "Dead increment";
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Standard:
if (!BugType) BugType = "Dead assignment";
os << "Value stored to '" << *V << "' is never read";
@@ -331,8 +331,7 @@ public:
// Special case: check for assigning null to a pointer.
// This is a common form of defensive programming.
const Expr *RHS =
- LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
- RHS = RHS->IgnoreParenCasts();
+ LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
QualType T = VD->getType();
if (T.isVolatileQualified())
@@ -415,8 +414,7 @@ public:
if (isConstant(E))
return;
- if (const DeclRefExpr *DRE =
- dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
// Special case: check for initialization from constant
// variables.
@@ -438,7 +436,7 @@ public:
PathDiagnosticLocation Loc =
PathDiagnosticLocation::create(V, BR.getSourceManager());
- Report(V, DeadInit, Loc, E->getSourceRange());
+ Report(V, DeadInit, Loc, V->getInit()->getSourceRange());
}
}
}
@@ -450,8 +448,9 @@ private:
bool isConstant(const InitListExpr *Candidate) const {
// We consider init list to be constant if each member of the list can be
// interpreted as constant.
- return llvm::all_of(Candidate->inits(),
- [this](const Expr *Init) { return isConstant(Init); });
+ return llvm::all_of(Candidate->inits(), [this](const Expr *Init) {
+ return isConstant(Init->IgnoreParenCasts());
+ });
}
/// Return true if the given expression can be interpreted as constant
@@ -461,7 +460,7 @@ private:
return true;
// We should also allow defensive initialization of structs, i.e. { 0 }
- if (const auto *ILE = dyn_cast<InitListExpr>(E->IgnoreParenCasts())) {
+ if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
return isConstant(ILE);
}
@@ -504,7 +503,7 @@ public:
// Treat local variables captured by reference in C++ lambdas as escaped.
void findLambdaReferenceCaptures(const LambdaExpr *LE) {
const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
- llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> CaptureFields;
FieldDecl *ThisCaptureField;
LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
@@ -512,14 +511,14 @@ public:
if (!C.capturesVariable())
continue;
- VarDecl *VD = C.getCapturedVar();
+ ValueDecl *VD = C.getCapturedVar();
const FieldDecl *FD = CaptureFields[VD];
- if (!FD)
+ if (!FD || !isa<VarDecl>(VD))
continue;
// If the capture field is a reference type, it is capture-by-reference.
if (FD->getType()->isReferenceType())
- Escaped.insert(VD);
+ Escaped.insert(cast<VarDecl>(VD));
}
}
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
index 47fd57c7db9b..832bb78c4803 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
@@ -41,9 +41,9 @@ class DebugContainerModeling
CheckerContext &) const;
CallDescriptionMap<FnCheck> Callbacks = {
- {{"clang_analyzer_container_begin", 1},
+ {{{"clang_analyzer_container_begin"}, 1},
&DebugContainerModeling::analyzerContainerBegin},
- {{"clang_analyzer_container_end", 1},
+ {{{"clang_analyzer_container_end"}, 1},
&DebugContainerModeling::analyzerContainerEnd},
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
index 6add9a007a87..d05298b42c55 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
@@ -42,11 +42,11 @@ class DebugIteratorModeling
CheckerContext &) const;
CallDescriptionMap<FnCheck> Callbacks = {
- {{"clang_analyzer_iterator_position", 1},
+ {{{"clang_analyzer_iterator_position"}, 1},
&DebugIteratorModeling::analyzerIteratorPosition},
- {{"clang_analyzer_iterator_container", 1},
+ {{{"clang_analyzer_iterator_container"}, 1},
&DebugIteratorModeling::analyzerIteratorContainer},
- {{"clang_analyzer_iterator_validity", 1},
+ {{{"clang_analyzer_iterator_validity"}, 1},
&DebugIteratorModeling::analyzerIteratorValidity},
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index bfd1d4c162ec..cc01e97d3fa2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -67,7 +68,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
return;
SVal Denom = C.getSVal(B->getRHS());
- Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
// Divide-by-undefined handled in the generic checking for uses of
// undefined values.
diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index aaf8cca32b60..6f26842e62c7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -31,6 +31,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -846,7 +847,7 @@ void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M,
return;
}
- Optional<ArrayRef<QualType>> TypeArgs =
+ std::optional<ArrayRef<QualType>> TypeArgs =
(*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
// This case might happen when there is an unspecialized override of a
// specialized method.
@@ -979,7 +980,7 @@ void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M,
if (!Method)
return;
- Optional<ArrayRef<QualType>> TypeArgs =
+ std::optional<ArrayRef<QualType>> TypeArgs =
(*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
if (!TypeArgs)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
index e5088fb266bc..1077ceb6288e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -22,6 +22,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -108,7 +109,7 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
}
// Get the value of the expression to cast.
- const llvm::Optional<DefinedOrUnknownSVal> ValueToCast =
+ const std::optional<DefinedOrUnknownSVal> ValueToCast =
C.getSVal(CE->getSubExpr()).getAs<DefinedOrUnknownSVal>();
// If the value cannot be reasoned about (not even a DefinedOrUnknownSVal),
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
index d8c3d7a4a6a6..265185e64107 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
@@ -22,6 +22,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -132,7 +133,7 @@ void ErrnoChecker::generateErrnoNotCheckedBug(
void ErrnoChecker::checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
CheckerContext &C) const {
- Optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
+ std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
if (!ErrnoLoc)
return;
@@ -206,7 +207,7 @@ void ErrnoChecker::checkPreCall(const CallEvent &Call,
C.getSourceManager().isInSystemHeader(CallF->getLocation()) &&
!isErrno(CallF)) {
if (getErrnoState(C.getState()) == MustBeChecked) {
- Optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
+ std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
assert(ErrnoLoc && "ErrnoLoc should exist if an errno state is set.");
generateErrnoNotCheckedBug(C, setErrnoStateIrrelevant(C.getState()),
ErrnoLoc->getAsRegion(), &Call);
@@ -219,7 +220,7 @@ ProgramStateRef ErrnoChecker::checkRegionChanges(
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
const CallEvent *Call) const {
- Optional<ento::Loc> ErrnoLoc = getErrnoLoc(State);
+ std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(State);
if (!ErrnoLoc)
return State;
const MemRegion *ErrnoRegion = ErrnoLoc->getAsRegion();
@@ -227,12 +228,12 @@ ProgramStateRef ErrnoChecker::checkRegionChanges(
// If 'errno' is invalidated we can not know if it is checked or written into,
// allow read and write without bug reports.
if (llvm::is_contained(Regions, ErrnoRegion))
- return setErrnoStateIrrelevant(State);
+ return clearErrnoState(State);
// Always reset errno state when the system memory space is invalidated.
// The ErrnoRegion is not always found in the list in this case.
if (llvm::is_contained(Regions, ErrnoRegion->getMemorySpace()))
- return setErrnoStateIrrelevant(State);
+ return clearErrnoState(State);
return State;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
index 618f7e97f6e8..51f39c606d5c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
@@ -28,6 +28,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -57,11 +58,11 @@ public:
private:
// FIXME: Names from `ErrnoLocationFuncNames` are used to build this set.
- CallDescriptionSet ErrnoLocationCalls{{"__errno_location", 0, 0},
- {"___errno", 0, 0},
- {"__errno", 0, 0},
- {"_errno", 0, 0},
- {"__error", 0, 0}};
+ CallDescriptionSet ErrnoLocationCalls{{{"__errno_location"}, 0, 0},
+ {{"___errno"}, 0, 0},
+ {{"__errno"}, 0, 0},
+ {{"_errno"}, 0, 0},
+ {{"__error"}, 0, 0}};
};
} // namespace
@@ -207,7 +208,7 @@ namespace clang {
namespace ento {
namespace errno_modeling {
-Optional<SVal> getErrnoValue(ProgramStateRef State) {
+std::optional<SVal> getErrnoValue(ProgramStateRef State) {
const MemRegion *ErrnoR = State->get<ErrnoRegion>();
if (!ErrnoR)
return {};
@@ -239,19 +240,23 @@ ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
return State->set<ErrnoState>(EState);
}
-Optional<Loc> getErrnoLoc(ProgramStateRef State) {
+std::optional<Loc> getErrnoLoc(ProgramStateRef State) {
const MemRegion *ErrnoR = State->get<ErrnoRegion>();
if (!ErrnoR)
return {};
return loc::MemRegionVal{ErrnoR};
}
+ErrnoCheckState getErrnoState(ProgramStateRef State) {
+ return State->get<ErrnoState>();
+}
+
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
return State->set<ErrnoState>(EState);
}
-ErrnoCheckState getErrnoState(ProgramStateRef State) {
- return State->get<ErrnoState>();
+ProgramStateRef clearErrnoState(ProgramStateRef State) {
+ return setErrnoState(State, Irrelevant);
}
bool isErrno(const Decl *D) {
@@ -264,6 +269,12 @@ bool isErrno(const Decl *D) {
return false;
}
+const char *describeErrnoCheckState(ErrnoCheckState CS) {
+ assert(CS == errno_modeling::MustNotBeChecked &&
+ "Errno description not applicable.");
+ return "may be undefined after the call and should not be used";
+}
+
const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
@@ -275,6 +286,53 @@ const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
});
}
+ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
+ CheckerContext &C) {
+ return setErrnoState(State, MustNotBeChecked);
+}
+
+ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
+ NonLoc ErrnoSym) {
+ SValBuilder &SVB = C.getSValBuilder();
+ NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
+ DefinedOrUnknownSVal Cond =
+ SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
+ .castAs<DefinedOrUnknownSVal>();
+ State = State->assume(Cond, true);
+ if (!State)
+ return nullptr;
+ return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
+}
+
+ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
+ CheckerContext &C,
+ const Expr *InvalE) {
+ const MemRegion *ErrnoR = State->get<ErrnoRegion>();
+ if (!ErrnoR)
+ return State;
+ State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
+ C.getLocationContext(), false);
+ if (!State)
+ return nullptr;
+ return setErrnoState(State, MustBeChecked);
+}
+
+const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn) {
+ return getErrnoNoteTag(
+ C, (Twine("Assuming that function '") + Twine(Fn) +
+ Twine("' is successful, in this case the value 'errno' ") +
+ Twine(describeErrnoCheckState(MustNotBeChecked)))
+ .str());
+}
+
+const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C,
+ llvm::StringRef Fn) {
+ return getErrnoNoteTag(
+ C, (Twine("Function '") + Twine(Fn) +
+ Twine("' indicates failure only by setting of 'errno'"))
+ .str());
+}
+
} // namespace errno_modeling
} // namespace ento
} // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
index 3757e25e1afe..2ca3979944e3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
@@ -16,35 +16,43 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include <optional>
namespace clang {
namespace ento {
namespace errno_modeling {
+/// Describe how reads and writes of \c errno are handled by the checker.
enum ErrnoCheckState : unsigned {
/// We do not know anything about 'errno'.
+ /// Read and write is always allowed.
Irrelevant = 0,
/// Value of 'errno' should be checked to find out if a previous function call
/// has failed.
+ /// When this state is set \c errno must be read by the program before a next
+ /// standard function call or other overwrite of \c errno follows, otherwise
+ /// a bug report is emitted.
MustBeChecked = 1,
/// Value of 'errno' is not allowed to be read, it can contain an unspecified
/// value.
+ /// When this state is set \c errno is not allowed to be read by the program
+ /// until it is overwritten or invalidated.
MustNotBeChecked = 2
};
/// Returns the value of 'errno', if 'errno' was found in the AST.
-llvm::Optional<SVal> getErrnoValue(ProgramStateRef State);
+std::optional<SVal> getErrnoValue(ProgramStateRef State);
/// Returns the errno check state, \c Errno_Irrelevant if 'errno' was not found
/// (this is not the only case for that value).
ErrnoCheckState getErrnoState(ProgramStateRef State);
/// Returns the location that points to the \c MemoryRegion where the 'errno'
-/// value is stored. Returns \c None if 'errno' was not found. Otherwise it
-/// always returns a valid memory region in the system global memory space.
-llvm::Optional<Loc> getErrnoLoc(ProgramStateRef State);
+/// value is stored. Returns \c std::nullopt if 'errno' was not found. Otherwise
+/// it always returns a valid memory region in the system global memory space.
+std::optional<Loc> getErrnoLoc(ProgramStateRef State);
/// Set value of 'errno' to any SVal, if possible.
/// The errno check state is set always when the 'errno' value is set.
@@ -60,6 +68,9 @@ ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
/// Set the errno check state, do not modify the errno value.
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState);
+/// Clear state of errno (make it irrelevant).
+ProgramStateRef clearErrnoState(ProgramStateRef State);
+
/// Determine if a `Decl` node related to 'errno'.
/// This is true if the declaration is the errno variable or a function
/// that returns a pointer to the 'errno' value (usually the 'errno' macro is
@@ -67,10 +78,53 @@ ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState);
/// declaration.
bool isErrno(const Decl *D);
+/// Produce a textual description about how \c errno is allowed to be used
+/// (in a \c ErrnoCheckState).
+/// The returned string is insertable into a longer warning message in the form
+/// "the value 'errno' <...>".
+/// Currently only the \c errno_modeling::MustNotBeChecked state is supported,
+/// others are not used by the clients.
+const char *describeErrnoCheckState(ErrnoCheckState CS);
+
/// Create a NoteTag that displays the message if the 'errno' memory region is
/// marked as interesting, and resets the interestingness.
const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message);
+/// Set errno state for the common case when a standard function is successful.
+/// Set \c ErrnoCheckState to \c MustNotBeChecked (the \c errno value is not
+/// affected). At the state transition a note tag created by
+/// \c getNoteTagForStdSuccess can be used.
+ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, CheckerContext &C);
+
+/// Set errno state for the common case when a standard function fails.
+/// Set \c errno value to be not equal to zero and \c ErrnoCheckState to
+/// \c Irrelevant . The irrelevant errno state ensures that no related bug
+/// report is emitted later and no note tag is needed.
+/// \arg \c ErrnoSym Value to be used for \c errno and constrained to be
+/// non-zero.
+ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
+ NonLoc ErrnoSym);
+
+/// Set errno state for the common case when a standard function indicates
+/// failure only by \c errno. Sets \c ErrnoCheckState to \c MustBeChecked, and
+/// invalidates the errno region (clear of previous value).
+/// At the state transition a note tag created by
+/// \c getNoteTagForStdMustBeChecked can be used.
+/// \arg \c InvalE Expression that causes invalidation of \c errno.
+ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
+ CheckerContext &C, const Expr *InvalE);
+
+/// Generate the note tag that can be applied at the state generated by
+/// \c setErrnoForStdSuccess .
+/// \arg \c Fn Name of the (standard) function that is modeled.
+const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn);
+
+/// Generate the note tag that can be applied at the state generated by
+/// \c setErrnoStdMustBeChecked .
+/// \arg \c Fn Name of the (standard) function that is modeled.
+const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C,
+ llvm::StringRef Fn);
+
} // namespace errno_modeling
} // namespace ento
} // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
index 924407ebe2d1..c46ebee0c94f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -69,13 +70,13 @@ private:
using EvalFn = std::function<void(CheckerContext &, const CallEvent &)>;
const CallDescriptionMap<EvalFn> TestCalls{
- {{"ErrnoTesterChecker_setErrno", 1}, &ErrnoTesterChecker::evalSetErrno},
- {{"ErrnoTesterChecker_getErrno", 0}, &ErrnoTesterChecker::evalGetErrno},
- {{"ErrnoTesterChecker_setErrnoIfError", 0},
+ {{{"ErrnoTesterChecker_setErrno"}, 1}, &ErrnoTesterChecker::evalSetErrno},
+ {{{"ErrnoTesterChecker_getErrno"}, 0}, &ErrnoTesterChecker::evalGetErrno},
+ {{{"ErrnoTesterChecker_setErrnoIfError"}, 0},
&ErrnoTesterChecker::evalSetErrnoIfError},
- {{"ErrnoTesterChecker_setErrnoIfErrorRange", 0},
+ {{{"ErrnoTesterChecker_setErrnoIfErrorRange"}, 0},
&ErrnoTesterChecker::evalSetErrnoIfErrorRange},
- {{"ErrnoTesterChecker_setErrnoCheckState", 0},
+ {{{"ErrnoTesterChecker_setErrnoCheckState"}, 0},
&ErrnoTesterChecker::evalSetErrnoCheckState}};
};
@@ -91,7 +92,7 @@ void ErrnoTesterChecker::evalGetErrno(CheckerContext &C,
const CallEvent &Call) {
ProgramStateRef State = C.getState();
- Optional<SVal> ErrnoVal = getErrnoValue(State);
+ std::optional<SVal> ErrnoVal = getErrnoValue(State);
assert(ErrnoVal && "Errno value should be available.");
State =
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), *ErrnoVal);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index ec1b0a70d7d3..355e9c2238a4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ScopedPrinter.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -58,9 +59,9 @@ class ExprInspectionChecker
// Optional parameter `ExprVal` for expression value to be marked interesting.
ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &C,
- Optional<SVal> ExprVal = None) const;
+ std::optional<SVal> ExprVal = std::nullopt) const;
ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR, ExplodedNode *N,
- Optional<SVal> ExprVal = None) const;
+ std::optional<SVal> ExprVal = std::nullopt) const;
template <typename T> void printAndReport(CheckerContext &C, T What) const;
const Expr *getArgExpr(const CallExpr *CE, CheckerContext &C) const;
@@ -115,7 +116,8 @@ bool ExprInspectionChecker::evalCall(const CallEvent &Call,
.Case("clang_analyzer_hashDump",
&ExprInspectionChecker::analyzerHashDump)
.Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote)
- .Case("clang_analyzer_express",
+ .Case("clang_analyzer_express", // This also marks the argument as
+ // interesting.
&ExprInspectionChecker::analyzerExpress)
.StartsWith("clang_analyzer_isTainted",
&ExprInspectionChecker::analyzerIsTainted)
@@ -160,17 +162,18 @@ static const char *getArgumentValueString(const CallExpr *CE,
}
}
-ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
- CheckerContext &C,
- Optional<SVal> ExprVal) const {
+ExplodedNode *
+ExprInspectionChecker::reportBug(llvm::StringRef Msg, CheckerContext &C,
+ std::optional<SVal> ExprVal) const {
ExplodedNode *N = C.generateNonFatalErrorNode();
reportBug(Msg, C.getBugReporter(), N, ExprVal);
return N;
}
-ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
- BugReporter &BR, ExplodedNode *N,
- Optional<SVal> ExprVal) const {
+ExplodedNode *
+ExprInspectionChecker::reportBug(llvm::StringRef Msg, BugReporter &BR,
+ ExplodedNode *N,
+ std::optional<SVal> ExprVal) const {
if (!N)
return nullptr;
@@ -354,8 +357,7 @@ void ExprInspectionChecker::analyzerDumpElementCount(const CallExpr *CE,
if (const auto *TVR = MR->getAs<TypedValueRegion>()) {
ElementTy = TVR->getValueType();
} else {
- ElementTy =
- MR->castAs<SymbolicRegion>()->getSymbol()->getType()->getPointeeType();
+ ElementTy = MR->castAs<SymbolicRegion>()->getPointeeStaticType();
}
assert(!ElementTy->isPointerType());
@@ -466,58 +468,60 @@ void ExprInspectionChecker::analyzerDenote(const CallExpr *CE,
namespace {
class SymbolExpressor
- : public SymExprVisitor<SymbolExpressor, Optional<std::string>> {
+ : public SymExprVisitor<SymbolExpressor, std::optional<std::string>> {
ProgramStateRef State;
public:
SymbolExpressor(ProgramStateRef State) : State(State) {}
- Optional<std::string> lookup(const SymExpr *S) {
+ std::optional<std::string> lookup(const SymExpr *S) {
if (const StringLiteral *const *SLPtr = State->get<DenotedSymbols>(S)) {
const StringLiteral *SL = *SLPtr;
return std::string(SL->getBytes());
}
- return None;
+ return std::nullopt;
}
- Optional<std::string> VisitSymExpr(const SymExpr *S) { return lookup(S); }
+ std::optional<std::string> VisitSymExpr(const SymExpr *S) {
+ return lookup(S);
+ }
- Optional<std::string> VisitSymIntExpr(const SymIntExpr *S) {
- if (Optional<std::string> Str = lookup(S))
+ std::optional<std::string> VisitSymIntExpr(const SymIntExpr *S) {
+ if (std::optional<std::string> Str = lookup(S))
return Str;
- if (Optional<std::string> Str = Visit(S->getLHS()))
+ if (std::optional<std::string> Str = Visit(S->getLHS()))
return (*Str + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " +
std::to_string(S->getRHS().getLimitedValue()) +
(S->getRHS().isUnsigned() ? "U" : ""))
.str();
- return None;
+ return std::nullopt;
}
- Optional<std::string> VisitSymSymExpr(const SymSymExpr *S) {
- if (Optional<std::string> Str = lookup(S))
+ std::optional<std::string> VisitSymSymExpr(const SymSymExpr *S) {
+ if (std::optional<std::string> Str = lookup(S))
return Str;
- if (Optional<std::string> Str1 = Visit(S->getLHS()))
- if (Optional<std::string> Str2 = Visit(S->getRHS()))
+ if (std::optional<std::string> Str1 = Visit(S->getLHS()))
+ if (std::optional<std::string> Str2 = Visit(S->getRHS()))
return (*Str1 + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) +
" " + *Str2)
.str();
- return None;
+ return std::nullopt;
}
- Optional<std::string> VisitUnarySymExpr(const UnarySymExpr *S) {
- if (Optional<std::string> Str = lookup(S))
+ std::optional<std::string> VisitUnarySymExpr(const UnarySymExpr *S) {
+ if (std::optional<std::string> Str = lookup(S))
return Str;
- if (Optional<std::string> Str = Visit(S->getOperand()))
+ if (std::optional<std::string> Str = Visit(S->getOperand()))
return (UnaryOperator::getOpcodeStr(S->getOpcode()) + *Str).str();
- return None;
+ return std::nullopt;
}
- Optional<std::string> VisitSymbolCast(const SymbolCast *S) {
- if (Optional<std::string> Str = lookup(S))
+ std::optional<std::string> VisitSymbolCast(const SymbolCast *S) {
+ if (std::optional<std::string> Str = lookup(S))
return Str;
- if (Optional<std::string> Str = Visit(S->getOperand()))
+ if (std::optional<std::string> Str = Visit(S->getOperand()))
return (Twine("(") + S->getType().getAsString() + ")" + *Str).str();
- return None;
+ return std::nullopt;
}
};
} // namespace
@@ -531,14 +535,14 @@ void ExprInspectionChecker::analyzerExpress(const CallExpr *CE,
SVal ArgVal = C.getSVal(CE->getArg(0));
SymbolRef Sym = ArgVal.getAsSymbol();
if (!Sym) {
- reportBug("Not a symbol", C);
+ reportBug("Not a symbol", C, ArgVal);
return;
}
SymbolExpressor V(C.getState());
auto Str = V.Visit(Sym);
if (!Str) {
- reportBug("Unable to express", C);
+ reportBug("Unable to express", C, ArgVal);
return;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
index eb3b89ee6c5c..65ff1be8ec05 100644
--- a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
@@ -101,6 +101,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -300,7 +301,7 @@ getFuchsiaHandleSymbols(QualType QT, SVal Arg, ProgramStateRef State) {
}
} else {
assert(PtrToHandleLevel == 1);
- if (Optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
+ if (std::optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
SymbolRef Sym = State->getSVal(*ArgLoc).getAsSymbol();
if (Sym) {
return {Sym};
diff --git a/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
index dbfdff4d2a3b..43d2eeeb4b27 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -258,7 +259,7 @@ SVal GTestChecker::getAssertionResultSuccessFieldValue(
if (!SuccessField)
return UnknownVal();
- Optional<Loc> FieldLoc =
+ std::optional<Loc> FieldLoc =
State->getLValue(SuccessField, Instance).getAs<Loc>();
if (!FieldLoc)
return UnknownVal();
diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index f0a114801dda..f6e2f59d5697 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -30,6 +30,7 @@
#include <limits>
#include <memory>
+#include <optional>
#include <utility>
#define DEBUG_TYPE "taint-checker"
@@ -124,16 +125,17 @@ SVal getPointeeOf(const CheckerContext &C, Loc LValue) {
}
/// Given a pointer/reference argument, return the value it refers to.
-Optional<SVal> getPointeeOf(const CheckerContext &C, SVal Arg) {
+std::optional<SVal> getPointeeOf(const CheckerContext &C, SVal Arg) {
if (auto LValue = Arg.getAs<Loc>())
return getPointeeOf(C, *LValue);
- return None;
+ return std::nullopt;
}
/// Given a pointer, return the SVal of its pointee or if it is tainted,
/// otherwise return the pointer's SVal if tainted.
/// Also considers stdin as a taint source.
-Optional<SVal> getTaintedPointeeOrPointer(const CheckerContext &C, SVal Arg) {
+std::optional<SVal> getTaintedPointeeOrPointer(const CheckerContext &C,
+ SVal Arg) {
const ProgramStateRef State = C.getState();
if (auto Pointee = getPointeeOf(C, Arg))
@@ -147,7 +149,7 @@ Optional<SVal> getTaintedPointeeOrPointer(const CheckerContext &C, SVal Arg) {
if (isStdin(Arg, C.getASTContext()))
return Arg;
- return None;
+ return std::nullopt;
}
bool isTaintedOrPointsToTainted(const Expr *E, const ProgramStateRef &State,
@@ -161,7 +163,8 @@ bool isTaintedOrPointsToTainted(const Expr *E, const ProgramStateRef &State,
class ArgSet {
public:
ArgSet() = default;
- ArgSet(ArgVecTy &&DiscreteArgs, Optional<ArgIdxTy> VariadicIndex = None)
+ ArgSet(ArgVecTy &&DiscreteArgs,
+ std::optional<ArgIdxTy> VariadicIndex = std::nullopt)
: DiscreteArgs(std::move(DiscreteArgs)),
VariadicIndex(std::move(VariadicIndex)) {}
@@ -176,7 +179,7 @@ public:
private:
ArgVecTy DiscreteArgs;
- Optional<ArgIdxTy> VariadicIndex;
+ std::optional<ArgIdxTy> VariadicIndex;
};
/// A struct used to specify taint propagation rules for a function.
@@ -197,12 +200,12 @@ class GenericTaintRule {
ArgSet PropDstArgs;
/// A message that explains why the call is sensitive to taint.
- Optional<StringRef> SinkMsg;
+ std::optional<StringRef> SinkMsg;
GenericTaintRule() = default;
GenericTaintRule(ArgSet &&Sink, ArgSet &&Filter, ArgSet &&Src, ArgSet &&Dst,
- Optional<StringRef> SinkMsg = None)
+ std::optional<StringRef> SinkMsg = std::nullopt)
: SinkArgs(std::move(Sink)), FilterArgs(std::move(Filter)),
PropSrcArgs(std::move(Src)), PropDstArgs(std::move(Dst)),
SinkMsg(SinkMsg) {}
@@ -211,7 +214,7 @@ public:
/// Make a rule that reports a warning if taint reaches any of \p FilterArgs
/// arguments.
static GenericTaintRule Sink(ArgSet &&SinkArgs,
- Optional<StringRef> Msg = None) {
+ std::optional<StringRef> Msg = std::nullopt) {
return {std::move(SinkArgs), {}, {}, {}, Msg};
}
@@ -232,9 +235,9 @@ public:
}
/// Make a rule that taints all PropDstArgs if any of PropSrcArgs is tainted.
- static GenericTaintRule SinkProp(ArgSet &&SinkArgs, ArgSet &&SrcArgs,
- ArgSet &&DstArgs,
- Optional<StringRef> Msg = None) {
+ static GenericTaintRule
+ SinkProp(ArgSet &&SinkArgs, ArgSet &&SrcArgs, ArgSet &&DstArgs,
+ std::optional<StringRef> Msg = std::nullopt) {
return {
std::move(SinkArgs), {}, std::move(SrcArgs), std::move(DstArgs), Msg};
}
@@ -302,7 +305,7 @@ struct GenericTaintRuleParser {
TaintConfiguration &&Config) const;
private:
- using NamePartsTy = llvm::SmallVector<SmallString<32>, 2>;
+ using NamePartsTy = llvm::SmallVector<StringRef, 2>;
/// Validate part of the configuration, which contains a list of argument
/// indexes.
@@ -359,8 +362,8 @@ private:
// TODO: Remove separation to simplify matching logic once CallDescriptions
// are more expressive.
- mutable Optional<RuleLookupTy> StaticTaintRules;
- mutable Optional<RuleLookupTy> DynamicTaintRules;
+ mutable std::optional<RuleLookupTy> StaticTaintRules;
+ mutable std::optional<RuleLookupTy> DynamicTaintRules;
};
} // end of anonymous namespace
@@ -442,10 +445,8 @@ GenericTaintRuleParser::parseNameParts(const Config &C) {
if (!C.Scope.empty()) {
// If the Scope argument contains multiple "::" parts, those are considered
// namespace identifiers.
- llvm::SmallVector<StringRef, 2> NSParts;
- StringRef{C.Scope}.split(NSParts, "::", /*MaxSplit*/ -1,
+ StringRef{C.Scope}.split(NameParts, "::", /*MaxSplit*/ -1,
/*KeepEmpty*/ false);
- NameParts.append(NSParts.begin(), NSParts.end());
}
NameParts.emplace_back(C.Name);
return NameParts;
@@ -456,10 +457,7 @@ void GenericTaintRuleParser::consumeRulesFromConfig(const Config &C,
GenericTaintRule &&Rule,
RulesContTy &Rules) {
NamePartsTy NameParts = parseNameParts(C);
- llvm::SmallVector<const char *, 2> CallDescParts{NameParts.size()};
- llvm::transform(NameParts, CallDescParts.begin(),
- [](SmallString<32> &S) { return S.c_str(); });
- Rules.emplace_back(CallDescription(CallDescParts), std::move(Rule));
+ Rules.emplace_back(CallDescription(NameParts), std::move(Rule));
}
void GenericTaintRuleParser::parseConfig(const std::string &Option,
@@ -485,10 +483,12 @@ void GenericTaintRuleParser::parseConfig(const std::string &Option,
validateArgVector(Option, P.DstArgs);
bool IsSrcVariadic = P.VarType == TaintConfiguration::VariadicType::Src;
bool IsDstVariadic = P.VarType == TaintConfiguration::VariadicType::Dst;
- Optional<ArgIdxTy> JustVarIndex = P.VarIndex;
+ std::optional<ArgIdxTy> JustVarIndex = P.VarIndex;
- ArgSet SrcDesc(std::move(P.SrcArgs), IsSrcVariadic ? JustVarIndex : None);
- ArgSet DstDesc(std::move(P.DstArgs), IsDstVariadic ? JustVarIndex : None);
+ ArgSet SrcDesc(std::move(P.SrcArgs),
+ IsSrcVariadic ? JustVarIndex : std::nullopt);
+ ArgSet DstDesc(std::move(P.DstArgs),
+ IsDstVariadic ? JustVarIndex : std::nullopt);
consumeRulesFromConfig(
P, GenericTaintRule::Prop(std::move(SrcDesc), std::move(DstDesc)), Rules);
@@ -527,128 +527,128 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
RulesConstructionTy GlobalCRules{
// Sources
- {{"fdopen"}, TR::Source({{ReturnValueIndex}})},
- {{"fopen"}, TR::Source({{ReturnValueIndex}})},
- {{"freopen"}, TR::Source({{ReturnValueIndex}})},
- {{"getch"}, TR::Source({{ReturnValueIndex}})},
- {{"getchar"}, TR::Source({{ReturnValueIndex}})},
- {{"getchar_unlocked"}, TR::Source({{ReturnValueIndex}})},
- {{"gets"}, TR::Source({{0}, ReturnValueIndex})},
- {{"gets_s"}, TR::Source({{0}, ReturnValueIndex})},
- {{"scanf"}, TR::Source({{}, 1})},
- {{"scanf_s"}, TR::Source({{}, {1}})},
- {{"wgetch"}, TR::Source({{}, ReturnValueIndex})},
+ {{{"fdopen"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"fopen"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"freopen"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getch"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getchar"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getchar_unlocked"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"gets"}}, TR::Source({{0}, ReturnValueIndex})},
+ {{{"gets_s"}}, TR::Source({{0}, ReturnValueIndex})},
+ {{{"scanf"}}, TR::Source({{}, 1})},
+ {{{"scanf_s"}}, TR::Source({{}, {1}})},
+ {{{"wgetch"}}, TR::Source({{}, ReturnValueIndex})},
// Sometimes the line between taint sources and propagators is blurry.
// _IO_getc is choosen to be a source, but could also be a propagator.
// This way it is simpler, as modeling it as a propagator would require
// to model the possible sources of _IO_FILE * values, which the _IO_getc
// function takes as parameters.
- {{"_IO_getc"}, TR::Source({{ReturnValueIndex}})},
- {{"getcwd"}, TR::Source({{0, ReturnValueIndex}})},
- {{"getwd"}, TR::Source({{0, ReturnValueIndex}})},
- {{"readlink"}, TR::Source({{1, ReturnValueIndex}})},
- {{"readlinkat"}, TR::Source({{2, ReturnValueIndex}})},
- {{"get_current_dir_name"}, TR::Source({{ReturnValueIndex}})},
- {{"gethostname"}, TR::Source({{0}})},
- {{"getnameinfo"}, TR::Source({{2, 4}})},
- {{"getseuserbyname"}, TR::Source({{1, 2}})},
- {{"getgroups"}, TR::Source({{1, ReturnValueIndex}})},
- {{"getlogin"}, TR::Source({{ReturnValueIndex}})},
- {{"getlogin_r"}, TR::Source({{0}})},
+ {{{"_IO_getc"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getcwd"}}, TR::Source({{0, ReturnValueIndex}})},
+ {{{"getwd"}}, TR::Source({{0, ReturnValueIndex}})},
+ {{{"readlink"}}, TR::Source({{1, ReturnValueIndex}})},
+ {{{"readlinkat"}}, TR::Source({{2, ReturnValueIndex}})},
+ {{{"get_current_dir_name"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"gethostname"}}, TR::Source({{0}})},
+ {{{"getnameinfo"}}, TR::Source({{2, 4}})},
+ {{{"getseuserbyname"}}, TR::Source({{1, 2}})},
+ {{{"getgroups"}}, TR::Source({{1, ReturnValueIndex}})},
+ {{{"getlogin"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getlogin_r"}}, TR::Source({{0}})},
// Props
- {{"atoi"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"atol"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"atoll"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fgetc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fgetln"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fgets"}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
- {{"fscanf"}, TR::Prop({{0}}, {{}, 2})},
- {{"fscanf_s"}, TR::Prop({{0}}, {{}, {2}})},
- {{"sscanf"}, TR::Prop({{0}}, {{}, 2})},
-
- {{"getc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"getc_unlocked"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"getdelim"}, TR::Prop({{3}}, {{0}})},
- {{"getline"}, TR::Prop({{2}}, {{0}})},
- {{"getw"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"pread"}, TR::Prop({{0, 1, 2, 3}}, {{1, ReturnValueIndex}})},
- {{"read"}, TR::Prop({{0, 2}}, {{1, ReturnValueIndex}})},
- {{"strchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"tolower"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"toupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fread"}, TR::Prop({{3}}, {{0, ReturnValueIndex}})},
- {{"recv"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
- {{"recvfrom"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
-
- {{"ttyname"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"ttyname_r"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
-
- {{"basename"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"dirname"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fnmatch"}, TR::Prop({{1}}, {{ReturnValueIndex}})},
- {{"memchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"memrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"rawmemchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
-
- {{"mbtowc"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{"wctomb"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{"wcwidth"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
-
- {{"memcmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"memcpy"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{"memmove"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{{"atoi"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"atol"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"atoll"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fgetc"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fgetln"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fgets"}}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
+ {{{"fscanf"}}, TR::Prop({{0}}, {{}, 2})},
+ {{{"fscanf_s"}}, TR::Prop({{0}}, {{}, {2}})},
+ {{{"sscanf"}}, TR::Prop({{0}}, {{}, 2})},
+
+ {{{"getc"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"getc_unlocked"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"getdelim"}}, TR::Prop({{3}}, {{0}})},
+ {{{"getline"}}, TR::Prop({{2}}, {{0}})},
+ {{{"getw"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"pread"}}, TR::Prop({{0, 1, 2, 3}}, {{1, ReturnValueIndex}})},
+ {{{"read"}}, TR::Prop({{0, 2}}, {{1, ReturnValueIndex}})},
+ {{{"strchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strrchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"tolower"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"toupper"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fread"}}, TR::Prop({{3}}, {{0, ReturnValueIndex}})},
+ {{{"recv"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+ {{{"recvfrom"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+
+ {{{"ttyname"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"ttyname_r"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+
+ {{{"basename"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"dirname"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fnmatch"}}, TR::Prop({{1}}, {{ReturnValueIndex}})},
+ {{{"memchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"memrchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"rawmemchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+
+ {{{"mbtowc"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{{"wctomb"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{{"wcwidth"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+
+ {{{"memcmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"memcpy"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{{"memmove"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
// If memmem was called with a tainted needle and the search was
// successful, that would mean that the value pointed by the return value
// has the same content as the needle. If we choose to go by the policy of
// content equivalence implies taintedness equivalence, that would mean
// haystack should be considered a propagation source argument.
- {{"memmem"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"memmem"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
// The comment for memmem above also applies to strstr.
- {{"strstr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strcasestr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strstr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strcasestr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strchrnul"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strchrnul"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"index"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"rindex"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"index"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"rindex"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
// FIXME: In case of arrays, only the first element of the array gets
// tainted.
- {{"qsort"}, TR::Prop({{0}}, {{0}})},
- {{"qsort_r"}, TR::Prop({{0}}, {{0}})},
-
- {{"strcmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"strcasecmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"strncmp"}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
- {{"strncasecmp"}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
- {{"strspn"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"strcspn"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"strpbrk"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strndup"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strndupa"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strlen"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strnlen"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strtol"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
- {{"strtoll"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
- {{"strtoul"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
- {{"strtoull"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
-
- {{"isalnum"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isalpha"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isascii"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isblank"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"iscntrl"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isdigit"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isgraph"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"islower"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isprint"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"ispunct"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isspace"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isxdigit"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"qsort"}}, TR::Prop({{0}}, {{0}})},
+ {{{"qsort_r"}}, TR::Prop({{0}}, {{0}})},
+
+ {{{"strcmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"strcasecmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"strncmp"}}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
+ {{{"strncasecmp"}}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
+ {{{"strspn"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"strcspn"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"strpbrk"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strndup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strndupa"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strlen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strnlen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strtol"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+ {{{"strtoll"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+ {{{"strtoul"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+ {{{"strtoull"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+
+ {{{"isalnum"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isalpha"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isascii"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isblank"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"iscntrl"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isdigit"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isgraph"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"islower"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isprint"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"ispunct"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isspace"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isupper"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isxdigit"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncat)}},
TR::Prop({{1, 2}}, {{0, ReturnValueIndex}})},
@@ -656,37 +656,40 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
TR::Prop({{1, 2}}, {{0}})},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcat)}},
TR::Prop({{1, 2}}, {{0}})},
- {{CDF_MaybeBuiltin, {"snprintf"}},
+ {{CDF_MaybeBuiltin, {{"snprintf"}}},
TR::Prop({{1}, 3}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"sprintf"}},
+ {{CDF_MaybeBuiltin, {{"sprintf"}}},
TR::Prop({{1}, 2}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"strcpy"}},
+ {{CDF_MaybeBuiltin, {{"strcpy"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"stpcpy"}},
+ {{CDF_MaybeBuiltin, {{"stpcpy"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"strcat"}},
+ {{CDF_MaybeBuiltin, {{"strcat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"strdup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"strdupa"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"wcsdup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {{"strdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {{"strdupa"}}},
+ TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {{"wcsdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
// Sinks
- {{"system"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"popen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execl"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execle"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execlp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execvp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execvP"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execve"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"dlopen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{CDF_MaybeBuiltin, {"malloc"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"calloc"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"alloca"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"memccpy"}}, TR::Sink({{3}}, MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"realloc"}}, TR::Sink({{1}}, MsgTaintedBufferSize)},
- {{{"setproctitle"}}, TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
- {{{"setproctitle_fast"}},
+ {{{"system"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"popen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execl"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execle"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execlp"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execvp"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execvP"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execve"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"dlopen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{CDF_MaybeBuiltin, {{"malloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {{"calloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {{"alloca"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {{"memccpy"}}},
+ TR::Sink({{3}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {{"realloc"}}},
+ TR::Sink({{1}}, MsgTaintedBufferSize)},
+ {{{{"setproctitle"}}}, TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
+ {{{{"setproctitle_fast"}}},
TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
// SinkProps
@@ -702,7 +705,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrndup)}},
TR::SinkProp({{1}}, {{0, 1}}, {{ReturnValueIndex}},
MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"bcopy"}},
+ {{CDF_MaybeBuiltin, {{"bcopy"}}},
TR::SinkProp({{2}}, {{0, 2}}, {{1}}, MsgTaintedBufferSize)}};
// `getenv` returns taint only in untrusted environments.
@@ -710,7 +713,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
// void setproctitle_init(int argc, char *argv[], char *envp[])
GlobalCRules.push_back(
{{{"setproctitle_init"}}, TR::Sink({{1, 2}}, MsgCustomSink)});
- GlobalCRules.push_back({{"getenv"}, TR::Source({{ReturnValueIndex}})});
+ GlobalCRules.push_back({{{"getenv"}}, TR::Source({{ReturnValueIndex}})});
}
StaticTaintRules.emplace(std::make_move_iterator(GlobalCRules.begin()),
@@ -723,7 +726,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
std::string Option{"Config"};
StringRef ConfigFile =
Mgr->getAnalyzerOptions().getCheckerStringOption(this, Option);
- llvm::Optional<TaintConfiguration> Config =
+ std::optional<TaintConfiguration> Config =
getConfiguration<TaintConfiguration>(*Mgr, this, Option, ConfigFile);
if (!Config) {
// We don't have external taint config, no parsing required.
@@ -899,7 +902,7 @@ bool GenericTaintRule::UntrustedEnv(CheckerContext &C) {
bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg,
CheckerContext &C) const {
assert(E);
- Optional<SVal> TaintedSVal{getTaintedPointeeOrPointer(C, C.getSVal(E))};
+ std::optional<SVal> TaintedSVal{getTaintedPointeeOrPointer(C, C.getSVal(E))};
if (!TaintedSVal)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index ce334b18386e..b3f2d7f4d268 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -379,8 +379,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
IvarToPropMapTy IvarToPopertyMap;
ObjCInterfaceDecl::PropertyMap PropMap;
- ObjCInterfaceDecl::PropertyDeclOrder PropOrder;
- InterfaceD->collectPropertiesToImplement(PropMap, PropOrder);
+ InterfaceD->collectPropertiesToImplement(PropMap);
for (ObjCInterfaceDecl::PropertyMap::iterator
I = PropMap.begin(), E = PropMap.end(); I != E; ++I) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index 9870746cbe0c..bca10ec96cea 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -29,6 +29,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/Support/Unicode.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -1004,7 +1005,7 @@ NonLocalizedStringBRVisitor::VisitNode(const ExplodedNode *Succ,
if (Satisfied)
return nullptr;
- Optional<StmtPoint> Point = Succ->getLocation().getAs<StmtPoint>();
+ std::optional<StmtPoint> Point = Succ->getLocation().getAs<StmtPoint>();
if (!Point)
return nullptr;
@@ -1141,7 +1142,7 @@ void EmptyLocalizationContextChecker::MethodCrawler::VisitObjCMessageExpr(
SE = Mgr.getSourceManager().getSLocEntry(SLInfo.first);
}
- llvm::Optional<llvm::MemoryBufferRef> BF =
+ std::optional<llvm::MemoryBufferRef> BF =
Mgr.getSourceManager().getBufferOrNone(SLInfo.first, SL);
if (!BF)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 139bc0e99d78..153a0a51e980 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -30,6 +30,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -86,7 +87,7 @@ class MIGChecker : public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
#undef CALL
};
- CallDescription OsRefRetain{"os_ref_retain", 1};
+ CallDescription OsRefRetain{{"os_ref_retain"}, 1};
void checkReturnAux(const ReturnStmt *RS, CheckerContext &C) const;
@@ -157,7 +158,7 @@ static bool isInMIGCall(CheckerContext &C) {
const Decl *D = SFC->getDecl();
- if (Optional<AnyCall> AC = AnyCall::forDecl(D)) {
+ if (std::optional<AnyCall> AC = AnyCall::forDecl(D)) {
// Even though there's a Sema warning when the return type of an annotated
// function is not a kern_return_t, this warning isn't an error, so we need
// an extra check here.
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 635eb00e4ca9..c1b85ace3e2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -209,7 +210,7 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr,
ProgramStateRef State = C.getState();
SVal ArgV = C.getSVal(Expr);
- if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
StoreManager& SM = C.getStoreManager();
SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
if (sym)
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index adedc9c30fad..f05cd9227b65 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -86,6 +86,7 @@
#include "llvm/Support/raw_ostream.h"
#include <climits>
#include <functional>
+#include <optional>
#include <utility>
using namespace clang;
@@ -220,10 +221,10 @@ 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,
- Optional<SVal> RetVal = None);
+static ProgramStateRef
+MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
+ AllocationFamily Family,
+ std::optional<SVal> RetVal = std::nullopt);
//===----------------------------------------------------------------------===//
// The modeling of memory reallocation.
@@ -391,10 +392,10 @@ private:
const CallEvent &Call, CheckerContext &C)>;
const CallDescriptionMap<CheckFn> FreeingMemFnMap{
- {{"free", 1}, &MallocChecker::checkFree},
- {{"if_freenameindex", 1}, &MallocChecker::checkIfFreeNameIndex},
- {{"kfree", 1}, &MallocChecker::checkFree},
- {{"g_free", 1}, &MallocChecker::checkFree},
+ {{{"free"}, 1}, &MallocChecker::checkFree},
+ {{{"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
+ {{{"kfree"}, 1}, &MallocChecker::checkFree},
+ {{{"g_free"}, 1}, &MallocChecker::checkFree},
};
bool isFreeingCall(const CallEvent &Call) const;
@@ -403,61 +404,60 @@ private:
friend class NoOwnershipChangeVisitor;
CallDescriptionMap<CheckFn> AllocatingMemFnMap{
- {{"alloca", 1}, &MallocChecker::checkAlloca},
- {{"_alloca", 1}, &MallocChecker::checkAlloca},
- {{"malloc", 1}, &MallocChecker::checkBasicAlloc},
- {{"malloc", 3}, &MallocChecker::checkKernelMalloc},
- {{"calloc", 2}, &MallocChecker::checkCalloc},
- {{"valloc", 1}, &MallocChecker::checkBasicAlloc},
- {{CDF_MaybeBuiltin, "strndup", 2}, &MallocChecker::checkStrdup},
- {{CDF_MaybeBuiltin, "strdup", 1}, &MallocChecker::checkStrdup},
- {{"_strdup", 1}, &MallocChecker::checkStrdup},
- {{"kmalloc", 2}, &MallocChecker::checkKernelMalloc},
- {{"if_nameindex", 1}, &MallocChecker::checkIfNameIndex},
- {{CDF_MaybeBuiltin, "wcsdup", 1}, &MallocChecker::checkStrdup},
- {{CDF_MaybeBuiltin, "_wcsdup", 1}, &MallocChecker::checkStrdup},
- {{"g_malloc", 1}, &MallocChecker::checkBasicAlloc},
- {{"g_malloc0", 1}, &MallocChecker::checkGMalloc0},
- {{"g_try_malloc", 1}, &MallocChecker::checkBasicAlloc},
- {{"g_try_malloc0", 1}, &MallocChecker::checkGMalloc0},
- {{"g_memdup", 2}, &MallocChecker::checkGMemdup},
- {{"g_malloc_n", 2}, &MallocChecker::checkGMallocN},
- {{"g_malloc0_n", 2}, &MallocChecker::checkGMallocN0},
- {{"g_try_malloc_n", 2}, &MallocChecker::checkGMallocN},
- {{"g_try_malloc0_n", 2}, &MallocChecker::checkGMallocN0},
+ {{{"alloca"}, 1}, &MallocChecker::checkAlloca},
+ {{{"_alloca"}, 1}, &MallocChecker::checkAlloca},
+ {{{"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
+ {{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
+ {{{"calloc"}, 2}, &MallocChecker::checkCalloc},
+ {{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
+ {{CDF_MaybeBuiltin, {"strndup"}, 2}, &MallocChecker::checkStrdup},
+ {{CDF_MaybeBuiltin, {"strdup"}, 1}, &MallocChecker::checkStrdup},
+ {{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
+ {{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
+ {{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
+ {{CDF_MaybeBuiltin, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
+ {{CDF_MaybeBuiltin, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
+ {{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
+ {{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
+ {{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
+ {{{"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
+ {{{"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
+ {{{"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
+ {{{"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
+ {{{"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
+ {{{"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
};
CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
- {{"realloc", 2},
+ {{{"realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
- {{"reallocf", 2},
+ {{{"reallocf"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, true)},
- {{"g_realloc", 2},
+ {{{"g_realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
- {{"g_try_realloc", 2},
+ {{{"g_try_realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
- {{"g_realloc_n", 3}, &MallocChecker::checkReallocN},
- {{"g_try_realloc_n", 3}, &MallocChecker::checkReallocN},
+ {{{"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
+ {{{"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
};
bool isMemCall(const CallEvent &Call) const;
// TODO: Remove mutable by moving the initializtaion to the registry function.
- mutable Optional<uint64_t> KernelZeroFlagVal;
+ mutable std::optional<uint64_t> KernelZeroFlagVal;
- using KernelZeroSizePtrValueTy = Optional<int>;
+ using KernelZeroSizePtrValueTy = std::optional<int>;
/// Store the value of macro called `ZERO_SIZE_PTR`.
/// The value is initialized at first use, before first use the outer
/// Optional is empty, afterwards it contains another Optional that indicates
/// if the macro value could be determined, and if yes the value itself.
- mutable Optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
+ mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
/// Process C++ operator new()'s allocation, which is the part of C++
/// new-expression that goes before the constructor.
- LLVM_NODISCARD
- ProgramStateRef processNewAllocation(const CXXAllocatorCall &Call,
- CheckerContext &C,
- AllocationFamily Family) const;
+ [[nodiscard]] ProgramStateRef
+ processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C,
+ AllocationFamily Family) const;
/// Perform a zero-allocation check.
///
@@ -467,11 +467,10 @@ private:
/// 0.
/// \param [in] RetVal Specifies the newly allocated pointer value;
/// if unspecified, the value of expression \p E is used.
- LLVM_NODISCARD
- static ProgramStateRef ProcessZeroAllocCheck(const CallEvent &Call,
- const unsigned IndexOfSizeArg,
- ProgramStateRef State,
- Optional<SVal> RetVal = None);
+ [[nodiscard]] static ProgramStateRef
+ ProcessZeroAllocCheck(const CallEvent &Call, const unsigned IndexOfSizeArg,
+ ProgramStateRef State,
+ std::optional<SVal> RetVal = std::nullopt);
/// Model functions with the ownership_returns attribute.
///
@@ -489,10 +488,9 @@ private:
/// \param [in] Att The ownership_returns attribute.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after allocation.
- LLVM_NODISCARD
- ProgramStateRef MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
- const OwnershipAttr *Att,
- ProgramStateRef State) const;
+ [[nodiscard]] ProgramStateRef
+ MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
+ const OwnershipAttr *Att, ProgramStateRef State) const;
/// Models memory allocation.
///
@@ -503,11 +501,9 @@ private:
/// malloc leaves it undefined.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after allocation.
- LLVM_NODISCARD
- static ProgramStateRef MallocMemAux(CheckerContext &C, const CallEvent &Call,
- const Expr *SizeEx, SVal Init,
- ProgramStateRef State,
- AllocationFamily Family);
+ [[nodiscard]] static ProgramStateRef
+ MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,
+ SVal Init, ProgramStateRef State, AllocationFamily Family);
/// Models memory allocation.
///
@@ -518,16 +514,13 @@ private:
/// malloc leaves it undefined.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after allocation.
- LLVM_NODISCARD
- static ProgramStateRef MallocMemAux(CheckerContext &C, const CallEvent &Call,
- SVal Size, SVal Init,
- ProgramStateRef State,
- AllocationFamily Family);
+ [[nodiscard]] static ProgramStateRef
+ MallocMemAux(CheckerContext &C, const CallEvent &Call, SVal Size, SVal Init,
+ ProgramStateRef State, AllocationFamily Family);
// Check if this malloc() for special flags. At present that means M_ZERO or
// __GFP_ZERO (in which case, treat it like calloc).
- LLVM_NODISCARD
- llvm::Optional<ProgramStateRef>
+ [[nodiscard]] std::optional<ProgramStateRef>
performKernelMalloc(const CallEvent &Call, CheckerContext &C,
const ProgramStateRef &State) const;
@@ -548,10 +541,10 @@ private:
/// \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.
- LLVM_NODISCARD
- ProgramStateRef FreeMemAttr(CheckerContext &C, const CallEvent &Call,
- const OwnershipAttr *Att,
- ProgramStateRef State) const;
+ [[nodiscard]] ProgramStateRef FreeMemAttr(CheckerContext &C,
+ const CallEvent &Call,
+ const OwnershipAttr *Att,
+ ProgramStateRef State) const;
/// Models memory deallocation.
///
@@ -572,12 +565,10 @@ private:
/// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
/// we're modeling returns with Null on failure.
/// \returns The ProgramState right after deallocation.
- LLVM_NODISCARD
- ProgramStateRef FreeMemAux(CheckerContext &C, const CallEvent &Call,
- ProgramStateRef State, unsigned Num, bool Hold,
- bool &IsKnownToBeAllocated,
- AllocationFamily Family,
- bool ReturnsNullOnFailure = false) const;
+ [[nodiscard]] ProgramStateRef
+ FreeMemAux(CheckerContext &C, const CallEvent &Call, ProgramStateRef State,
+ unsigned Num, bool Hold, bool &IsKnownToBeAllocated,
+ AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
/// Models memory deallocation.
///
@@ -598,12 +589,10 @@ private:
/// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
/// we're modeling returns with Null on failure.
/// \returns The ProgramState right after deallocation.
- LLVM_NODISCARD
- ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
- const CallEvent &Call, ProgramStateRef State,
- bool Hold, bool &IsKnownToBeAllocated,
- AllocationFamily Family,
- bool ReturnsNullOnFailure = false) const;
+ [[nodiscard]] ProgramStateRef
+ FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,
+ ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
+ AllocationFamily Family, 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
@@ -618,29 +607,27 @@ private:
/// \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.
- LLVM_NODISCARD
- ProgramStateRef ReallocMemAux(CheckerContext &C, const CallEvent &Call,
- bool ShouldFreeOnFail, ProgramStateRef State,
- AllocationFamily Family,
- bool SuffixWithN = false) const;
+ [[nodiscard]] ProgramStateRef
+ ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail,
+ ProgramStateRef State, AllocationFamily Family,
+ 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.
- LLVM_NODISCARD
- static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
- const Expr *BlockBytes);
+ [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C,
+ const Expr *Blocks,
+ const Expr *BlockBytes);
/// Models zero initialized array allocation.
///
/// \param [in] Call The expression that reallocated memory
/// \param [in] State The \c ProgramState right before reallocation.
/// \returns The ProgramState right after allocation.
- LLVM_NODISCARD
- static ProgramStateRef CallocMem(CheckerContext &C, const CallEvent &Call,
- ProgramStateRef State);
+ [[nodiscard]] static ProgramStateRef
+ CallocMem(CheckerContext &C, const CallEvent &Call, ProgramStateRef State);
/// See if deallocation happens in a suspicious context. If so, escape the
/// pointers that otherwise would have been deallocated and return true.
@@ -673,12 +660,11 @@ private:
SymbolRef &EscapingSymbol) const;
/// Implementation of the checkPointerEscape callbacks.
- LLVM_NODISCARD
- ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
- const InvalidatedSymbols &Escaped,
- const CallEvent *Call,
- PointerEscapeKind Kind,
- bool IsConstPointerEscape) const;
+ [[nodiscard]] ProgramStateRef
+ checkPointerEscapeAux(ProgramStateRef State,
+ 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;
@@ -687,11 +673,11 @@ private:
/// Tells if a given family/call/symbol is tracked by the current checker.
/// Sets CheckKind to the kind of the checker responsible for this
/// family/call/symbol.
- Optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
- bool IsALeakCheck = false) const;
+ std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
+ bool IsALeakCheck = false) const;
- Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
- bool IsALeakCheck = false) const;
+ std::optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
+ bool IsALeakCheck = false) const;
///@}
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
@@ -870,7 +856,7 @@ protected:
// If a variable is dead (is not referenced directly or indirectly after
// some point), it will be removed from the Store before the end of its
// actual lifetime.
- // This means that that if the ownership status didn't change, CurrOwners
+ // This means that if the ownership status didn't change, CurrOwners
// must be a superset of, but not necessarily equal to ExitOwners.
return !llvm::set_is_subset(ExitOwners, CurrOwners);
}
@@ -1132,7 +1118,7 @@ bool MallocChecker::isMemCall(const CallEvent &Call) const {
return Func && Func->hasAttr<OwnershipAttr>();
}
-llvm::Optional<ProgramStateRef>
+std::optional<ProgramStateRef>
MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
const ProgramStateRef &State) const {
// 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:
@@ -1170,33 +1156,32 @@ MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
// Fall back to normal malloc behavior on platforms where we don't
// know M_ZERO.
- return None;
+ return std::nullopt;
}
// We treat the last argument as the flags argument, and callers fall-back to
// normal malloc on a None return. This works for the FreeBSD kernel malloc
// as well as Linux kmalloc.
if (Call.getNumArgs() < 2)
- return None;
+ return std::nullopt;
const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);
const SVal V = C.getSVal(FlagsEx);
if (!isa<NonLoc>(V)) {
// The case where 'V' can be a location can only be due to a bad header,
// so in this case bail out.
- return None;
+ return std::nullopt;
}
NonLoc Flags = V.castAs<NonLoc>();
- NonLoc ZeroFlag =
- C.getSValBuilder()
- .makeIntVal(KernelZeroFlagVal.value(), FlagsEx->getType())
- .castAs<NonLoc>();
+ NonLoc ZeroFlag = C.getSValBuilder()
+ .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())
+ .castAs<NonLoc>();
SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
Flags, ZeroFlag,
FlagsEx->getType());
if (MaskedFlagsUC.isUnknownOrUndef())
- return None;
+ return std::nullopt;
DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
// Check if maskedFlags is non-zero.
@@ -1210,7 +1195,7 @@ MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
AF_Malloc);
}
- return None;
+ return std::nullopt;
}
SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
@@ -1236,10 +1221,10 @@ void MallocChecker::checkBasicAlloc(const CallEvent &Call,
void MallocChecker::checkKernelMalloc(const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- llvm::Optional<ProgramStateRef> MaybeState =
+ std::optional<ProgramStateRef> MaybeState =
performKernelMalloc(Call, C, State);
if (MaybeState)
- State = MaybeState.value();
+ State = *MaybeState;
else
State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
AF_Malloc);
@@ -1506,7 +1491,7 @@ void MallocChecker::checkPostCall(const CallEvent &Call,
// Performs a 0-sized allocations check.
ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
const CallEvent &Call, const unsigned IndexOfSizeArg, ProgramStateRef State,
- Optional<SVal> RetVal) {
+ std::optional<SVal> RetVal) {
if (!State)
return nullptr;
@@ -1658,7 +1643,7 @@ static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) {
FirstSlot == "initWithCharactersNoCopy";
}
-static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
+static std::optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
Selector S = Call.getSelector();
// FIXME: We should not rely on fully-constrained symbols being folded.
@@ -1666,7 +1651,7 @@ static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
if (S.getNameForSlot(i).equals("freeWhenDone"))
return !Call.getArgSVal(i).isZeroConstant();
- return None;
+ return std::nullopt;
}
void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
@@ -1677,7 +1662,7 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
if (!isKnownDeallocObjCMethodName(Call))
return;
- if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
+ if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
if (!*FreeWhenDone)
return;
@@ -1749,6 +1734,10 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
// Fill the region with the initialization value.
State = State->bindDefaultInitial(RetVal, Init, LCtx);
+ // If Size is somehow undefined at this point, this line prevents a crash.
+ if (Size.isUndef())
+ Size = UnknownVal();
+
// Set the region's extent.
State = setDynamicExtent(State, RetVal.getAsRegion(),
Size.castAs<DefinedOrUnknownSVal>(), svalBuilder);
@@ -1759,7 +1748,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
ProgramStateRef State,
AllocationFamily Family,
- Optional<SVal> RetVal) {
+ std::optional<SVal> RetVal) {
if (!State)
return nullptr;
@@ -2074,7 +2063,7 @@ ProgramStateRef MallocChecker::FreeMemAux(
RefState::getReleased(Family, ParentExpr));
}
-Optional<MallocChecker::CheckKind>
+std::optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(AllocationFamily Family,
bool IsALeakCheck) const {
switch (Family) {
@@ -2083,7 +2072,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
case AF_IfNameIndex: {
if (ChecksEnabled[CK_MallocChecker])
return CK_MallocChecker;
- return None;
+ return std::nullopt;
}
case AF_CXXNew:
case AF_CXXNewArray: {
@@ -2095,12 +2084,12 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
if (ChecksEnabled[CK_NewDeleteChecker])
return CK_NewDeleteChecker;
}
- return None;
+ return std::nullopt;
}
case AF_InnerBuffer: {
if (ChecksEnabled[CK_InnerPointerChecker])
return CK_InnerPointerChecker;
- return None;
+ return std::nullopt;
}
case AF_None: {
llvm_unreachable("no family");
@@ -2109,7 +2098,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
llvm_unreachable("unhandled family");
}
-Optional<MallocChecker::CheckKind>
+std::optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
bool IsALeakCheck) const {
if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
@@ -2121,11 +2110,13 @@ MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
- if (Optional<nonloc::ConcreteInt> IntVal = V.getAs<nonloc::ConcreteInt>())
+ if (std::optional<nonloc::ConcreteInt> IntVal =
+ V.getAs<nonloc::ConcreteInt>())
os << "an integer (" << IntVal->getValue() << ")";
- else if (Optional<loc::ConcreteInt> ConstAddr = V.getAs<loc::ConcreteInt>())
+ else if (std::optional<loc::ConcreteInt> ConstAddr =
+ V.getAs<loc::ConcreteInt>())
os << "a constant address (" << ConstAddr->getValue() << ")";
- else if (Optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
+ else if (std::optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
os << "the address of the label '" << Label->getLabel()->getName() << "'";
else
return false;
@@ -2217,7 +2208,7 @@ void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind)
return;
@@ -2258,7 +2249,7 @@ void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
SourceRange Range) const {
- Optional<MallocChecker::CheckKind> CheckKind;
+ std::optional<MallocChecker::CheckKind> CheckKind;
if (ChecksEnabled[CK_MallocChecker])
CheckKind = CK_MallocChecker;
@@ -2350,7 +2341,7 @@ void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind)
return;
@@ -2407,7 +2398,7 @@ void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind)
return;
@@ -2446,7 +2437,7 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind)
return;
@@ -2476,7 +2467,7 @@ void MallocChecker::HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind)
return;
@@ -2503,7 +2494,7 @@ void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind)
return;
@@ -2536,7 +2527,7 @@ void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind)
return;
@@ -2747,8 +2738,8 @@ void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
if (Family == AF_Alloca)
return;
- Optional<MallocChecker::CheckKind>
- CheckKind = getCheckIfTracked(Family, true);
+ std::optional<MallocChecker::CheckKind> CheckKind =
+ getCheckIfTracked(Family, true);
if (!CheckKind)
return;
@@ -3151,7 +3142,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// about, we can't be sure that the object will use free() to deallocate the
// memory, so we can't model it explicitly. The best we can do is use it to
// decide whether the pointer escapes.
- if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
+ if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
return *FreeWhenDone;
// If the first selector piece ends with "NoCopy", and there is no
@@ -3570,7 +3561,8 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
const RefState *RefS = State->get<RegionState>(I.getKey());
AllocationFamily Family = RefS->getAllocationFamily();
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ std::optional<MallocChecker::CheckKind> CheckKind =
+ getCheckIfTracked(Family);
if (!CheckKind)
CheckKind = getCheckIfTracked(Family, true);
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index a6e8fcd425d5..5266df2ae6a6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -24,6 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
#include <utility>
using namespace clang;
@@ -308,26 +309,27 @@ void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D,
CFGBlock *block = *it;
for (CFGBlock::iterator bi = block->begin(), be = block->end();
bi != be; ++bi) {
- if (Optional<CFGStmt> CS = bi->getAs<CFGStmt>()) {
- if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
- // Get the callee.
- const FunctionDecl *FD = TheCall->getDirectCallee();
-
- if (!FD)
- continue;
-
- // Get the name of the callee. If it's a builtin, strip off the prefix.
- IdentifierInfo *FnInfo = FD->getIdentifier();
- if (!FnInfo)
- continue;
-
- if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) {
- if (TheCall->getNumArgs() == 1)
- CheckMallocArgument(PossibleMallocOverflows, TheCall,
- mgr.getASTContext());
+ if (std::optional<CFGStmt> CS = bi->getAs<CFGStmt>()) {
+ if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
+ // Get the callee.
+ const FunctionDecl *FD = TheCall->getDirectCallee();
+
+ if (!FD)
+ continue;
+
+ // Get the name of the callee. If it's a builtin, strip off the
+ // prefix.
+ IdentifierInfo *FnInfo = FD->getIdentifier();
+ if (!FnInfo)
+ continue;
+
+ if (FnInfo->isStr("malloc") || FnInfo->isStr("_MALLOC")) {
+ if (TheCall->getNumArgs() == 1)
+ CheckMallocArgument(PossibleMallocOverflows, TheCall,
+ mgr.getASTContext());
+ }
}
}
- }
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
index 1960873599f7..2020dc7cc791 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
@@ -176,8 +176,10 @@ void MismatchedIteratorChecker::checkPreCall(const CallEvent &Call,
const auto *Param = Func->getParamDecl(J);
const auto *ParamType =
Param->getType()->getAs<SubstTemplateTypeParmType>();
- if (!ParamType ||
- ParamType->getReplacedParameter()->getDecl() != TPDecl)
+ if (!ParamType)
+ continue;
+ const TemplateTypeParmDecl *D = ParamType->getReplacedParameter();
+ if (D != TPDecl)
continue;
if (LHS.isUndef()) {
LHS = Call.getArgSVal(J);
diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index 1906ca5c8f55..0b3d635a50a3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -33,7 +33,7 @@ class MmapWriteExecChecker : public Checker<check::PreCall> {
static int ProtRead;
mutable std::unique_ptr<BugType> BT;
public:
- MmapWriteExecChecker() : MmapFn("mmap", 6), MprotectFn("mprotect", 3) {}
+ MmapWriteExecChecker() : MmapFn({"mmap"}, 6), MprotectFn({"mprotect"}, 3) {}
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
int ProtExecOv;
int ProtReadOv;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index e78c130a9c22..c8ddf3b2c14f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -309,7 +309,7 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
// If it's not a dereference, we don't care if it was reset to null
// or that it is even a smart pointer.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SK_NonStd:
case SK_Safe:
OS << "Object";
@@ -587,7 +587,7 @@ void MoveChecker::explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
break;
// We only care about the type if it's a dereference.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SK_Unsafe:
OS << " of type '" << RD->getQualifiedNameAsString() << "'";
break;
@@ -618,10 +618,6 @@ void MoveChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
if (!IC)
return;
- // Calling a destructor on a moved object is fine.
- if (isa<CXXDestructorCall>(IC))
- return;
-
const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
if (!ThisRegion)
return;
@@ -631,6 +627,10 @@ void MoveChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
if (!MethodDecl)
return;
+ // Calling a destructor on a moved object is fine.
+ if (isa<CXXDestructorDecl>(MethodDecl))
+ return;
+
// We want to investigate the whole object, not only sub-object of a parent
// class in which the encountered method defined.
ThisRegion = ThisRegion->getMostDerivedObjectRegion();
diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index fea35d03cb81..59741dde1eea 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -24,6 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -118,7 +119,7 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
II = &D->getASTContext().Idents.get("CFErrorRef");
bool hasCFError = false;
- for (auto I : D->parameters()) {
+ for (auto *I : D->parameters()) {
if (IsCFError(I->getType(), II)) {
hasCFError = true;
break;
@@ -197,7 +198,7 @@ static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C) {
static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
const StackFrameContext * SFC = C.getStackFrame();
- if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
if (const VarRegion *VR = R->getAs<VarRegion>())
if (const StackArgumentsSpaceRegion *
diff --git a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index af208e867318..17c3cb4e9e04 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -44,9 +44,11 @@ void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
BuildSinks = FD->hasAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
- const Expr *Callee = CE.getOriginExpr();
- if (!BuildSinks && Callee)
- BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
+ if (const CallExpr *CExpr = dyn_cast_or_null<CallExpr>(CE.getOriginExpr());
+ CExpr && !BuildSinks) {
+ if (const Expr *C = CExpr->getCallee())
+ BuildSinks = getFunctionExtInfo(C->getType()).getNoReturn();
+ }
if (!BuildSinks && CE.isGlobalCFunction()) {
if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index fb6afd0fdabc..fd47e19cb786 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -136,10 +136,10 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
if (!DV)
continue;
- assert(!HasRefTypeParam || isa<Loc>(DV.value()));
+ assert(!HasRefTypeParam || isa<Loc>(*DV));
// Process the case when the argument is not a location.
- if (ExpectedToBeNonNull && !isa<Loc>(DV.value())) {
+ if (ExpectedToBeNonNull && !isa<Loc>(*DV)) {
// If the argument is a union type, we want to handle a potential
// transparent_union GCC extension.
if (!ArgE)
diff --git a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
index c5437b16c688..72c6a869d225 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
@@ -26,6 +26,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -77,7 +78,8 @@ void NonnullGlobalConstantsChecker::checkLocation(SVal location, bool isLoad,
if (isGlobalConstString(location)) {
SVal V = State->getSVal(location.castAs<Loc>());
- Optional<DefinedOrUnknownSVal> Constr = V.getAs<DefinedOrUnknownSVal>();
+ std::optional<DefinedOrUnknownSVal> Constr =
+ V.getAs<DefinedOrUnknownSVal>();
if (Constr) {
@@ -91,7 +93,7 @@ void NonnullGlobalConstantsChecker::checkLocation(SVal location, bool isLoad,
/// \param V loaded lvalue.
/// \return whether @c val is a string-like const global.
bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const {
- Optional<loc::MemRegionVal> RegionVal = V.getAs<loc::MemRegionVal>();
+ std::optional<loc::MemRegionVal> RegionVal = V.getAs<loc::MemRegionVal>();
if (!RegionVal)
return false;
auto *Region = dyn_cast<VarRegion>(RegionVal->getAsRegion());
@@ -109,17 +111,20 @@ bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const {
// Look through the typedefs.
while (const Type *T = Ty.getTypePtr()) {
- if (const auto *TT = dyn_cast<TypedefType>(T)) {
+ if (const auto *AT = dyn_cast<AttributedType>(T)) {
+ if (AT->getAttrKind() == attr::TypeNonNull)
+ return true;
+ Ty = AT->getModifiedType();
+ } else if (const auto *ET = dyn_cast<ElaboratedType>(T)) {
+ const auto *TT = dyn_cast<TypedefType>(ET->getNamedType());
+ if (!TT)
+ return false;
Ty = TT->getDecl()->getUnderlyingType();
// It is sufficient for any intermediate typedef
// to be classified const.
HasConst = HasConst || Ty.isConstQualified();
if (isNonnullType(Ty) && HasConst)
return true;
- } else if (const auto *AT = dyn_cast<AttributedType>(T)) {
- if (AT->getAttrKind() == attr::TypeNonNull)
- return true;
- Ty = AT->getModifiedType();
} else {
return false;
}
@@ -136,7 +141,7 @@ bool NonnullGlobalConstantsChecker::isNonnullType(QualType Ty) const {
if (auto *T = dyn_cast<ObjCObjectPointerType>(Ty)) {
return T->getInterfaceDecl() &&
T->getInterfaceDecl()->getIdentifier() == NSStringII;
- } else if (auto *T = dyn_cast<TypedefType>(Ty)) {
+ } else if (auto *T = Ty->getAs<TypedefType>()) {
IdentifierInfo* II = T->getDecl()->getIdentifier();
return II == CFStringRefII || II == CFBooleanRefII || II == CFNullRefII;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 1d8835f6b474..da8529f4ea81 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -80,7 +80,7 @@ enum class ErrorKind : int {
class NullabilityChecker
: public Checker<check::Bind, check::PreCall, check::PreStmt<ReturnStmt>,
check::PostCall, check::PostStmt<ExplicitCastExpr>,
- check::PostObjCMessage, check::DeadSymbols,
+ check::PostObjCMessage, check::DeadSymbols, eval::Assume,
check::Location, check::Event<ImplicitNullDerefEvent>> {
public:
@@ -102,6 +102,8 @@ public:
void checkEvent(ImplicitNullDerefEvent Event) const;
void checkLocation(SVal Location, bool IsLoad, const Stmt *S,
CheckerContext &C) const;
+ ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const;
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
const char *Sep) const override;
@@ -129,7 +131,7 @@ public:
// When set to false no nullability information will be tracked in
// NullabilityMap. It is possible to catch errors like passing a null pointer
// to a callee that expects nonnull argument without the information that is
- // stroed in the NullabilityMap. This is an optimization.
+ // stored in the NullabilityMap. This is an optimization.
bool NeedTracking = false;
private:
@@ -230,10 +232,41 @@ bool operator==(NullabilityState Lhs, NullabilityState Rhs) {
Lhs.getNullabilitySource() == Rhs.getNullabilitySource();
}
+// For the purpose of tracking historical property accesses, the key for lookup
+// is an object pointer (could be an instance or a class) paired with the unique
+// identifier for the property being invoked on that object.
+using ObjectPropPair = std::pair<const MemRegion *, const IdentifierInfo *>;
+
+// Metadata associated with the return value from a recorded property access.
+struct ConstrainedPropertyVal {
+ // This will reference the conjured return SVal for some call
+ // of the form [object property]
+ DefinedOrUnknownSVal Value;
+
+ // If the SVal has been determined to be nonnull, that is recorded here
+ bool isConstrainedNonnull;
+
+ ConstrainedPropertyVal(DefinedOrUnknownSVal SV)
+ : Value(SV), isConstrainedNonnull(false) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Value.Profile(ID);
+ ID.AddInteger(isConstrainedNonnull ? 1 : 0);
+ }
+};
+
+bool operator==(const ConstrainedPropertyVal &Lhs,
+ const ConstrainedPropertyVal &Rhs) {
+ return Lhs.Value == Rhs.Value &&
+ Lhs.isConstrainedNonnull == Rhs.isConstrainedNonnull;
+}
+
} // end anonymous namespace
REGISTER_MAP_WITH_PROGRAMSTATE(NullabilityMap, const MemRegion *,
NullabilityState)
+REGISTER_MAP_WITH_PROGRAMSTATE(PropertyAccessesMap, ObjectPropPair,
+ ConstrainedPropertyVal)
// We say "the nullability type invariant is violated" when a location with a
// non-null type contains NULL or a function with a non-null return type returns
@@ -285,8 +318,11 @@ NullabilityChecker::getTrackRegion(SVal Val, bool CheckSuperRegion) const {
const MemRegion *Region = RegionSVal->getRegion();
if (CheckSuperRegion) {
- if (auto FieldReg = Region->getAs<FieldRegion>())
+ if (const SubRegion *FieldReg = Region->getAs<FieldRegion>()) {
+ if (const auto *ER = dyn_cast<ElementRegion>(FieldReg->getSuperRegion()))
+ FieldReg = ER;
return dyn_cast<SymbolicRegion>(FieldReg->getSuperRegion());
+ }
if (auto ElementReg = Region->getAs<ElementRegion>())
return dyn_cast<SymbolicRegion>(ElementReg->getSuperRegion());
}
@@ -464,6 +500,19 @@ void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR,
State = State->remove<NullabilityMap>(I->first);
}
}
+
+ // When an object goes out of scope, we can free the history associated
+ // with any property accesses on that object
+ PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
+ for (PropertyAccessesMapTy::iterator I = PropertyAccesses.begin(),
+ E = PropertyAccesses.end();
+ I != E; ++I) {
+ const MemRegion *ReceiverRegion = I->first.first;
+ if (!SR.isLiveRegion(ReceiverRegion)) {
+ State = State->remove<PropertyAccessesMap>(I->first);
+ }
+ }
+
// When one of the nonnull arguments are constrained to be null, nullability
// preconditions are violated. It is not enough to check this only when we
// actually report an error, because at that time interesting symbols might be
@@ -851,6 +900,32 @@ static Nullability getReceiverNullability(const ObjCMethodCall &M,
return Nullability::Unspecified;
}
+// The return value of a property access is typically a temporary value which
+// will not be tracked in a persistent manner by the analyzer. We use
+// evalAssume() in order to immediately record constraints on those temporaries
+// at the time they are imposed (e.g. by a nil-check conditional).
+ProgramStateRef NullabilityChecker::evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const {
+ PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
+ for (PropertyAccessesMapTy::iterator I = PropertyAccesses.begin(),
+ E = PropertyAccesses.end();
+ I != E; ++I) {
+ if (!I->second.isConstrainedNonnull) {
+ ConditionTruthVal IsNonNull = State->isNonNull(I->second.Value);
+ if (IsNonNull.isConstrainedTrue()) {
+ ConstrainedPropertyVal Replacement = I->second;
+ Replacement.isConstrainedNonnull = true;
+ State = State->set<PropertyAccessesMap>(I->first, Replacement);
+ } else if (IsNonNull.isConstrainedFalse()) {
+ // Space optimization: no point in tracking constrained-null cases
+ State = State->remove<PropertyAccessesMap>(I->first);
+ }
+ }
+ }
+
+ return State;
+}
+
/// Calculate the nullability of the result of a message expr based on the
/// nullability of the receiver, the nullability of the return value, and the
/// constraints.
@@ -907,7 +982,7 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
// this class of methods reduced the emitted diagnostics by about 30% on
// some projects (and all of that was false positives).
if (Name.contains("String")) {
- for (auto Param : M.parameters()) {
+ for (auto *Param : M.parameters()) {
if (Param->getName() == "encoding") {
State = State->set<NullabilityMap>(ReturnRegion,
Nullability::Contradicted);
@@ -947,12 +1022,53 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
// No tracked information. Use static type information for return value.
Nullability RetNullability = getNullabilityAnnotation(RetType);
- // Properties might be computed. For this reason the static analyzer creates a
- // new symbol each time an unknown property is read. To avoid false pozitives
- // do not treat unknown properties as nullable, even when they explicitly
- // marked nullable.
- if (M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined)
- RetNullability = Nullability::Nonnull;
+ // Properties might be computed, which means the property value could
+ // theoretically change between calls even in commonly-observed cases like
+ // this:
+ //
+ // if (foo.prop) { // ok, it's nonnull here...
+ // [bar doStuffWithNonnullVal:foo.prop]; // ...but what about
+ // here?
+ // }
+ //
+ // If the property is nullable-annotated, a naive analysis would lead to many
+ // false positives despite the presence of probably-correct nil-checks. To
+ // reduce the false positive rate, we maintain a history of the most recently
+ // observed property value. For each property access, if the prior value has
+ // been constrained to be not nil then we will conservatively assume that the
+ // next access can be inferred as nonnull.
+ if (RetNullability != Nullability::Nonnull &&
+ M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined) {
+ bool LookupResolved = false;
+ if (const MemRegion *ReceiverRegion = getTrackRegion(M.getReceiverSVal())) {
+ if (IdentifierInfo *Ident = M.getSelector().getIdentifierInfoForSlot(0)) {
+ LookupResolved = true;
+ ObjectPropPair Key = std::make_pair(ReceiverRegion, Ident);
+ const ConstrainedPropertyVal *PrevPropVal =
+ State->get<PropertyAccessesMap>(Key);
+ if (PrevPropVal && PrevPropVal->isConstrainedNonnull) {
+ RetNullability = Nullability::Nonnull;
+ } else {
+ // If a previous property access was constrained as nonnull, we hold
+ // on to that constraint (effectively inferring that all subsequent
+ // accesses on that code path can be inferred as nonnull). If the
+ // previous property access was *not* constrained as nonnull, then
+ // let's throw it away in favor of keeping the SVal associated with
+ // this more recent access.
+ if (auto ReturnSVal =
+ M.getReturnValue().getAs<DefinedOrUnknownSVal>()) {
+ State = State->set<PropertyAccessesMap>(
+ Key, ConstrainedPropertyVal(*ReturnSVal));
+ }
+ }
+ }
+ }
+
+ if (!LookupResolved) {
+ // Fallback: err on the side of suppressing the false positive.
+ RetNullability = Nullability::Nonnull;
+ }
+ }
Nullability ComputedNullab = getMostNullable(RetNullability, SelfNullability);
if (ComputedNullab == Nullability::Nullable) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
index 3e9fc696f8e6..f217520d8f4a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
@@ -196,12 +196,10 @@ void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
AnalysisManager &AM,
BugReporter &BR) const {
// Currently this matches CoreFoundation opaque pointer typedefs.
- auto CSuspiciousNumberObjectExprM =
- expr(ignoringParenImpCasts(
- expr(hasType(
- typedefType(hasDeclaration(anyOf(
- typedefDecl(hasName("CFNumberRef")),
- typedefDecl(hasName("CFBooleanRef")))))))
+ auto CSuspiciousNumberObjectExprM = expr(ignoringParenImpCasts(
+ expr(hasType(elaboratedType(namesType(typedefType(
+ hasDeclaration(anyOf(typedefDecl(hasName("CFNumberRef")),
+ typedefDecl(hasName("CFBooleanRef")))))))))
.bind("c_object")));
// Currently this matches XNU kernel number-object pointers.
@@ -240,8 +238,9 @@ void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
// The .bind here is in order to compose the error message more accurately.
auto ObjCSuspiciousScalarBooleanTypeM =
- qualType(typedefType(hasDeclaration(
- typedefDecl(hasName("BOOL"))))).bind("objc_bool_type");
+ qualType(elaboratedType(namesType(
+ typedefType(hasDeclaration(typedefDecl(hasName("BOOL")))))))
+ .bind("objc_bool_type");
// The .bind here is in order to compose the error message more accurately.
auto SuspiciousScalarBooleanTypeM =
@@ -253,9 +252,9 @@ void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
// for storing pointers.
auto SuspiciousScalarNumberTypeM =
qualType(hasCanonicalType(isInteger()),
- unless(typedefType(hasDeclaration(
- typedefDecl(matchesName("^::u?intptr_t$"))))))
- .bind("int_type");
+ unless(elaboratedType(namesType(typedefType(hasDeclaration(
+ typedefDecl(matchesName("^::u?intptr_t$"))))))))
+ .bind("int_type");
auto SuspiciousScalarTypeM =
qualType(anyOf(SuspiciousScalarBooleanTypeM,
diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index 6688278a7a33..2b008d1c775a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -72,7 +72,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
: BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()),
- PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
+ PtrWidth(ASTC.getTargetInfo().getPointerWidth(LangAS::Default)) {}
// Statement visitor methods.
void VisitChildren(Stmt *S);
diff --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index e877dd119ff6..929bd6bc3eb3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -87,7 +87,7 @@ private:
CheckerKind CheckKind) const;
CallDescriptionMap<FnCheck> PThreadCallbacks = {
// Init.
- {{"pthread_mutex_init", 2}, &PthreadLockChecker::InitAnyLock},
+ {{{"pthread_mutex_init"}, 2}, &PthreadLockChecker::InitAnyLock},
// TODO: pthread_rwlock_init(2 arguments).
// TODO: lck_mtx_init(3 arguments).
// TODO: lck_mtx_alloc_init(2 arguments) => returns the mutex.
@@ -95,74 +95,74 @@ private:
// TODO: lck_rw_alloc_init(2 arguments) => returns the mutex.
// Acquire.
- {{"pthread_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"pthread_rwlock_rdlock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"pthread_rwlock_wrlock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"lck_mtx_lock", 1}, &PthreadLockChecker::AcquireXNULock},
- {{"lck_rw_lock_exclusive", 1}, &PthreadLockChecker::AcquireXNULock},
- {{"lck_rw_lock_shared", 1}, &PthreadLockChecker::AcquireXNULock},
+ {{{"pthread_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"pthread_rwlock_rdlock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"pthread_rwlock_wrlock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"lck_mtx_lock"}, 1}, &PthreadLockChecker::AcquireXNULock},
+ {{{"lck_rw_lock_exclusive"}, 1}, &PthreadLockChecker::AcquireXNULock},
+ {{{"lck_rw_lock_shared"}, 1}, &PthreadLockChecker::AcquireXNULock},
// Try.
- {{"pthread_mutex_trylock", 1}, &PthreadLockChecker::TryPthreadLock},
- {{"pthread_rwlock_tryrdlock", 1}, &PthreadLockChecker::TryPthreadLock},
- {{"pthread_rwlock_trywrlock", 1}, &PthreadLockChecker::TryPthreadLock},
- {{"lck_mtx_try_lock", 1}, &PthreadLockChecker::TryXNULock},
- {{"lck_rw_try_lock_exclusive", 1}, &PthreadLockChecker::TryXNULock},
- {{"lck_rw_try_lock_shared", 1}, &PthreadLockChecker::TryXNULock},
+ {{{"pthread_mutex_trylock"}, 1}, &PthreadLockChecker::TryPthreadLock},
+ {{{"pthread_rwlock_tryrdlock"}, 1}, &PthreadLockChecker::TryPthreadLock},
+ {{{"pthread_rwlock_trywrlock"}, 1}, &PthreadLockChecker::TryPthreadLock},
+ {{{"lck_mtx_try_lock"}, 1}, &PthreadLockChecker::TryXNULock},
+ {{{"lck_rw_try_lock_exclusive"}, 1}, &PthreadLockChecker::TryXNULock},
+ {{{"lck_rw_try_lock_shared"}, 1}, &PthreadLockChecker::TryXNULock},
// Release.
- {{"pthread_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"pthread_rwlock_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"lck_mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"lck_rw_unlock_exclusive", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"lck_rw_unlock_shared", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"lck_rw_done", 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"pthread_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"pthread_rwlock_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"lck_mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"lck_rw_unlock_exclusive"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"lck_rw_unlock_shared"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"lck_rw_done"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
// Destroy.
- {{"pthread_mutex_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock},
- {{"lck_mtx_destroy", 2}, &PthreadLockChecker::DestroyXNULock},
+ {{{"pthread_mutex_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
+ {{{"lck_mtx_destroy"}, 2}, &PthreadLockChecker::DestroyXNULock},
// TODO: pthread_rwlock_destroy(1 argument).
// TODO: lck_rw_destroy(2 arguments).
};
CallDescriptionMap<FnCheck> FuchsiaCallbacks = {
// Init.
- {{"spin_lock_init", 1}, &PthreadLockChecker::InitAnyLock},
+ {{{"spin_lock_init"}, 1}, &PthreadLockChecker::InitAnyLock},
// Acquire.
- {{"spin_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"spin_lock_save", 3}, &PthreadLockChecker::AcquirePthreadLock},
- {{"sync_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"sync_mutex_lock_with_waiter", 1},
+ {{{"spin_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"spin_lock_save"}, 3}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"sync_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"sync_mutex_lock_with_waiter"}, 1},
&PthreadLockChecker::AcquirePthreadLock},
// Try.
- {{"spin_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock},
- {{"sync_mutex_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock},
- {{"sync_mutex_timedlock", 2}, &PthreadLockChecker::TryFuchsiaLock},
+ {{{"spin_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
+ {{{"sync_mutex_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
+ {{{"sync_mutex_timedlock"}, 2}, &PthreadLockChecker::TryFuchsiaLock},
// Release.
- {{"spin_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"spin_unlock_restore", 3}, &PthreadLockChecker::ReleaseAnyLock},
- {{"sync_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"spin_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"spin_unlock_restore"}, 3}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"sync_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
};
CallDescriptionMap<FnCheck> C11Callbacks = {
// Init.
- {{"mtx_init", 2}, &PthreadLockChecker::InitAnyLock},
+ {{{"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock},
// Acquire.
- {{"mtx_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"mtx_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
// Try.
- {{"mtx_trylock", 1}, &PthreadLockChecker::TryC11Lock},
- {{"mtx_timedlock", 2}, &PthreadLockChecker::TryC11Lock},
+ {{{"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock},
+ {{{"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock},
// Release.
- {{"mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
// Destroy
- {{"mtx_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock},
+ {{{"mtx_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
};
ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state,
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index bee7c468812c..01c71d91d1a1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -14,6 +14,7 @@
#include "RetainCountChecker.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -284,7 +285,7 @@ void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
CheckerContext &C) const {
- Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
+ std::optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
if (!IVarLoc)
return;
@@ -412,15 +413,15 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
return RetTy;
}
-static Optional<RefVal> refValFromRetEffect(RetEffect RE,
- QualType ResultTy) {
+static std::optional<RefVal> refValFromRetEffect(RetEffect RE,
+ QualType ResultTy) {
if (RE.isOwned()) {
return RefVal::makeOwned(RE.getObjKind(), ResultTy);
} else if (RE.notOwned()) {
return RefVal::makeNotOwned(RE.getObjKind(), ResultTy);
}
- return None;
+ return std::nullopt;
}
static bool isPointerToObject(QualType QT) {
@@ -692,7 +693,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
assert(Ex);
ResultTy = GetReturnType(Ex, C.getASTContext());
}
- if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
+ if (std::optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
state = setRefBinding(state, Sym, *updatedRefVal);
}
@@ -767,7 +768,7 @@ ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DoNothing:
return state;
@@ -907,7 +908,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
const LocationContext *LCtx = C.getLocationContext();
using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
- Optional<BehaviorSummary> BSmr =
+ std::optional<BehaviorSummary> BSmr =
SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
// See if it's one of the specific functions we know how to eval.
@@ -1336,7 +1337,7 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
const LocationContext *LCtx = Ctx.getLocationContext();
const Decl *D = LCtx->getDecl();
- Optional<AnyCall> C = AnyCall::forDecl(D);
+ std::optional<AnyCall> C = AnyCall::forDecl(D);
if (!C || SmrMgr.isTrustedReferenceCountImplementation(D))
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 5109ae668686..e11e509f159d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -15,6 +15,7 @@
#include "RetainCountChecker.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -165,13 +166,12 @@ static bool shouldGenerateNote(llvm::raw_string_ostream &os,
/// Finds argument index of the out paramter in the call @c S
/// corresponding to the symbol @c Sym.
-/// If none found, returns None.
-static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt,
- const LocationContext *LCtx,
- SymbolRef &Sym,
- Optional<CallEventRef<>> CE) {
+/// If none found, returns std::nullopt.
+static std::optional<unsigned>
+findArgIdxOfSymbol(ProgramStateRef CurrSt, const LocationContext *LCtx,
+ SymbolRef &Sym, std::optional<CallEventRef<>> CE) {
if (!CE)
- return None;
+ return std::nullopt;
for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++)
if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
@@ -179,25 +179,25 @@ static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt,
if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymbol() == Sym)
return Idx;
- return None;
+ return std::nullopt;
}
-static Optional<std::string> findMetaClassAlloc(const Expr *Callee) {
+static std::optional<std::string> findMetaClassAlloc(const Expr *Callee) {
if (const auto *ME = dyn_cast<MemberExpr>(Callee)) {
if (ME->getMemberDecl()->getNameAsString() != "alloc")
- return None;
+ return std::nullopt;
const Expr *This = ME->getBase()->IgnoreParenImpCasts();
if (const auto *DRE = dyn_cast<DeclRefExpr>(This)) {
const ValueDecl *VD = DRE->getDecl();
if (VD->getNameAsString() != "metaClass")
- return None;
+ return std::nullopt;
if (const auto *RD = dyn_cast<CXXRecordDecl>(VD->getDeclContext()))
return RD->getNameAsString();
}
}
- return None;
+ return std::nullopt;
}
static std::string findAllocatedObjectName(const Stmt *S, QualType QT) {
@@ -250,7 +250,7 @@ static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
}
}
- Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
+ std::optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
// If index is not found, we assume that the symbol was returned.
@@ -602,16 +602,17 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
return std::move(P);
}
-static Optional<std::string> describeRegion(const MemRegion *MR) {
+static std::optional<std::string> describeRegion(const MemRegion *MR) {
if (const auto *VR = dyn_cast_or_null<VarRegion>(MR))
return std::string(VR->getDecl()->getName());
// Once we support more storage locations for bindings,
// this would need to be improved.
- return None;
+ return std::nullopt;
}
using Bindings = llvm::SmallVector<std::pair<const MemRegion *, SVal>, 4>;
+namespace {
class VarBindingsCollector : public StoreManager::BindingsHandler {
SymbolRef Sym;
Bindings &Result;
@@ -632,6 +633,7 @@ public:
return true;
}
};
+} // namespace
Bindings getAllVarBindingsForSymbol(ProgramStateManager &Manager,
const ExplodedNode *Node, SymbolRef Sym) {
@@ -728,7 +730,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
const LocationContext *InterestingMethodContext = nullptr;
if (InitMethodContext) {
const ProgramPoint AllocPP = AllocationNode->getLocation();
- if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
+ if (std::optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
if (ME->getMethodFamily() == OMF_alloc)
InterestingMethodContext = InitMethodContext;
@@ -771,7 +773,7 @@ RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
os << "Object leaked: ";
- Optional<std::string> RegionDescription = describeRegion(LastBinding);
+ std::optional<std::string> RegionDescription = describeRegion(LastBinding);
if (RegionDescription) {
os << "object allocated and stored into '" << *RegionDescription << '\'';
} else {
@@ -917,7 +919,7 @@ void RefLeakReport::createDescription(CheckerContext &Ctx) {
llvm::raw_string_ostream os(Description);
os << "Potential leak of an object";
- Optional<std::string> RegionDescription =
+ std::optional<std::string> RegionDescription =
describeRegion(AllocBindingToReport);
if (RegionDescription) {
os << " stored into '" << *RegionDescription << '\'';
@@ -969,7 +971,7 @@ void RefLeakReport::findBindingToReport(CheckerContext &Ctx,
// Let's pick one of them at random (if there is something to pick from).
AllocBindingToReport = AllVarBindings[0].first;
- // Because 'AllocBindingToReport' is not the the same as
+ // Because 'AllocBindingToReport' is not the same as
// 'AllocFirstBinding', we need to explain how the leaking object
// got from one to another.
//
diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
index cf97439a468d..c3112ebe4e79 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
@@ -17,8 +17,8 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -70,11 +70,11 @@ static std::string getName(const CallEvent &Call) {
// The predefinitions ('CDM') could break due to the ever growing code base.
// Check for the expected invariants and see whether they apply.
-static Optional<bool> isInvariantBreak(bool ExpectedValue, SVal ReturnV,
- CheckerContext &C) {
+static std::optional<bool> isInvariantBreak(bool ExpectedValue, SVal ReturnV,
+ CheckerContext &C) {
auto ReturnDV = ReturnV.getAs<DefinedOrUnknownSVal>();
if (!ReturnDV)
- return None;
+ return std::nullopt;
if (ExpectedValue)
return C.getState()->isNull(*ReturnDV).isConstrainedTrue();
@@ -90,7 +90,8 @@ void ReturnValueChecker::checkPostCall(const CallEvent &Call,
SVal ReturnV = Call.getReturnValue();
bool ExpectedValue = *RawExpectedValue;
- Optional<bool> IsInvariantBreak = isInvariantBreak(ExpectedValue, ReturnV, C);
+ std::optional<bool> IsInvariantBreak =
+ isInvariantBreak(ExpectedValue, ReturnV, C);
if (!IsInvariantBreak)
return;
@@ -137,7 +138,8 @@ void ReturnValueChecker::checkEndFunction(const ReturnStmt *RS,
SVal ReturnV = State->getSVal(RS->getRetValue(), C.getLocationContext());
bool ExpectedValue = *RawExpectedValue;
- Optional<bool> IsInvariantBreak = isInvariantBreak(ExpectedValue, ReturnV, C);
+ std::optional<bool> IsInvariantBreak =
+ isInvariantBreak(ExpectedValue, ReturnV, C);
if (!IsInvariantBreak)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index 8c87a548fd91..9251c895614c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -90,7 +90,7 @@ public:
REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
SimpleStreamChecker::SimpleStreamChecker()
- : OpenFn("fopen"), CloseFn("fclose", 1) {
+ : OpenFn({"fopen"}), CloseFn({"fclose"}, 1) {
// Initialize the bug types.
DoubleCloseBugType.reset(
new BugType(this, "Double fclose", "Unix Stream API Error"));
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index 92eef20d2daa..5689a63f8dd8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -33,6 +33,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
+#include <optional>
#include <string>
using namespace clang;
@@ -85,10 +86,10 @@ private:
using SmartPtrMethodHandlerFn =
void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
CallDescriptionMap<SmartPtrMethodHandlerFn> SmartPtrMethodHandlers{
- {{"reset"}, &SmartPtrModeling::handleReset},
- {{"release"}, &SmartPtrModeling::handleRelease},
- {{"swap", 1}, &SmartPtrModeling::handleSwapMethod},
- {{"get"}, &SmartPtrModeling::handleGet}};
+ {{{"reset"}}, &SmartPtrModeling::handleReset},
+ {{{"release"}}, &SmartPtrModeling::handleRelease},
+ {{{"swap"}, 1}, &SmartPtrModeling::handleSwapMethod},
+ {{{"get"}}, &SmartPtrModeling::handleGet}};
const CallDescription StdSwapCall{{"std", "swap"}, 2};
const CallDescription StdMakeUniqueCall{{"std", "make_unique"}};
const CallDescription StdMakeUniqueForOverwriteCall{
@@ -298,8 +299,9 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
if (matchesAny(Call, StdMakeUniqueCall, StdMakeUniqueForOverwriteCall)) {
if (!ModelSmartPtrDereference)
return false;
-
- const Optional<SVal> ThisRegionOpt = Call.getReturnValueUnderConstruction();
+
+ const std::optional<SVal> ThisRegionOpt =
+ Call.getReturnValueUnderConstruction();
if (!ThisRegionOpt)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index e6cea0fbff8c..c4b7411e9401 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -61,7 +61,6 @@ private:
ASTContext &Ctx);
static SmallVector<const MemRegion *, 4>
getCapturedStackRegions(const BlockDataRegion &B, CheckerContext &C);
- static bool isArcManagedBlock(const MemRegion *R, CheckerContext &C);
static bool isNotInCurrentFrame(const MemRegion *R, CheckerContext &C);
};
} // namespace
@@ -110,13 +109,6 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
return range;
}
-bool StackAddrEscapeChecker::isArcManagedBlock(const MemRegion *R,
- CheckerContext &C) {
- assert(R && "MemRegion should not be null");
- return C.getASTContext().getLangOpts().ObjCAutoRefCount &&
- isa<BlockDataRegion>(R);
-}
-
bool StackAddrEscapeChecker::isNotInCurrentFrame(const MemRegion *R,
CheckerContext &C) {
const StackSpaceRegion *S = cast<StackSpaceRegion>(R->getMemorySpace());
@@ -214,7 +206,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
void StackAddrEscapeChecker::checkReturnedBlockCaptures(
const BlockDataRegion &B, CheckerContext &C) const {
for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
- if (isArcManagedBlock(Region, C) || isNotInCurrentFrame(Region, C))
+ if (isNotInCurrentFrame(Region, C))
continue;
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
@@ -267,8 +259,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
checkReturnedBlockCaptures(*B, C);
- if (!isa<StackSpaceRegion>(R->getMemorySpace()) ||
- isNotInCurrentFrame(R, C) || isArcManagedBlock(R, C))
+ if (!isa<StackSpaceRegion>(R->getMemorySpace()) || isNotInCurrentFrame(R, C))
return;
// Returning a record by value is fine. (In this case, the returned
@@ -348,8 +339,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
// Check the globals for the same.
if (!isa<GlobalsSpaceRegion>(Region->getMemorySpace()))
return true;
- if (VR && VR->hasStackStorage() && !isArcManagedBlock(VR, Ctx) &&
- !isNotInCurrentFrame(VR, Ctx))
+ if (VR && VR->hasStackStorage() && !isNotInCurrentFrame(VR, Ctx))
V.emplace_back(Region, VR);
return true;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 5897e5096461..49b3db560843 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -52,24 +52,12 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
#include <string>
using namespace clang;
using namespace clang::ento;
-/// Produce a textual description of the state of \c errno (this describes the
-/// way how it is allowed to be used).
-/// The returned string is insertable into a longer warning message (in the form
-/// "the value 'errno' <...>").
-/// Currently only the \c errno_modeling::MustNotBeChecked state is supported.
-/// But later other kind of errno state may be needed if functions with special
-/// handling of \c errno are added.
-static const char *describeErrnoCheckState(errno_modeling::ErrnoCheckState CS) {
- assert(CS == errno_modeling::MustNotBeChecked &&
- "Errno description not applicable.");
- return "may be undefined after the call and should not be used";
-}
-
namespace {
class StdLibraryFunctionsChecker
: public Checker<check::PreCall, check::PostCall, eval::Call> {
@@ -147,9 +135,18 @@ class StdLibraryFunctionsChecker
virtual StringRef getName() const = 0;
+ // Represents that in which context do we require a description of the
+ // constraint.
+ enum class DescriptionKind {
+ // The constraint is violated.
+ Violation,
+ // We assume that the constraint is satisfied.
+ Assumption
+ };
+
// Give a description that explains the constraint to the user. Used when
// the bug is reported.
- virtual std::string describe(ProgramStateRef State,
+ virtual std::string describe(DescriptionKind DK, ProgramStateRef State,
const Summary &Summary) const {
// There are some descendant classes that are not used as argument
// constraints, e.g. ComparisonConstraint. In that case we can safely
@@ -187,7 +184,7 @@ class StdLibraryFunctionsChecker
RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
: ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
- std::string describe(ProgramStateRef State,
+ std::string describe(DescriptionKind DK, ProgramStateRef State,
const Summary &Summary) const override;
const IntRangeVector &getRanges() const { return Ranges; }
@@ -257,7 +254,9 @@ class StdLibraryFunctionsChecker
bool CannotBeNull = true;
public:
- std::string describe(ProgramStateRef State,
+ NotNullConstraint(ArgNo ArgN, bool CannotBeNull = true)
+ : ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}
+ std::string describe(DescriptionKind DK, ProgramStateRef State,
const Summary &Summary) const override;
StringRef getName() const override { return "NonNull"; }
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -300,13 +299,13 @@ class StdLibraryFunctionsChecker
// // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
class BufferSizeConstraint : public ValueConstraint {
// The concrete value which is the minimum size for the buffer.
- llvm::Optional<llvm::APSInt> ConcreteSize;
+ std::optional<llvm::APSInt> ConcreteSize;
// The argument which holds the size of the buffer.
- llvm::Optional<ArgNo> SizeArgN;
+ std::optional<ArgNo> SizeArgN;
// The argument which is a multiplier to size. This is set in case of
// `fread` like functions where the size is computed as a multiplication of
// two arguments.
- llvm::Optional<ArgNo> SizeMultiplierArgN;
+ std::optional<ArgNo> SizeMultiplierArgN;
// The operator we use in apply. This is negated in negate().
BinaryOperator::Opcode Op = BO_LE;
@@ -329,7 +328,7 @@ class StdLibraryFunctionsChecker
return Result;
}
- std::string describe(ProgramStateRef State,
+ std::string describe(DescriptionKind DK, ProgramStateRef State,
const Summary &Summary) const override;
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -392,45 +391,67 @@ class StdLibraryFunctionsChecker
using ConstraintSet = std::vector<ValueConstraintPtr>;
/// Define how a function affects the system variable 'errno'.
- /// This works together with the ErrnoModeling and ErrnoChecker classes.
+ /// This works together with the \c ErrnoModeling and \c ErrnoChecker classes.
+ /// Currently 3 use cases exist: success, failure, irrelevant.
+ /// In the future the failure case can be customized to set \c errno to a
+ /// more specific constraint (for example > 0), or new case can be added
+ /// for functions which require check of \c errno in both success and failure
+ /// case.
class ErrnoConstraintBase {
public:
/// Apply specific state changes related to the errno variable.
virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const = 0;
- /// Get a description about what is applied to 'errno' and how is it allowed
- /// to be used. If ErrnoChecker generates a bug then this message is
- /// displayed as a note at the function call.
- /// It may return empty string if no note tag is to be added.
- virtual std::string describe(StringRef FunctionName) const { return ""; }
+ /// Get a NoteTag about the changes made to 'errno' and the possible bug.
+ /// It may return \c nullptr (if no bug report from \c ErrnoChecker is
+ /// expected).
+ virtual const NoteTag *describe(CheckerContext &C,
+ StringRef FunctionName) const {
+ return nullptr;
+ }
virtual ~ErrnoConstraintBase() {}
protected:
- /// Many of the descendant classes use this value.
- const errno_modeling::ErrnoCheckState CheckState;
-
- ErrnoConstraintBase(errno_modeling::ErrnoCheckState CS) : CheckState(CS) {}
+ ErrnoConstraintBase() = default;
/// This is used for conjure symbol for errno to differentiate from the
/// original call expression (same expression is used for the errno symbol).
static int Tag;
};
- /// Set value of 'errno' to be related to 0 in a specified way, with a
- /// specified "errno check state". For example with \c BO_GT 'errno' is
- /// constrained to be greater than 0. Use this for failure cases of functions.
- class ZeroRelatedErrnoConstraint : public ErrnoConstraintBase {
- BinaryOperatorKind Op;
+ /// Reset errno constraints to irrelevant.
+ /// This is applicable to functions that may change 'errno' and are not
+ /// modeled elsewhere.
+ class ResetErrnoConstraint : public ErrnoConstraintBase {
+ public:
+ ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
+ const Summary &Summary,
+ CheckerContext &C) const override {
+ return errno_modeling::setErrnoState(State, errno_modeling::Irrelevant);
+ }
+ };
+ /// Do not change errno constraints.
+ /// This is applicable to functions that are modeled in another checker
+ /// and the already set errno constraints should not be changed in the
+ /// post-call event.
+ class NoErrnoConstraint : public ErrnoConstraintBase {
public:
- ZeroRelatedErrnoConstraint(clang::BinaryOperatorKind OpK,
- errno_modeling::ErrnoCheckState CS)
- : ErrnoConstraintBase(CS), Op(OpK) {
- assert(BinaryOperator::isComparisonOp(OpK));
+ ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
+ const Summary &Summary,
+ CheckerContext &C) const override {
+ return State;
}
+ };
+ /// Set errno constraint at failure cases of standard functions.
+ /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
+ /// by the program. \c ErrnoChecker does not emit a bug report after such a
+ /// function call.
+ class FailureErrnoConstraint : public ErrnoConstraintBase {
+ public:
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const override {
@@ -440,62 +461,40 @@ class StdLibraryFunctionsChecker
C.getLocationContext(), C.getASTContext().IntTy,
C.blockCount())
.castAs<NonLoc>();
- NonLoc ZeroVal =
- SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
- DefinedOrUnknownSVal Cond =
- SVB.evalBinOp(State, Op, ErrnoSVal, ZeroVal, SVB.getConditionType())
- .castAs<DefinedOrUnknownSVal>();
- State = State->assume(Cond, true);
- if (!State)
- return State;
- return errno_modeling::setErrnoValue(State, C.getLocationContext(),
- ErrnoSVal, CheckState);
- }
-
- std::string describe(StringRef FunctionName) const override {
- if (CheckState == errno_modeling::Irrelevant)
- return "";
- return (Twine("Assuming that function '") + FunctionName.str() +
- "' fails, in this case the value 'errno' becomes " +
- BinaryOperator::getOpcodeStr(Op).str() + " 0 and " +
- describeErrnoCheckState(CheckState))
- .str();
+ return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
}
};
- /// Applies the constraints to 'errno' for a common case when a standard
- /// function is successful. The value of 'errno' after the call is not
- /// specified by the standard (it may change or not). The \c ErrnoChecker can
- /// generate a bug if 'errno' is read afterwards.
+ /// Set errno constraint at success cases of standard functions.
+ /// Success case: 'errno' is not allowed to be used.
+ /// \c ErrnoChecker can emit bug report after such a function call if errno
+ /// is used.
class SuccessErrnoConstraint : public ErrnoConstraintBase {
public:
- SuccessErrnoConstraint()
- : ErrnoConstraintBase(errno_modeling::MustNotBeChecked) {}
-
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const override {
- return errno_modeling::setErrnoState(State, CheckState);
+ return errno_modeling::setErrnoForStdSuccess(State, C);
}
- std::string describe(StringRef FunctionName) const override {
- return (Twine("Assuming that function '") + FunctionName.str() +
- "' is successful, in this case the value 'errno' " +
- describeErrnoCheckState(CheckState))
- .str();
+ const NoteTag *describe(CheckerContext &C,
+ StringRef FunctionName) const override {
+ return errno_modeling::getNoteTagForStdSuccess(C, FunctionName);
}
};
- /// Set errno constraints if use of 'errno' is completely irrelevant to the
- /// modeled function or modeling is not possible.
- class NoErrnoConstraint : public ErrnoConstraintBase {
+ class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
public:
- NoErrnoConstraint() : ErrnoConstraintBase(errno_modeling::Irrelevant) {}
-
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const override {
- return errno_modeling::setErrnoState(State, CheckState);
+ return errno_modeling::setErrnoStdMustBeChecked(State, C,
+ Call.getOriginExpr());
+ }
+
+ const NoteTag *describe(CheckerContext &C,
+ StringRef FunctionName) const override {
+ return errno_modeling::getNoteTagForStdMustBeChecked(C, FunctionName);
}
};
@@ -542,8 +541,8 @@ class StdLibraryFunctionsChecker
StringRef getNote() const { return Note; }
};
- using ArgTypes = std::vector<Optional<QualType>>;
- using RetType = Optional<QualType>;
+ using ArgTypes = std::vector<std::optional<QualType>>;
+ using RetType = std::optional<QualType>;
// A placeholder type, we use it whenever we do not care about the concrete
// type in a Signature.
@@ -565,7 +564,7 @@ class StdLibraryFunctionsChecker
// Construct a signature from optional types. If any of the optional types
// are not set then the signature will be invalid.
Signature(ArgTypes ArgTys, RetType RetTy) {
- for (Optional<QualType> Arg : ArgTys) {
+ for (std::optional<QualType> Arg : ArgTys) {
if (!Arg) {
Invalid = true;
return;
@@ -718,10 +717,10 @@ public:
bool ShouldAssumeControlledEnvironment = false;
private:
- Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
- CheckerContext &C) const;
- Optional<Summary> findFunctionSummary(const CallEvent &Call,
- CheckerContext &C) const;
+ std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,
+ CheckerContext &C) const;
+ std::optional<Summary> findFunctionSummary(const CallEvent &Call,
+ CheckerContext &C) const;
void initFunctionSummaries(CheckerContext &C) const;
@@ -746,9 +745,12 @@ private:
// Highlight the range of the argument that was violated.
R->addRange(Call.getArgSourceRange(VC->getArgNo()));
- // Describe the argument constraint in a note.
- R->addNote(VC->describe(C.getState(), Summary), R->getLocation(),
- Call.getArgSourceRange(VC->getArgNo()));
+ // Describe the argument constraint violation in a note.
+ std::string Descr = VC->describe(
+ ValueConstraint::DescriptionKind::Violation, C.getState(), Summary);
+ // Capitalize the first letter b/c we want a full sentence.
+ Descr[0] = toupper(Descr[0]);
+ R->addNote(Descr, R->getLocation(), Call.getArgSourceRange(VC->getArgNo()));
C.emitReport(std::move(R));
}
@@ -758,10 +760,11 @@ private:
/// Usually if a failure return value exists for function, that function
/// needs different cases for success and failure with different errno
/// constraints (and different return value constraints).
- const NoErrnoConstraint ErrnoIrrelevant;
- const SuccessErrnoConstraint ErrnoMustNotBeChecked;
- const ZeroRelatedErrnoConstraint ErrnoNEZeroIrrelevant{
- clang::BinaryOperatorKind::BO_NE, errno_modeling::Irrelevant};
+ const NoErrnoConstraint ErrnoUnchanged{};
+ const ResetErrnoConstraint ErrnoIrrelevant{};
+ const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
+ const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
+ const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
};
int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
@@ -778,24 +781,26 @@ static BasicValueFactory &getBVF(ProgramStateRef State) {
}
std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
SmallString<48> Result;
- Result += "The ";
+ const auto Violation = ValueConstraint::DescriptionKind::Violation;
+ Result += "the ";
Result += getArgDesc(ArgN);
- Result += " should not be NULL";
+ Result += DK == Violation ? " should not be NULL" : " is not NULL";
return Result.c_str();
}
std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
BasicValueFactory &BVF = getBVF(State);
QualType T = Summary.getArgType(getArgNo());
SmallString<48> Result;
- Result += "The ";
+ const auto Violation = ValueConstraint::DescriptionKind::Violation;
+ Result += "the ";
Result += getArgDesc(ArgN);
- Result += " should be ";
+ Result += DK == Violation ? " should be " : " is ";
// Range kind as a string.
Kind == OutOfRange ? Result += "out of" : Result += "within";
@@ -827,16 +832,18 @@ StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) {
SmallString<8> Result;
Result += std::to_string(ArgN + 1);
Result += llvm::getOrdinalSuffix(ArgN + 1);
- Result += " arg";
+ Result += " argument";
return Result;
}
std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
SmallString<96> Result;
- Result += "The size of the ";
+ const auto Violation = ValueConstraint::DescriptionKind::Violation;
+ Result += "the size of the ";
Result += getArgDesc(ArgN);
- Result += " should be equal to or less than the value of ";
+ Result += DK == Violation ? " should be " : " is ";
+ Result += "equal to or greater than the value of ";
if (ConcreteSize) {
ConcreteSize->toString(Result);
} else if (SizeArgN) {
@@ -962,7 +969,7 @@ ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
+ std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
if (!FoundSummary)
return;
@@ -970,31 +977,43 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
ProgramStateRef State = C.getState();
ProgramStateRef NewState = State;
+ ExplodedNode *NewNode = C.getPredecessor();
for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
ProgramStateRef FailureSt =
Constraint->negate()->apply(NewState, Call, Summary, C);
// The argument constraint is not satisfied.
if (FailureSt && !SuccessSt) {
- if (ExplodedNode *N = C.generateErrorNode(NewState))
+ if (ExplodedNode *N = C.generateErrorNode(NewState, NewNode))
reportBug(Call, N, Constraint.get(), Summary, C);
break;
- } else {
- // We will apply the constraint even if we cannot reason about the
- // argument. This means both SuccessSt and FailureSt can be true. If we
- // weren't applying the constraint that would mean that symbolic
- // execution continues on a code whose behaviour is undefined.
- assert(SuccessSt);
- NewState = SuccessSt;
+ }
+ // We will apply the constraint even if we cannot reason about the
+ // argument. This means both SuccessSt and FailureSt can be true. If we
+ // weren't applying the constraint that would mean that symbolic
+ // execution continues on a code whose behaviour is undefined.
+ assert(SuccessSt);
+ NewState = SuccessSt;
+ if (NewState != State) {
+ SmallString<64> Msg;
+ Msg += "Assuming ";
+ Msg += Constraint->describe(ValueConstraint::DescriptionKind::Assumption,
+ NewState, Summary);
+ const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
+ NewNode = C.addTransition(
+ NewState, NewNode,
+ C.getNoteTag([Msg = std::move(Msg), ArgSVal](
+ PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
+ if (BR.isInteresting(ArgSVal))
+ OS << Msg;
+ }));
}
}
- if (NewState && NewState != State)
- C.addTransition(NewState);
}
void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
+ std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
if (!FoundSummary)
return;
@@ -1017,13 +1036,10 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
if (NewState && NewState != State) {
if (Case.getNote().empty()) {
- std::string Note;
+ const NoteTag *NT = nullptr;
if (const auto *D = dyn_cast_or_null<FunctionDecl>(Call.getDecl()))
- Note = Case.getErrnoConstraint().describe(D->getNameAsString());
- if (Note.empty())
- C.addTransition(NewState);
- else
- C.addTransition(NewState, errno_modeling::getErrnoNoteTag(C, Note));
+ NT = Case.getErrnoConstraint().describe(C, D->getNameAsString());
+ C.addTransition(NewState, NT);
} else {
StringRef Note = Case.getNote();
const NoteTag *Tag = C.getNoteTag(
@@ -1036,13 +1052,23 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
/*IsPrunable=*/true);
C.addTransition(NewState, Tag);
}
+ } else if (NewState == State) {
+ // It is possible that the function was evaluated in a checker callback
+ // where the state constraints are already applied, then no change happens
+ // here to the state (if the ErrnoConstraint did not change it either).
+ // If the evaluated function requires a NoteTag for errno change, it is
+ // added here.
+ if (const auto *D = dyn_cast_or_null<FunctionDecl>(Call.getDecl()))
+ if (const NoteTag *NT =
+ Case.getErrnoConstraint().describe(C, D->getNameAsString()))
+ C.addTransition(NewState, NT);
}
}
}
bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
+ std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
if (!FoundSummary)
return false;
@@ -1109,26 +1135,26 @@ bool StdLibraryFunctionsChecker::Signature::matches(
return true;
}
-Optional<StdLibraryFunctionsChecker::Summary>
+std::optional<StdLibraryFunctionsChecker::Summary>
StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
CheckerContext &C) const {
if (!FD)
- return None;
+ return std::nullopt;
initFunctionSummaries(C);
auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
if (FSMI == FunctionSummaryMap.end())
- return None;
+ return std::nullopt;
return FSMI->second;
}
-Optional<StdLibraryFunctionsChecker::Summary>
+std::optional<StdLibraryFunctionsChecker::Summary>
StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
CheckerContext &C) const {
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
if (!FD)
- return None;
+ return std::nullopt;
return findFunctionSummary(FD, C);
}
@@ -1149,11 +1175,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
// Find the type. If not found then the optional is not set.
- llvm::Optional<QualType> operator()(StringRef Name) {
+ std::optional<QualType> operator()(StringRef Name) {
IdentifierInfo &II = ACtx.Idents.get(Name);
auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
if (LookupRes.empty())
- return None;
+ return std::nullopt;
// Prioritze typedef declarations.
// This is needed in case of C struct typedefs. E.g.:
@@ -1171,7 +1197,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
for (Decl *D : LookupRes)
if (auto *TD = dyn_cast<TypeDecl>(D))
return ACtx.getTypeDeclType(TD).getCanonicalType();
- return None;
+ return std::nullopt;
}
} lookupTy(ACtx);
@@ -1185,10 +1211,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
QualType operator()(QualType Ty) {
return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
}
- Optional<QualType> operator()(Optional<QualType> Ty) {
+ std::optional<QualType> operator()(std::optional<QualType> Ty) {
if (Ty)
return operator()(*Ty);
- return None;
+ return std::nullopt;
}
} getRestrictTy(ACtx);
class GetPointerTy {
@@ -1197,16 +1223,16 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
public:
GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
- Optional<QualType> operator()(Optional<QualType> Ty) {
+ std::optional<QualType> operator()(std::optional<QualType> Ty) {
if (Ty)
return operator()(*Ty);
- return None;
+ return std::nullopt;
}
} getPointerTy(ACtx);
class {
public:
- Optional<QualType> operator()(Optional<QualType> Ty) {
- return Ty ? Optional<QualType>(Ty->withConst()) : None;
+ std::optional<QualType> operator()(std::optional<QualType> Ty) {
+ return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
}
QualType operator()(QualType Ty) { return Ty.withConst(); }
} getConstTy;
@@ -1215,14 +1241,14 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
public:
GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
- Optional<RangeInt> operator()(QualType Ty) {
+ std::optional<RangeInt> operator()(QualType Ty) {
return BVF.getMaxValue(Ty).getLimitedValue();
}
- Optional<RangeInt> operator()(Optional<QualType> Ty) {
+ std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
if (Ty) {
return operator()(*Ty);
}
- return None;
+ return std::nullopt;
}
} getMaxValue(BVF);
@@ -1278,7 +1304,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// The platform dependent value of EOF.
// Try our best to parse this from the Preprocessor, otherwise fallback to -1.
const auto EOFv = [&C]() -> RangeInt {
- if (const llvm::Optional<int> OptInt =
+ if (const std::optional<int> OptInt =
tryExpandAsInteger("EOF", C.getPreprocessor()))
return *OptInt;
return -1;
@@ -1351,13 +1377,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
auto operator()(RangeInt b, RangeInt e) {
return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
}
- auto operator()(RangeInt b, Optional<RangeInt> e) {
+ auto operator()(RangeInt b, std::optional<RangeInt> e) {
if (e)
return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
return IntRangeVector{};
}
auto operator()(std::pair<RangeInt, RangeInt> i0,
- std::pair<RangeInt, Optional<RangeInt>> i1) {
+ std::pair<RangeInt, std::optional<RangeInt>> i1) {
if (i1.second)
return IntRangeVector{i0, {i1.first, *(i1.second)}};
return IntRangeVector{i0};
@@ -1370,10 +1396,18 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
auto NotNull = [&](ArgNo ArgN) {
return std::make_shared<NotNullConstraint>(ArgN);
};
+ auto IsNull = [&](ArgNo ArgN) {
+ return std::make_shared<NotNullConstraint>(ArgN, false);
+ };
- Optional<QualType> FileTy = lookupTy("FILE");
- Optional<QualType> FilePtrTy = getPointerTy(FileTy);
- Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
+ std::optional<QualType> FileTy = lookupTy("FILE");
+ std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
+ std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
+
+ std::optional<QualType> FPosTTy = lookupTy("fpos_t");
+ std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
+ std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
+ std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
// We are finally ready to define specifications for all supported functions.
//
@@ -1599,11 +1633,23 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// read()-like functions that never return more than buffer size.
auto FreadSummary =
Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
+ .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
+ ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
+ ReturnValueCondition(BO_LT, ArgNo(2)),
ReturnValueCondition(WithinRange, Range(0, SizeMax))},
- ErrnoIrrelevant)
+ ErrnoNEZeroIrrelevant)
+ .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
+ ReturnValueCondition(BO_EQ, ArgNo(2)),
+ ReturnValueCondition(WithinRange, Range(0, SizeMax))},
+ ErrnoMustNotBeChecked)
+ .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
+ ReturnValueCondition(WithinRange, SingleValue(0))},
+ ErrnoMustNotBeChecked)
.ArgConstraint(NotNull(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(3)))
+ // FIXME: It should be allowed to have a null buffer if any of
+ // args 1 or 2 are zero. Remove NotNull check of arg 0, add a check
+ // for non-null buffer if non-zero size to BufferSizeConstraint?
.ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
/*BufSizeMultiplier=*/ArgNo(2)));
@@ -1622,8 +1668,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
RetType{SizeTy}),
FreadSummary);
- Optional<QualType> Ssize_tTy = lookupTy("ssize_t");
- Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
+ std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
+ std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
auto ReadSummary =
Summary(NoEvalCall)
@@ -1689,6 +1735,142 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
}
if (ModelPOSIX) {
+ const auto ReturnsZeroOrMinusOne =
+ ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
+ const auto ReturnsZero =
+ ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
+ const auto ReturnsMinusOne =
+ ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
+ const auto ReturnsNonnegative =
+ ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
+ const auto ReturnsNonZero =
+ ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
+ const auto ReturnsFileDescriptor =
+ ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
+ const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
+
+ // FILE *fopen(const char *restrict pathname, const char *restrict mode);
+ addToFunctionSummaryMap(
+ "fopen",
+ Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
+ RetType{FilePtrTy}),
+ Summary(NoEvalCall)
+ .Case({NotNull(Ret)}, ErrnoMustNotBeChecked)
+ .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ // FILE *tmpfile(void);
+ addToFunctionSummaryMap("tmpfile",
+ Signature(ArgTypes{}, RetType{FilePtrTy}),
+ Summary(NoEvalCall)
+ .Case({NotNull(Ret)}, ErrnoMustNotBeChecked)
+ .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant));
+
+ // FILE *freopen(const char *restrict pathname, const char *restrict mode,
+ // FILE *restrict stream);
+ addToFunctionSummaryMap(
+ "freopen",
+ Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
+ FilePtrRestrictTy},
+ RetType{FilePtrTy}),
+ Summary(NoEvalCall)
+ .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
+ ErrnoMustNotBeChecked)
+ .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(1)))
+ .ArgConstraint(NotNull(ArgNo(2))));
+
+ // int fclose(FILE *stream);
+ addToFunctionSummaryMap(
+ "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsZero, ErrnoMustNotBeChecked)
+ .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
+ ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // int fseek(FILE *stream, long offset, int whence);
+ // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
+ // these for condition of arg 2.
+ // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
+ addToFunctionSummaryMap(
+ "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsZero, ErrnoMustNotBeChecked)
+ .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
+
+ // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
+ // From 'The Open Group Base Specifications Issue 7, 2018 edition':
+ // "The fgetpos() function shall not change the setting of errno if
+ // successful."
+ addToFunctionSummaryMap(
+ "fgetpos",
+ Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
+ RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsZero, ErrnoUnchanged)
+ .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ // int fsetpos(FILE *stream, const fpos_t *pos);
+ // From 'The Open Group Base Specifications Issue 7, 2018 edition':
+ // "The fsetpos() function shall not change the setting of errno if
+ // successful."
+ addToFunctionSummaryMap(
+ "fsetpos",
+ Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsZero, ErrnoUnchanged)
+ .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ // long ftell(FILE *stream);
+ // From 'The Open Group Base Specifications Issue 7, 2018 edition':
+ // "The ftell() function shall not change the setting of errno if
+ // successful."
+ addToFunctionSummaryMap(
+ "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
+ Summary(NoEvalCall)
+ .Case({ReturnValueCondition(WithinRange, Range(1, LongMax))},
+ ErrnoUnchanged)
+ .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // int fileno(FILE *stream);
+ addToFunctionSummaryMap(
+ "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
+ .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // void rewind(FILE *stream);
+ // This function indicates error only by setting of 'errno'.
+ addToFunctionSummaryMap("rewind",
+ Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
+ Summary(NoEvalCall)
+ .Case({}, ErrnoMustBeChecked)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // void clearerr(FILE *stream);
+ addToFunctionSummaryMap(
+ "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
+ Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+
+ // int feof(FILE *stream);
+ addToFunctionSummaryMap(
+ "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+
+ // int ferror(FILE *stream);
+ addToFunctionSummaryMap(
+ "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
// long a64l(const char *str64);
addToFunctionSummaryMap(
@@ -1702,18 +1884,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(ArgumentCondition(
0, WithinRange, Range(0, LongMax))));
- const auto ReturnsZeroOrMinusOne =
- ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
- const auto ReturnsZero =
- ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
- const auto ReturnsMinusOne =
- ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
- const auto ReturnsNonnegative =
- ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
- const auto ReturnsFileDescriptor =
- ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
- const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
-
// int access(const char *pathname, int amode);
addToFunctionSummaryMap(
"access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
@@ -1777,7 +1947,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(ArgumentCondition(
0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Off_tTy = lookupTy("off_t");
+ std::optional<QualType> Off_tTy = lookupTy("off_t");
// int truncate(const char *path, off_t length);
addToFunctionSummaryMap(
@@ -1819,7 +1989,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Mode_tTy = lookupTy("mode_t");
+ std::optional<QualType> Mode_tTy = lookupTy("mode_t");
// int creat(const char *pathname, mode_t mode);
addToFunctionSummaryMap(
@@ -1836,8 +2006,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
- Optional<QualType> DirTy = lookupTy("DIR");
- Optional<QualType> DirPtrTy = getPointerTy(DirTy);
+ std::optional<QualType> DirTy = lookupTy("DIR");
+ std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
// int dirfd(DIR *dirp);
addToFunctionSummaryMap(
@@ -1920,7 +2090,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> Dev_tTy = lookupTy("dev_t");
+ std::optional<QualType> Dev_tTy = lookupTy("dev_t");
// int mknod(const char *pathname, mode_t mode, dev_t dev);
addToFunctionSummaryMap(
@@ -1969,8 +2139,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Uid_tTy = lookupTy("uid_t");
- Optional<QualType> Gid_tTy = lookupTy("gid_t");
+ std::optional<QualType> Uid_tTy = lookupTy("uid_t");
+ std::optional<QualType> Gid_tTy = lookupTy("gid_t");
// int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
// int flags);
@@ -2069,9 +2239,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructStatTy = lookupTy("stat");
- Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
- Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy);
+ std::optional<QualType> StructStatTy = lookupTy("stat");
+ std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
+ std::optional<QualType> StructStatPtrRestrictTy =
+ getRestrictTy(StructStatPtrTy);
// int fstat(int fd, struct stat *statbuf);
addToFunctionSummaryMap(
@@ -2200,14 +2371,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
"rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int fileno(FILE *stream);
- addToFunctionSummaryMap(
- "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
- .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
- .ArgConstraint(NotNull(ArgNo(0))));
-
// int fseeko(FILE *stream, off_t offset, int whence);
addToFunctionSummaryMap(
"fseeko",
@@ -2233,7 +2396,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
- Optional<QualType> Off64_tTy = lookupTy("off64_t");
+ std::optional<QualType> Off64_tTy = lookupTy("off64_t");
// void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
// off64_t offset);
// FIXME: Improve for errno modeling.
@@ -2358,18 +2521,20 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(NotNull(ArgNo(1)))
.ArgConstraint(NotNull(ArgNo(2))));
- Optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
- Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy);
- Optional<QualType> ConstStructSockaddrPtrTy =
+ std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
+ std::optional<QualType> StructSockaddrPtrTy =
+ getPointerTy(StructSockaddrTy);
+ std::optional<QualType> ConstStructSockaddrPtrTy =
getPointerTy(getConstTy(StructSockaddrTy));
- Optional<QualType> StructSockaddrPtrRestrictTy =
+ std::optional<QualType> StructSockaddrPtrRestrictTy =
getRestrictTy(StructSockaddrPtrTy);
- Optional<QualType> ConstStructSockaddrPtrRestrictTy =
+ std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
getRestrictTy(ConstStructSockaddrPtrTy);
- Optional<QualType> Socklen_tTy = lookupTy("socklen_t");
- Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
- Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy);
- Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
+ std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
+ std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
+ std::optional<QualType> Socklen_tPtrRestrictTy =
+ getRestrictTy(Socklen_tPtrTy);
+ std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
// In 'socket.h' of some libc implementations with C99, sockaddr parameter
// is a transparent union of the underlying sockaddr_ family of pointers
@@ -2568,9 +2733,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
/*BufSize=*/ArgNo(2))));
- Optional<QualType> StructMsghdrTy = lookupTy("msghdr");
- Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
- Optional<QualType> ConstStructMsghdrPtrTy =
+ std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
+ std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
+ std::optional<QualType> ConstStructMsghdrPtrTy =
getPointerTy(getConstTy(StructMsghdrTy));
// ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
@@ -2676,8 +2841,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
- Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
- Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
+ std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
+ std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
// int utime(const char *filename, struct utimbuf *buf);
addToFunctionSummaryMap(
@@ -2688,9 +2853,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> StructTimespecTy = lookupTy("timespec");
- Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
- Optional<QualType> ConstStructTimespecPtrTy =
+ std::optional<QualType> StructTimespecTy = lookupTy("timespec");
+ std::optional<QualType> StructTimespecPtrTy =
+ getPointerTy(StructTimespecTy);
+ std::optional<QualType> ConstStructTimespecPtrTy =
getPointerTy(getConstTy(StructTimespecTy));
// int futimens(int fd, const struct timespec times[2]);
@@ -2714,8 +2880,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructTimevalTy = lookupTy("timeval");
- Optional<QualType> ConstStructTimevalPtrTy =
+ std::optional<QualType> StructTimevalTy = lookupTy("timeval");
+ std::optional<QualType> ConstStructTimevalPtrTy =
getPointerTy(getConstTy(StructTimevalTy));
// int utimes(const char *filename, const struct timeval times[2]);
@@ -2738,17 +2904,19 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> Time_tTy = lookupTy("time_t");
- Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
- Optional<QualType> ConstTime_tPtrRestrictTy =
+ std::optional<QualType> Time_tTy = lookupTy("time_t");
+ std::optional<QualType> ConstTime_tPtrTy =
+ getPointerTy(getConstTy(Time_tTy));
+ std::optional<QualType> ConstTime_tPtrRestrictTy =
getRestrictTy(ConstTime_tPtrTy);
- Optional<QualType> StructTmTy = lookupTy("tm");
- Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
- Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
- Optional<QualType> ConstStructTmPtrTy =
+ std::optional<QualType> StructTmTy = lookupTy("tm");
+ std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
+ std::optional<QualType> StructTmPtrRestrictTy =
+ getRestrictTy(StructTmPtrTy);
+ std::optional<QualType> ConstStructTmPtrTy =
getPointerTy(getConstTy(StructTmTy));
- Optional<QualType> ConstStructTmPtrRestrictTy =
+ std::optional<QualType> ConstStructTmPtrRestrictTy =
getRestrictTy(ConstStructTmPtrTy);
// struct tm * localtime(const time_t *tp);
@@ -2804,7 +2972,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
"gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
+ std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
// int clock_gettime(clockid_t clock_id, struct timespec *tp);
addToFunctionSummaryMap(
@@ -2815,8 +2983,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructItimervalTy = lookupTy("itimerval");
- Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
+ std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
+ std::optional<QualType> StructItimervalPtrTy =
+ getPointerTy(StructItimervalTy);
// int getitimer(int which, struct itimerval *curr_value);
addToFunctionSummaryMap(
@@ -2827,25 +2996,30 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
- Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy);
- Optional<QualType> Pthread_tTy = lookupTy("pthread_t");
- Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
- Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy);
- Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
- Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy);
- Optional<QualType> Pthread_mutex_tPtrRestrictTy =
+ std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
+ std::optional<QualType> Pthread_cond_tPtrTy =
+ getPointerTy(Pthread_cond_tTy);
+ std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
+ std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
+ std::optional<QualType> Pthread_tPtrRestrictTy =
+ getRestrictTy(Pthread_tPtrTy);
+ std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
+ std::optional<QualType> Pthread_mutex_tPtrTy =
+ getPointerTy(Pthread_mutex_tTy);
+ std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
getRestrictTy(Pthread_mutex_tPtrTy);
- Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
- Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy);
- Optional<QualType> ConstPthread_attr_tPtrTy =
+ std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
+ std::optional<QualType> Pthread_attr_tPtrTy =
+ getPointerTy(Pthread_attr_tTy);
+ std::optional<QualType> ConstPthread_attr_tPtrTy =
getPointerTy(getConstTy(Pthread_attr_tTy));
- Optional<QualType> ConstPthread_attr_tPtrRestrictTy =
+ std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
getRestrictTy(ConstPthread_attr_tPtrTy);
- Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t");
- Optional<QualType> ConstPthread_mutexattr_tPtrTy =
+ std::optional<QualType> Pthread_mutexattr_tTy =
+ lookupTy("pthread_mutexattr_t");
+ std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
getPointerTy(getConstTy(Pthread_mutexattr_tTy));
- Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
+ std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
getRestrictTy(ConstPthread_mutexattr_tPtrTy);
QualType PthreadStartRoutineTy = getPointerTy(
@@ -2929,6 +3103,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// Test range values.
addToFunctionSummaryMap(
+ "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
+ addToFunctionSummaryMap(
"__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
.ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
@@ -2996,6 +3174,15 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
"__test_restrict_param_2"},
Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
Summary(EvalCallAsPure));
+
+ // Test the application of cases.
+ addToFunctionSummaryMap(
+ "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
+ ErrnoIrrelevant, "Function returns 0")
+ .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
+ ErrnoIrrelevant, "Function returns 1"));
}
SummariesInitialized = true;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 1aa665f0ef45..3f61dd823940 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -17,10 +17,12 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include <functional>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -85,10 +87,10 @@ const StreamErrorState ErrorFError{false, false, true};
/// Full state information about a stream pointer.
struct StreamState {
/// The last file operation called in the stream.
+ /// Can be nullptr.
const FnDescription *LastOperation;
/// State of a stream symbol.
- /// FIXME: We need maybe an "escaped" state later.
enum KindTy {
Opened, /// Stream is opened.
Closed, /// Closed stream (an invalid stream pointer after it was closed).
@@ -202,13 +204,12 @@ ProgramStateRef bindAndAssumeTrue(ProgramStateRef State, CheckerContext &C,
ProgramStateRef bindInt(uint64_t Value, ProgramStateRef State,
CheckerContext &C, const CallExpr *CE) {
State = State->BindExpr(CE, C.getLocationContext(),
- C.getSValBuilder().makeIntVal(Value, false));
+ C.getSValBuilder().makeIntVal(Value, CE->getType()));
return State;
}
class StreamChecker : public Checker<check::PreCall, eval::Call,
check::DeadSymbols, check::PointerEscape> {
- BugType BT_FileNull{this, "NULL stream pointer", "Stream handling error"};
BugType BT_UseAfterClose{this, "Closed stream", "Stream handling error"};
BugType BT_UseAfterOpenFailed{this, "Invalid stream",
"Stream handling error"};
@@ -236,48 +237,55 @@ public:
private:
CallDescriptionMap<FnDescription> FnDescriptions = {
- {{"fopen"}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
- {{"freopen", 3},
+ {{{"fopen"}}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
+ {{{"freopen"}, 3},
{&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}},
- {{"tmpfile"}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
- {{"fclose", 1},
+ {{{"tmpfile"}}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
+ {{{"fclose"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalFclose, 0}},
- {{"fread", 4},
+ {{{"fread"}, 4},
{&StreamChecker::preFread,
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, true), 3}},
- {{"fwrite", 4},
+ {{{"fwrite"}, 4},
{&StreamChecker::preFwrite,
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, false), 3}},
- {{"fseek", 3}, {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
- {{"ftell", 1}, {&StreamChecker::preDefault, nullptr, 0}},
- {{"rewind", 1}, {&StreamChecker::preDefault, nullptr, 0}},
- {{"fgetpos", 2}, {&StreamChecker::preDefault, nullptr, 0}},
- {{"fsetpos", 2}, {&StreamChecker::preDefault, nullptr, 0}},
- {{"clearerr", 1},
+ {{{"fseek"}, 3},
+ {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
+ {{{"ftell"}, 1},
+ {&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}},
+ {{{"rewind"}, 1},
+ {&StreamChecker::preDefault, &StreamChecker::evalRewind, 0}},
+ {{{"fgetpos"}, 2},
+ {&StreamChecker::preDefault, &StreamChecker::evalFgetpos, 0}},
+ {{{"fsetpos"}, 2},
+ {&StreamChecker::preDefault, &StreamChecker::evalFsetpos, 0}},
+ {{{"clearerr"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalClearerr, 0}},
- {{"feof", 1},
+ {{{"feof"}, 1},
{&StreamChecker::preDefault,
std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4, ErrorFEof),
0}},
- {{"ferror", 1},
+ {{{"ferror"}, 1},
{&StreamChecker::preDefault,
std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4, ErrorFError),
0}},
- {{"fileno", 1}, {&StreamChecker::preDefault, nullptr, 0}},
+ {{{"fileno"}, 1}, {&StreamChecker::preDefault, nullptr, 0}},
};
CallDescriptionMap<FnDescription> FnTestDescriptions = {
- {{"StreamTesterChecker_make_feof_stream", 1},
+ {{{"StreamTesterChecker_make_feof_stream"}, 1},
{nullptr,
std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof),
0}},
- {{"StreamTesterChecker_make_ferror_stream", 1},
+ {{{"StreamTesterChecker_make_ferror_stream"}, 1},
{nullptr,
std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4,
ErrorFError),
0}},
};
+ mutable std::optional<int> EofVal;
+
void evalFopen(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
@@ -303,6 +311,18 @@ private:
void evalFseek(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
+ void evalFgetpos(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void evalFsetpos(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void evalFtell(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void evalRewind(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
void preDefault(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
@@ -318,7 +338,7 @@ private:
const StreamErrorState &ErrorKind) const;
/// Check that the stream (in StreamVal) is not NULL.
- /// If it can only be NULL a fatal error is emitted and nullptr returned.
+ /// If it can only be NULL a sink node is generated and nullptr returned.
/// Otherwise the return value is a new state where the stream is constrained
/// to be non-null.
ProgramStateRef ensureStreamNonNull(SVal StreamVal, const Expr *StreamE,
@@ -368,7 +388,7 @@ private:
// (and matching name) as stream functions.
if (!Call.isGlobalCFunction())
return nullptr;
- for (auto P : Call.parameters()) {
+ for (auto *P : Call.parameters()) {
QualType T = P->getType();
if (!T->isIntegralOrEnumerationType() && !T->isPointerType())
return nullptr;
@@ -411,6 +431,17 @@ private:
});
}
+ void initEof(CheckerContext &C) const {
+ if (EofVal)
+ return;
+
+ if (const std::optional<int> OptInt =
+ tryExpandAsInteger("EOF", C.getPreprocessor()))
+ EofVal = *OptInt;
+ else
+ EofVal = -1;
+ }
+
/// Searches for the ExplodedNode where the file descriptor was acquired for
/// StreamSym.
static const ExplodedNode *getAcquisitionSite(const ExplodedNode *N,
@@ -426,8 +457,7 @@ private:
REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
inline void assertStreamStateOpened(const StreamState *SS) {
- assert(SS->isOpened() &&
- "Previous create of error node for non-opened stream failed?");
+ assert(SS->isOpened() && "Stream is expected to be opened");
}
const ExplodedNode *StreamChecker::getAcquisitionSite(const ExplodedNode *N,
@@ -457,6 +487,8 @@ const ExplodedNode *StreamChecker::getAcquisitionSite(const ExplodedNode *N,
void StreamChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
+ initEof(C);
+
const FnDescription *Desc = lookupFn(Call);
if (!Desc || !Desc->PreFn)
return;
@@ -526,7 +558,7 @@ void StreamChecker::evalFreopen(const FnDescription *Desc,
if (!CE)
return;
- Optional<DefinedSVal> StreamVal =
+ std::optional<DefinedSVal> StreamVal =
getStreamArg(Desc, Call).getAs<DefinedSVal>();
if (!StreamVal)
return;
@@ -574,6 +606,10 @@ void StreamChecker::evalFclose(const FnDescription *Desc, const CallEvent &Call,
if (!SS)
return;
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
assertStreamStateOpened(SS);
// Close the File Descriptor.
@@ -581,7 +617,16 @@ void StreamChecker::evalFclose(const FnDescription *Desc, const CallEvent &Call,
// and can not be used any more.
State = State->set<StreamMap>(Sym, StreamState::getClosed(Desc));
- C.addTransition(State);
+ // Return 0 on success, EOF on failure.
+ SValBuilder &SVB = C.getSValBuilder();
+ ProgramStateRef StateSuccess = State->BindExpr(
+ CE, C.getLocationContext(), SVB.makeIntVal(0, C.getASTContext().IntTy));
+ ProgramStateRef StateFailure =
+ State->BindExpr(CE, C.getLocationContext(),
+ SVB.makeIntVal(*EofVal, C.getASTContext().IntTy));
+
+ C.addTransition(StateSuccess);
+ C.addTransition(StateFailure);
}
void StreamChecker::preFread(const FnDescription *Desc, const CallEvent &Call,
@@ -639,10 +684,10 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
if (!CE)
return;
- Optional<NonLoc> SizeVal = Call.getArgSVal(1).getAs<NonLoc>();
+ std::optional<NonLoc> SizeVal = Call.getArgSVal(1).getAs<NonLoc>();
if (!SizeVal)
return;
- Optional<NonLoc> NMembVal = Call.getArgSVal(2).getAs<NonLoc>();
+ std::optional<NonLoc> NMembVal = Call.getArgSVal(2).getAs<NonLoc>();
if (!NMembVal)
return;
@@ -766,6 +811,131 @@ void StreamChecker::evalFseek(const FnDescription *Desc, const CallEvent &Call,
C.addTransition(StateFailed, constructSetEofNoteTag(C, StreamSym));
}
+void StreamChecker::evalFgetpos(const FnDescription *Desc,
+ const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef Sym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!Sym)
+ return;
+
+ // Do not evaluate if stream is not found.
+ if (!State->get<StreamMap>(Sym))
+ return;
+
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ DefinedSVal RetVal = makeRetVal(C, CE);
+ State = State->BindExpr(CE, C.getLocationContext(), RetVal);
+ ProgramStateRef StateNotFailed, StateFailed;
+ std::tie(StateFailed, StateNotFailed) =
+ C.getConstraintManager().assumeDual(State, RetVal);
+
+ // This function does not affect the stream state.
+ // Still we add success and failure state with the appropriate return value.
+ // StdLibraryFunctionsChecker can change these states (set the 'errno' state).
+ C.addTransition(StateNotFailed);
+ C.addTransition(StateFailed);
+}
+
+void StreamChecker::evalFsetpos(const FnDescription *Desc,
+ const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!StreamSym)
+ return;
+
+ const StreamState *SS = State->get<StreamMap>(StreamSym);
+ if (!SS)
+ return;
+
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ assertStreamStateOpened(SS);
+
+ DefinedSVal RetVal = makeRetVal(C, CE);
+ State = State->BindExpr(CE, C.getLocationContext(), RetVal);
+ ProgramStateRef StateNotFailed, StateFailed;
+ std::tie(StateFailed, StateNotFailed) =
+ C.getConstraintManager().assumeDual(State, RetVal);
+
+ StateNotFailed = StateNotFailed->set<StreamMap>(
+ StreamSym, StreamState::getOpened(Desc, ErrorNone, false));
+
+ // At failure ferror could be set.
+ // The standards do not tell what happens with the file position at failure.
+ // But we can assume that it is dangerous to make a next I/O operation after
+ // the position was not set correctly (similar to 'fseek').
+ StateFailed = StateFailed->set<StreamMap>(
+ StreamSym, StreamState::getOpened(Desc, ErrorNone | ErrorFError, true));
+
+ C.addTransition(StateNotFailed);
+ C.addTransition(StateFailed);
+}
+
+void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef Sym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!Sym)
+ return;
+
+ if (!State->get<StreamMap>(Sym))
+ return;
+
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ SValBuilder &SVB = C.getSValBuilder();
+ NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
+ ProgramStateRef StateNotFailed =
+ State->BindExpr(CE, C.getLocationContext(), RetVal);
+ auto Cond = SVB.evalBinOp(State, BO_GE, RetVal,
+ SVB.makeZeroVal(C.getASTContext().LongTy),
+ SVB.getConditionType())
+ .getAs<DefinedOrUnknownSVal>();
+ if (!Cond)
+ return;
+ StateNotFailed = StateNotFailed->assume(*Cond, true);
+ if (!StateNotFailed)
+ return;
+
+ ProgramStateRef StateFailed = State->BindExpr(
+ CE, C.getLocationContext(), SVB.makeIntVal(-1, C.getASTContext().LongTy));
+
+ C.addTransition(StateNotFailed);
+ C.addTransition(StateFailed);
+}
+
+void StreamChecker::evalRewind(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!StreamSym)
+ return;
+
+ const StreamState *SS = State->get<StreamMap>(StreamSym);
+ if (!SS)
+ return;
+
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ assertStreamStateOpened(SS);
+
+ State = State->set<StreamMap>(StreamSym,
+ StreamState::getOpened(Desc, ErrorNone, false));
+
+ C.addTransition(State);
+}
+
void StreamChecker::evalClearerr(const FnDescription *Desc,
const CallEvent &Call,
CheckerContext &C) const {
@@ -869,13 +1039,11 @@ StreamChecker::ensureStreamNonNull(SVal StreamVal, const Expr *StreamE,
std::tie(StateNotNull, StateNull) = CM.assumeDual(C.getState(), *Stream);
if (!StateNotNull && StateNull) {
- if (ExplodedNode *N = C.generateErrorNode(StateNull)) {
- auto R = std::make_unique<PathSensitiveBugReport>(
- BT_FileNull, "Stream pointer might be NULL.", N);
- if (StreamE)
- bugreporter::trackExpressionValue(N, StreamE, *R);
- C.emitReport(std::move(R));
- }
+ // Stream argument is NULL, stop analysis on this path.
+ // This case should occur only if StdLibraryFunctionsChecker (or ModelPOSIX
+ // option of it) is not turned on, otherwise that checker ensures non-null
+ // argument.
+ C.generateSink(StateNull, C.getPredecessor());
return nullptr;
}
@@ -976,7 +1144,8 @@ ProgramStateRef StreamChecker::ensureNoFilePositionIndeterminate(
ProgramStateRef
StreamChecker::ensureFseekWhenceCorrect(SVal WhenceVal, CheckerContext &C,
ProgramStateRef State) const {
- Optional<nonloc::ConcreteInt> CI = WhenceVal.getAs<nonloc::ConcreteInt>();
+ std::optional<nonloc::ConcreteInt> CI =
+ WhenceVal.getAs<nonloc::ConcreteInt>();
if (!CI)
return State;
diff --git a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
index 44162094e49a..a95c0e183284 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Checkers/Taint.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -63,7 +64,7 @@ ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
// their parent region, which is a conjured symbol default-bound to the base
// region of the parent region.
if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
- if (Optional<SVal> binding =
+ if (std::optional<SVal> binding =
State->getStateManager().getStoreManager().getDefaultBinding(
*LCV)) {
if (SymbolRef Sym = binding->getAsSymbol())
diff --git a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
index eeec807ccee4..28fe11d5ed06 100644
--- a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/FoldingSet.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -100,7 +101,7 @@ DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC,
const Expr *E = nullptr;
- if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
+ if (std::optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
BinaryOperator::Opcode Op = BO->getOpcode();
if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
@@ -132,7 +133,7 @@ DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC,
}
bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const {
- Optional<DefinedSVal> DSV = S.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> DSV = S.getAs<DefinedSVal>();
if (!DSV)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index ebe5ad53cc30..b17b983f0345 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -18,6 +18,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
#include <utility>
using namespace clang;
@@ -93,7 +94,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
ProgramPoint P = PrevN->getLocation();
ProgramStateRef St = N->getState();
- if (Optional<PostStmt> PS = P.getAs<PostStmt>())
+ if (std::optional<PostStmt> PS = P.getAs<PostStmt>())
if (PS->getStmt() == Ex)
St = PrevN->getState();
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 816a547cadc3..27f3345e67ac 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -69,8 +70,8 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
continue;
// Get the VarRegion associated with VD in the local stack frame.
- if (Optional<UndefinedVal> V =
- state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
+ if (std::optional<UndefinedVal> V =
+ state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT)
BT.reset(
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 05f8f6084c0b..0fa3d6043971 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -92,7 +92,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (const auto *CD =
dyn_cast<CXXConstructorDecl>(C.getStackFrame()->getDecl())) {
if (CD->isImplicit()) {
- for (auto I : CD->inits()) {
+ for (auto *I : CD->inits()) {
if (I->getInit()->IgnoreImpCasts() == StoreE) {
OS << "Value assigned to field '" << I->getMember()->getName()
<< "' in implicit constructor is garbage or undefined";
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
new file mode 100644
index 000000000000..f053ee887a1a
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
@@ -0,0 +1,80 @@
+//===--- UndefinedNewArraySizeChecker.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
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedNewArraySizeChecker, a builtin check in ExprEngine
+// that checks if the size of the array in a new[] expression is undefined.
+//
+//===----------------------------------------------------------------------===//
+
+#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/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class UndefinedNewArraySizeChecker : public Checker<check::PreCall> {
+
+private:
+ BugType BT{this, "Undefined array element count in new[]",
+ categories::LogicError};
+
+public:
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void HandleUndefinedArrayElementCount(CheckerContext &C, SVal ArgVal,
+ const Expr *Init,
+ SourceRange Range) const;
+};
+} // namespace
+
+void UndefinedNewArraySizeChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ if (const auto *AC = dyn_cast<CXXAllocatorCall>(&Call)) {
+ if (!AC->isArray())
+ return;
+
+ auto *SizeEx = *AC->getArraySizeExpr();
+ auto SizeVal = AC->getArraySizeVal();
+
+ if (SizeVal.isUndef())
+ HandleUndefinedArrayElementCount(C, SizeVal, SizeEx,
+ SizeEx->getSourceRange());
+ }
+}
+
+void UndefinedNewArraySizeChecker::HandleUndefinedArrayElementCount(
+ CheckerContext &C, SVal ArgVal, const Expr *Init, SourceRange Range) const {
+
+ if (ExplodedNode *N = C.generateErrorNode()) {
+
+ SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "Element count in new[] is a garbage value";
+
+ auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
+ R->markInteresting(ArgVal);
+ R->addRange(Range);
+ bugreporter::trackExpressionValue(N, Init, *R);
+
+ C.emitReport(std::move(R));
+ }
+}
+
+void ento::registerUndefinedNewArraySizeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UndefinedNewArraySizeChecker>();
+}
+
+bool ento::shouldRegisterUndefinedNewArraySizeChecker(
+ const CheckerManager &mgr) {
+ return mgr.getLangOpts().CPlusPlus;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
index f5bd765ff679..54e1e0e11909 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
+#include <optional>
using namespace clang;
using namespace clang::ento;
@@ -121,9 +122,9 @@ struct DereferenceInfo {
/// Dereferences \p FR and returns with the pointee's region, and whether it
/// needs to be casted back to it's location type. If for whatever reason
-/// dereferencing fails, returns with None.
-static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
- const FieldRegion *FR);
+/// dereferencing fails, returns std::nullopt.
+static std::optional<DereferenceInfo> dereference(ProgramStateRef State,
+ const FieldRegion *FR);
/// Returns whether \p T can be (transitively) dereferenced to a void pointer
/// type (void*, void**, ...).
@@ -159,7 +160,7 @@ bool FindUninitializedFields::isDereferencableUninit(
// At this point the pointer itself is initialized and points to a valid
// location, we'll now check the pointee.
- llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
+ std::optional<DereferenceInfo> DerefInfo = dereference(State, FR);
if (!DerefInfo) {
IsAnyFieldInitialized = true;
return false;
@@ -217,8 +218,8 @@ bool FindUninitializedFields::isDereferencableUninit(
// Utility functions.
//===----------------------------------------------------------------------===//
-static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
- const FieldRegion *FR) {
+static std::optional<DereferenceInfo> dereference(ProgramStateRef State,
+ const FieldRegion *FR) {
llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
@@ -234,7 +235,7 @@ static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
// The region we'd like to acquire.
const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
if (!R)
- return None;
+ return std::nullopt;
VisitedRegions.insert(R);
@@ -245,7 +246,7 @@ static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
R = Tmp->getAs<TypedValueRegion>();
if (!R)
- return None;
+ return std::nullopt;
// We found a cyclic pointer, like int *ptr = (int *)&ptr.
if (!VisitedRegions.insert(R).second)
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index aa3f4524798a..f503b3e88bb3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -17,11 +17,11 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -40,7 +40,7 @@ namespace {
class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
- mutable Optional<uint64_t> Val_O_CREAT;
+ mutable std::optional<uint64_t> Val_O_CREAT;
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -234,7 +234,7 @@ void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
}
NonLoc oflags = V.castAs<NonLoc>();
NonLoc ocreateFlag = C.getSValBuilder()
- .makeIntVal(Val_O_CREAT.value(), oflagsEx->getType())
+ .makeIntVal(*Val_O_CREAT, oflagsEx->getType())
.castAs<NonLoc>();
SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
oflags, ocreateFlag,
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index d231be64c2e1..3ad6858ead46 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -24,6 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/SmallSet.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -74,7 +75,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (!PM)
PM = &LC->getParentMap();
- if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
+ if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
const CFGBlock *CB = BE->getBlock();
reachable.insert(CB->getBlockID());
}
@@ -129,7 +130,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
bool foundUnreachable = false;
for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
ci != ce; ++ci) {
- if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
+ if (std::optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable ||
CE->isBuiltinAssumeFalse(Eng.getContext())) {
@@ -199,7 +200,7 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
// Find the Stmt* in a CFGBlock for reporting a warning
const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
- if (Optional<CFGStmt> S = I->getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> S = I->getAs<CFGStmt>()) {
if (!isa<DeclStmt>(S->getStmt()))
return S->getStmt();
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index cf519b085892..fe910ce35302 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -24,6 +24,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -192,7 +193,7 @@ ProgramStateRef VLASizeChecker::checkVLAIndexSize(CheckerContext &C,
DefinedOrUnknownSVal Zero = SVB.makeZeroVal(SizeTy);
SVal LessThanZeroVal = SVB.evalBinOp(State, BO_LT, SizeD, Zero, SizeTy);
- if (Optional<DefinedSVal> LessThanZeroDVal =
+ if (std::optional<DefinedSVal> LessThanZeroDVal =
LessThanZeroVal.getAs<DefinedSVal>()) {
ConstraintManager &CM = C.getConstraintManager();
ProgramStateRef StatePos, StateNeg;
diff --git a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
index fbefd5f9ffdc..2d1b873abf73 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
@@ -100,27 +100,26 @@ private:
};
const SmallVector<ValistChecker::VAListAccepter, 15>
- ValistChecker::VAListAccepters = {
- {{"vfprintf", 3}, 2},
- {{"vfscanf", 3}, 2},
- {{"vprintf", 2}, 1},
- {{"vscanf", 2}, 1},
- {{"vsnprintf", 4}, 3},
- {{"vsprintf", 3}, 2},
- {{"vsscanf", 3}, 2},
- {{"vfwprintf", 3}, 2},
- {{"vfwscanf", 3}, 2},
- {{"vwprintf", 2}, 1},
- {{"vwscanf", 2}, 1},
- {{"vswprintf", 4}, 3},
- // vswprintf is the wide version of vsnprintf,
- // vsprintf has no wide version
- {{"vswscanf", 3}, 2}};
-
-const CallDescription
- ValistChecker::VaStart("__builtin_va_start", /*Args=*/2, /*Params=*/1),
- ValistChecker::VaCopy("__builtin_va_copy", 2),
- ValistChecker::VaEnd("__builtin_va_end", 1);
+ ValistChecker::VAListAccepters = {{{{"vfprintf"}, 3}, 2},
+ {{{"vfscanf"}, 3}, 2},
+ {{{"vprintf"}, 2}, 1},
+ {{{"vscanf"}, 2}, 1},
+ {{{"vsnprintf"}, 4}, 3},
+ {{{"vsprintf"}, 3}, 2},
+ {{{"vsscanf"}, 3}, 2},
+ {{{"vfwprintf"}, 3}, 2},
+ {{{"vfwscanf"}, 3}, 2},
+ {{{"vwprintf"}, 2}, 1},
+ {{{"vwscanf"}, 2}, 1},
+ {{{"vswprintf"}, 4}, 3},
+ // vswprintf is the wide version of
+ // vsnprintf, vsprintf has no wide version
+ {{{"vswscanf"}, 3}, 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
void ValistChecker::checkPreCall(const CallEvent &Call,
diff --git a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
index 04e6603b4cbe..86a4e6fbcd6a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
@@ -35,6 +35,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/AST/ParentMap.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -154,8 +155,8 @@ void VforkChecker::checkPostCall(const CallEvent &Call,
// Get return value of vfork.
SVal VforkRetVal = Call.getReturnValue();
- Optional<DefinedOrUnknownSVal> DVal =
- VforkRetVal.getAs<DefinedOrUnknownSVal>();
+ std::optional<DefinedOrUnknownSVal> DVal =
+ VforkRetVal.getAs<DefinedOrUnknownSVal>();
if (!DVal)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 9c7a59971763..64028b277021 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -12,8 +12,8 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
+#include <optional>
-using llvm::Optional;
namespace clang {
std::pair<const Expr *, bool>
@@ -34,8 +34,7 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
}
if (auto *call = dyn_cast<CallExpr>(E)) {
if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
- Optional<bool> IsGetterOfRefCt =
- isGetterOfRefCounted(memberCall->getMethodDecl());
+ std::optional<bool> IsGetterOfRefCt = isGetterOfRefCounted(memberCall->getMethodDecl());
if (IsGetterOfRefCt && *IsGetterOfRefCt) {
E = memberCall->getImplicitObjectArgument();
if (StopAtFirstRefCountedObj) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
index 97f75135bf92..66d8588e2531 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Casting.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -69,7 +70,7 @@ public:
if (shouldSkipDecl(RD))
return;
- for (auto Member : RD->fields()) {
+ for (auto *Member : RD->fields()) {
const Type *MemberType = Member->getType().getTypePtrOrNull();
if (!MemberType)
continue;
@@ -77,9 +78,9 @@ public:
if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl()) {
// If we don't see the definition we just don't know.
if (MemberCXXRD->hasDefinition()) {
- llvm::Optional<bool> isRCAble = isRefCountable(MemberCXXRD);
- if (isRCAble && *isRCAble)
- reportBug(Member, MemberType, MemberCXXRD, RD);
+ std::optional<bool> isRCAble = isRefCountable(MemberCXXRD);
+ if (isRCAble && *isRCAble)
+ reportBug(Member, MemberType, MemberCXXRD, RD);
}
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index a198943c9433..9b1d7ae3e6a3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -12,9 +12,8 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
-#include "llvm/ADT/Optional.h"
+#include <optional>
-using llvm::Optional;
using namespace clang;
namespace {
@@ -45,29 +44,31 @@ bool hasPublicRefAndDeref(const CXXRecordDecl *R) {
namespace clang {
-llvm::Optional<const clang::CXXRecordDecl *>
-isRefCountable(const CXXBaseSpecifier *Base) {
+std::optional<const clang::CXXRecordDecl*>
+isRefCountable(const CXXBaseSpecifier* Base)
+{
assert(Base);
const Type *T = Base->getType().getTypePtrOrNull();
if (!T)
- return llvm::None;
+ return std::nullopt;
const CXXRecordDecl *R = T->getAsCXXRecordDecl();
if (!R)
- return llvm::None;
+ return std::nullopt;
if (!R->hasDefinition())
- return llvm::None;
+ return std::nullopt;
return hasPublicRefAndDeref(R) ? R : nullptr;
}
-llvm::Optional<bool> isRefCountable(const CXXRecordDecl *R) {
+std::optional<bool> isRefCountable(const CXXRecordDecl* R)
+{
assert(R);
R = R->getDefinition();
if (!R)
- return llvm::None;
+ return std::nullopt;
if (hasPublicRefAndDeref(R))
return true;
@@ -77,20 +78,19 @@ llvm::Optional<bool> isRefCountable(const CXXRecordDecl *R) {
bool AnyInconclusiveBase = false;
const auto isRefCountableBase =
- [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
- Optional<const clang::CXXRecordDecl *> IsRefCountable =
- clang::isRefCountable(Base);
- if (!IsRefCountable) {
- AnyInconclusiveBase = true;
- return false;
- }
- return (*IsRefCountable) != nullptr;
+ [&AnyInconclusiveBase](const CXXBaseSpecifier* Base, CXXBasePath&) {
+ std::optional<const clang::CXXRecordDecl*> IsRefCountable = clang::isRefCountable(Base);
+ if (!IsRefCountable) {
+ AnyInconclusiveBase = true;
+ return false;
+ }
+ return (*IsRefCountable) != nullptr;
};
bool BasesResult = R->lookupInBases(isRefCountableBase, Paths,
/*LookupInDependent =*/true);
if (AnyInconclusiveBase)
- return llvm::None;
+ return std::nullopt;
return BasesResult;
}
@@ -112,19 +112,21 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
|| FunctionName == "Identifier";
}
-llvm::Optional<bool> isUncounted(const CXXRecordDecl *Class) {
+std::optional<bool> isUncounted(const CXXRecordDecl* Class)
+{
// Keep isRefCounted first as it's cheaper.
if (isRefCounted(Class))
return false;
- llvm::Optional<bool> IsRefCountable = isRefCountable(Class);
+ std::optional<bool> IsRefCountable = isRefCountable(Class);
if (!IsRefCountable)
- return llvm::None;
+ return std::nullopt;
return (*IsRefCountable);
}
-llvm::Optional<bool> isUncountedPtr(const Type *T) {
+std::optional<bool> isUncountedPtr(const Type* T)
+{
assert(T);
if (T->isPointerType() || T->isReferenceType()) {
@@ -135,7 +137,8 @@ llvm::Optional<bool> isUncountedPtr(const Type *T) {
return false;
}
-Optional<bool> isGetterOfRefCounted(const CXXMethodDecl *M) {
+std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
+{
assert(M);
if (isa<CXXMethodDecl>(M)) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 753adea0d14d..91e3ccf2ec30 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H
#include "llvm/ADT/APInt.h"
+#include <optional>
namespace clang {
class CXXBaseSpecifier;
@@ -26,31 +27,31 @@ class Type;
// Ref<T>.
/// \returns CXXRecordDecl of the base if the type is ref-countable, nullptr if
-/// not, None if inconclusive.
-llvm::Optional<const clang::CXXRecordDecl *>
-isRefCountable(const clang::CXXBaseSpecifier *Base);
+/// not, std::nullopt if inconclusive.
+std::optional<const clang::CXXRecordDecl*>
+isRefCountable(const clang::CXXBaseSpecifier* Base);
-/// \returns true if \p Class is ref-countable, false if not, None if
+/// \returns true if \p Class is ref-countable, false if not, std::nullopt if
/// inconclusive.
-llvm::Optional<bool> isRefCountable(const clang::CXXRecordDecl *Class);
+std::optional<bool> isRefCountable(const clang::CXXRecordDecl* Class);
/// \returns true if \p Class is ref-counted, false if not.
bool isRefCounted(const clang::CXXRecordDecl *Class);
/// \returns true if \p Class is ref-countable AND not ref-counted, false if
-/// not, None if inconclusive.
-llvm::Optional<bool> isUncounted(const clang::CXXRecordDecl *Class);
+/// not, std::nullopt if inconclusive.
+std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
/// \returns true if \p T is either a raw pointer or reference to an uncounted
-/// class, false if not, None if inconclusive.
-llvm::Optional<bool> isUncountedPtr(const clang::Type *T);
+/// class, false if not, std::nullopt if inconclusive.
+std::optional<bool> isUncountedPtr(const clang::Type* T);
/// \returns true if \p F creates ref-countable object from uncounted parameter,
/// false if not.
bool isCtorOfRefCounted(const clang::FunctionDecl *F);
/// \returns true if \p M is getter of a ref-counted class, false if not.
-llvm::Optional<bool> isGetterOfRefCounted(const clang::CXXMethodDecl *Method);
+std::optional<bool> isGetterOfRefCounted(const clang::CXXMethodDecl* Method);
/// \returns true if \p F is a conversion between ref-countable or ref-counted
/// pointer types.
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
index fa9ece217cc0..48dcfc4a3c46 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -76,8 +77,7 @@ public:
(AccSpec == AS_none && RD->isClass()))
return false;
- llvm::Optional<const CXXRecordDecl *> RefCntblBaseRD =
- isRefCountable(Base);
+ std::optional<const CXXRecordDecl*> RefCntblBaseRD = isRefCountable(Base);
if (!RefCntblBaseRD || !(*RefCntblBaseRD))
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
index e6d0948f71bb..4ae8c442fa70 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseSet.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -85,7 +86,7 @@ public:
continue; // FIXME? Should we bail?
// FIXME: more complex types (arrays, references to raw pointers, etc)
- Optional<bool> IsUncounted = isUncountedPtr(ArgType);
+ std::optional<bool> IsUncounted = isUncountedPtr(ArgType);
if (!IsUncounted || !(*IsUncounted))
continue;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
index deebbd603b2c..004b0b9d398b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -57,18 +58,18 @@ public:
void visitLambdaExpr(LambdaExpr *L) const {
for (const LambdaCapture &C : L->captures()) {
if (C.capturesVariable()) {
- VarDecl *CapturedVar = C.getCapturedVar();
+ ValueDecl *CapturedVar = C.getCapturedVar();
if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) {
- Optional<bool> IsUncountedPtr = isUncountedPtr(CapturedVarType);
- if (IsUncountedPtr && *IsUncountedPtr) {
- reportBug(C, CapturedVar, CapturedVarType);
- }
+ std::optional<bool> IsUncountedPtr = isUncountedPtr(CapturedVarType);
+ if (IsUncountedPtr && *IsUncountedPtr) {
+ reportBug(C, CapturedVar, CapturedVarType);
+ }
}
}
}
}
- void reportBug(const LambdaCapture &Capture, VarDecl *CapturedVar,
+ void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
const Type *T) const {
assert(CapturedVar);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
index 7e86f28cb70f..fa7475934981 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseSet.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -169,7 +170,7 @@ public:
if (!ArgType)
return;
- Optional<bool> IsUncountedPtr = isUncountedPtr(ArgType);
+ std::optional<bool> IsUncountedPtr = isUncountedPtr(ArgType);
if (IsUncountedPtr && *IsUncountedPtr) {
const Expr *const InitExpr = V->getInit();
if (!InitExpr)
diff --git a/clang/lib/StaticAnalyzer/Checkers/Yaml.h b/clang/lib/StaticAnalyzer/Checkers/Yaml.h
index 497189f4c160..4159e14105f8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Yaml.h
+++ b/clang/lib/StaticAnalyzer/Checkers/Yaml.h
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLTraits.h"
+#include <optional>
namespace clang {
namespace ento {
@@ -25,10 +26,10 @@ namespace ento {
/// 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) {
+std::optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
+ StringRef Option, StringRef ConfigFile) {
if (ConfigFile.trim().empty())
- return None;
+ return std::nullopt;
llvm::vfs::FileSystem *FS = llvm::vfs::getRealFileSystem().get();
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
@@ -38,7 +39,7 @@ llvm::Optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
Mgr.reportInvalidCheckerOptionValue(Chk, Option,
"a valid filename instead of '" +
std::string(ConfigFile) + "'");
- return None;
+ return std::nullopt;
}
llvm::yaml::Input Input(Buffer.get()->getBuffer());
@@ -48,7 +49,7 @@ llvm::Optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
if (std::error_code ec = Input.error()) {
Mgr.reportInvalidCheckerOptionValue(Chk, Option,
"a valid yaml file: " + ec.message());
- return None;
+ return std::nullopt;
}
return Config;
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
index 084789509533..aae1a17bc0ae 100644
--- a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
@@ -39,11 +39,11 @@ private:
// SEI CERT ENV31-C
const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = {
- {{"setenv", 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
- {{"unsetenv", 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
- {{"putenv", 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
- {{"_putenv_s", 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
- {{"_wputenv_s", 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{{"setenv"}, 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{{"unsetenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{{"putenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{{"_putenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{{"_wputenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
};
void postPreviousReturnInvalidatingCall(const CallEvent &Call,
@@ -51,13 +51,15 @@ private:
// SEI CERT ENV34-C
const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = {
- {{"getenv", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
- {{"setlocale", 2},
+ {{{"getenv"}, 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{{"setlocale"}, 2},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
- {{"strerror", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
- {{"localeconv", 0},
+ {{{"strerror"}, 1},
+ &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{{"localeconv"}, 0},
+ &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{{"asctime"}, 1},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
- {{"asctime", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
};
public:
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
index ed3bdafad084..eae162cda693 100644
--- a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
@@ -30,7 +30,7 @@ class PutenvWithAutoChecker : public Checker<check::PostCall> {
private:
BugType BT{this, "'putenv' function should not be called with auto variables",
categories::SecurityError};
- const CallDescription Putenv{"putenv", 1};
+ const CallDescription Putenv{{"putenv"}, 1};
public:
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 009cbd4559b5..86ef4a568665 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstddef>
+#include <optional>
#include <utility>
#include <vector>
@@ -64,45 +65,44 @@ void AnalyzerOptions::printFormattedEntry(
ExplorationStrategyKind
AnalyzerOptions::getExplorationStrategy() const {
auto K =
- llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>(
- ExplorationStrategy)
+ llvm::StringSwitch<std::optional<ExplorationStrategyKind>>(
+ ExplorationStrategy)
.Case("dfs", ExplorationStrategyKind::DFS)
.Case("bfs", ExplorationStrategyKind::BFS)
- .Case("unexplored_first",
- ExplorationStrategyKind::UnexploredFirst)
+ .Case("unexplored_first", ExplorationStrategyKind::UnexploredFirst)
.Case("unexplored_first_queue",
ExplorationStrategyKind::UnexploredFirstQueue)
.Case("unexplored_first_location_queue",
ExplorationStrategyKind::UnexploredFirstLocationQueue)
.Case("bfs_block_dfs_contents",
ExplorationStrategyKind::BFSBlockDFSContents)
- .Default(None);
+ .Default(std::nullopt);
assert(K && "User mode is invalid.");
- return K.value();
+ return *K;
}
CTUPhase1InliningKind AnalyzerOptions::getCTUPhase1Inlining() const {
- auto K = llvm::StringSwitch<llvm::Optional<CTUPhase1InliningKind>>(
+ auto K = llvm::StringSwitch<std::optional<CTUPhase1InliningKind>>(
CTUPhase1InliningMode)
.Case("none", CTUPhase1InliningKind::None)
.Case("small", CTUPhase1InliningKind::Small)
.Case("all", CTUPhase1InliningKind::All)
- .Default(None);
+ .Default(std::nullopt);
assert(K && "CTU inlining mode is invalid.");
- return K.value();
+ return *K;
}
IPAKind AnalyzerOptions::getIPAMode() const {
- auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(IPAMode)
- .Case("none", IPAK_None)
- .Case("basic-inlining", IPAK_BasicInlining)
- .Case("inlining", IPAK_Inlining)
- .Case("dynamic", IPAK_DynamicDispatch)
- .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
- .Default(None);
+ auto K = llvm::StringSwitch<std::optional<IPAKind>>(IPAMode)
+ .Case("none", IPAK_None)
+ .Case("basic-inlining", IPAK_BasicInlining)
+ .Case("inlining", IPAK_Inlining)
+ .Case("dynamic", IPAK_DynamicDispatch)
+ .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
+ .Default(std::nullopt);
assert(K && "IPA Mode is invalid.");
- return K.value();
+ return *K;
}
bool
@@ -111,14 +111,13 @@ AnalyzerOptions::mayInlineCXXMemberFunction(
if (getIPAMode() < IPAK_Inlining)
return false;
- auto K =
- llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>(
- CXXMemberInliningMode)
- .Case("constructors", CIMK_Constructors)
- .Case("destructors", CIMK_Destructors)
- .Case("methods", CIMK_MemberFunctions)
- .Case("none", CIMK_None)
- .Default(None);
+ auto K = llvm::StringSwitch<std::optional<CXXInlineableMemberKind>>(
+ CXXMemberInliningMode)
+ .Case("constructors", CIMK_Constructors)
+ .Case("destructors", CIMK_Destructors)
+ .Case("methods", CIMK_MemberFunctions)
+ .Case("none", CIMK_None)
+ .Default(std::nullopt);
assert(K && "Invalid c++ member function inlining mode.");
@@ -162,12 +161,12 @@ StringRef AnalyzerOptions::getCheckerStringOption(const ento::CheckerBase *C,
bool AnalyzerOptions::getCheckerBooleanOption(StringRef CheckerName,
StringRef OptionName,
bool SearchInParents) const {
- auto Ret = llvm::StringSwitch<llvm::Optional<bool>>(
- getCheckerStringOption(CheckerName, OptionName,
- SearchInParents))
- .Case("true", true)
- .Case("false", false)
- .Default(None);
+ auto Ret =
+ llvm::StringSwitch<std::optional<bool>>(
+ getCheckerStringOption(CheckerName, OptionName, SearchInParents))
+ .Case("true", true)
+ .Case("false", false)
+ .Default(std::nullopt);
assert(Ret &&
"This option should be either 'true' or 'false', and should've been "
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index 4d6b82e63f6a..a7f149b87e79 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -46,8 +46,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -66,6 +64,7 @@
#include <cstddef>
#include <iterator>
#include <memory>
+#include <optional>
#include <queue>
#include <string>
#include <tuple>
@@ -221,8 +220,8 @@ class PathDiagnosticBuilder : public BugReporterContext {
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>
+ /// consumers. Returns std::nullopt if no valid report is found.
+ static std::optional<PathDiagnosticBuilder>
findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports,
PathSensitiveBugReporter &Reporter);
@@ -309,7 +308,7 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
}
// Check if the parameter is a pointer to the symbol.
- if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
// Do not attempt to dereference void*.
if ((*I)->getType()->isVoidPointerType())
continue;
@@ -1033,7 +1032,7 @@ static bool isContainedByStmt(const ParentMap &PM, const Stmt *S,
static const Stmt *getStmtBeforeCond(const ParentMap &PM, const Stmt *Term,
const ExplodedNode *N) {
while (N) {
- Optional<StmtPoint> SP = N->getLocation().getAs<StmtPoint>();
+ std::optional<StmtPoint> SP = N->getLocation().getAs<StmtPoint>();
if (SP) {
const Stmt *S = SP->getStmt();
if (!isContainedByStmt(PM, Term, S))
@@ -1194,7 +1193,7 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
"location context associated with the active path!");
// Have we encountered an exit from a function call?
- if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
+ if (std::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.
@@ -1566,21 +1565,22 @@ static void simplifySimpleBranches(PathPieces &pieces) {
/// Returns the number of bytes in the given (character-based) SourceRange.
///
-/// If the locations in the range are not on the same line, returns None.
+/// If the locations in the range are not on the same line, returns
+/// std::nullopt.
///
/// Note that this does not do a precise user-visible character or column count.
-static Optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
- SourceRange Range) {
+static std::optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
+ SourceRange Range) {
SourceRange ExpansionRange(SM.getExpansionLoc(Range.getBegin()),
SM.getExpansionRange(Range.getEnd()).getEnd());
FileID FID = SM.getFileID(ExpansionRange.getBegin());
if (FID != SM.getFileID(ExpansionRange.getEnd()))
- return None;
+ return std::nullopt;
- Optional<MemoryBufferRef> Buffer = SM.getBufferOrNone(FID);
+ std::optional<MemoryBufferRef> Buffer = SM.getBufferOrNone(FID);
if (!Buffer)
- return None;
+ return std::nullopt;
unsigned BeginOffset = SM.getFileOffset(ExpansionRange.getBegin());
unsigned EndOffset = SM.getFileOffset(ExpansionRange.getEnd());
@@ -1591,15 +1591,15 @@ static Optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
// SourceRange is covering a large or small amount of space in the user's
// editor.
if (Snippet.find_first_of("\r\n") != StringRef::npos)
- return None;
+ return std::nullopt;
// This isn't Unicode-aware, but it doesn't need to be.
return Snippet.size();
}
/// \sa getLengthOnSingleLine(SourceManager, SourceRange)
-static Optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
- const Stmt *S) {
+static std::optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
+ const Stmt *S) {
return getLengthOnSingleLine(SM, S->getSourceRange());
}
@@ -1658,9 +1658,9 @@ static void removeContextCycles(PathPieces &Path, const SourceManager &SM) {
if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
const size_t MAX_SHORT_LINE_LENGTH = 80;
- Optional<size_t> s1Length = getLengthOnSingleLine(SM, s1Start);
+ std::optional<size_t> s1Length = getLengthOnSingleLine(SM, s1Start);
if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
- Optional<size_t> s2Length = getLengthOnSingleLine(SM, s2Start);
+ std::optional<size_t> s2Length = getLengthOnSingleLine(SM, s2Start);
if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
Path.erase(I);
I = Path.erase(NextI);
@@ -1719,7 +1719,7 @@ static void removePunyEdges(PathPieces &path, const SourceManager &SM,
std::swap(SecondLoc, FirstLoc);
SourceRange EdgeRange(FirstLoc, SecondLoc);
- Optional<size_t> ByteWidth = getLengthOnSingleLine(SM, EdgeRange);
+ std::optional<size_t> ByteWidth = getLengthOnSingleLine(SM, EdgeRange);
// If the statements are on different lines, continue.
if (!ByteWidth)
@@ -2310,7 +2310,7 @@ void PathSensitiveBugReport::markInteresting(const LocationContext *LC) {
InterestingLocationContexts.insert(LC);
}
-Optional<bugreporter::TrackingKind>
+std::optional<bugreporter::TrackingKind>
PathSensitiveBugReport::getInterestingnessKind(SVal V) const {
auto RKind = getInterestingnessKind(V.getAsRegion());
auto SKind = getInterestingnessKind(V.getAsSymbol());
@@ -2332,25 +2332,25 @@ PathSensitiveBugReport::getInterestingnessKind(SVal V) const {
"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;
+ return std::nullopt;
}
-Optional<bugreporter::TrackingKind>
+std::optional<bugreporter::TrackingKind>
PathSensitiveBugReport::getInterestingnessKind(SymbolRef sym) const {
if (!sym)
- return None;
+ return std::nullopt;
// We don't currently consider metadata symbols to be interesting
// even if we know their region is interesting. Is that correct behavior?
auto It = InterestingSymbols.find(sym);
if (It == InterestingSymbols.end())
- return None;
+ return std::nullopt;
return It->getSecond();
}
-Optional<bugreporter::TrackingKind>
+std::optional<bugreporter::TrackingKind>
PathSensitiveBugReport::getInterestingnessKind(const MemRegion *R) const {
if (!R)
- return None;
+ return std::nullopt;
R = R->getBaseRegion();
auto It = InterestingRegions.find(R);
@@ -2359,7 +2359,7 @@ PathSensitiveBugReport::getInterestingnessKind(const MemRegion *R) const {
if (const auto *SR = dyn_cast<SymbolicRegion>(R))
return getInterestingnessKind(SR->getSymbol());
- return None;
+ return std::nullopt;
}
bool PathSensitiveBugReport::isInteresting(SVal V) const {
@@ -2387,7 +2387,7 @@ const Stmt *PathSensitiveBugReport::getStmt() const {
ProgramPoint ProgP = ErrorNode->getLocation();
const Stmt *S = nullptr;
- if (Optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
+ if (std::optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
if (BE->getBlock() == &Exit)
S = ErrorNode->getPreviousStmtForDiagnostics();
@@ -2419,7 +2419,7 @@ PathSensitiveBugReport::getLocation() const {
if (!S) {
// If this is an implicit call, return the implicit call point location.
- if (Optional<PreImplicitCall> PIE = P.getAs<PreImplicitCall>())
+ if (std::optional<PreImplicitCall> PIE = P.getAs<PreImplicitCall>())
return PathDiagnosticLocation(PIE->getLocation(), SM);
if (auto FE = P.getAs<FunctionExitPoint>()) {
if (const ReturnStmt *RS = FE->getStmt())
@@ -2821,7 +2821,7 @@ generateVisitorsDiagnostics(PathSensitiveBugReport *R,
return Notes;
}
-Optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
+std::optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
ArrayRef<PathSensitiveBugReport *> &bugReports,
PathSensitiveBugReporter &Reporter) {
@@ -2880,7 +2880,7 @@ PathSensitiveBugReporter::generatePathDiagnostics(
auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
- Optional<PathDiagnosticBuilder> PDB =
+ std::optional<PathDiagnosticBuilder> PDB =
PathDiagnosticBuilder::findValidReport(bugReports, *this);
if (PDB) {
@@ -3097,9 +3097,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
if (getAnalyzerOptions().ShouldDisplayNotesAsEvents) {
// For path diagnostic consumers that don't support extra notes,
// we may optionally convert those to path notes.
- for (auto I = report->getNotes().rbegin(),
- E = report->getNotes().rend(); I != E; ++I) {
- PathDiagnosticNotePiece *Piece = I->get();
+ for (const auto &I : llvm::reverse(report->getNotes())) {
+ PathDiagnosticNotePiece *Piece = I.get();
auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
Piece->getLocation(), Piece->getString());
for (const auto &R: Piece->getRanges())
@@ -3108,9 +3107,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
Pieces.push_front(std::move(ConvertedPiece));
}
} else {
- for (auto I = report->getNotes().rbegin(),
- E = report->getNotes().rend(); I != E; ++I)
- Pieces.push_front(*I);
+ for (const auto &I : llvm::reverse(report->getNotes()))
+ Pieces.push_front(I);
}
for (const auto &I : report->getFixits())
diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 3a90c37a36da..2b461acf9a73 100644
--- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -46,8 +46,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -60,6 +58,7 @@
#include <cassert>
#include <deque>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
@@ -206,8 +205,8 @@ static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal,
RLCV->getStore() == RightNode->getState()->getStore();
}
-static Optional<SVal> getSValForVar(const Expr *CondVarExpr,
- const ExplodedNode *N) {
+static std::optional<SVal> getSValForVar(const Expr *CondVarExpr,
+ const ExplodedNode *N) {
ProgramStateRef State = N->getState();
const LocationContext *LCtx = N->getLocationContext();
@@ -227,16 +226,16 @@ static Optional<SVal> getSValForVar(const Expr *CondVarExpr,
if (auto FieldL = State->getSVal(ME, LCtx).getAs<Loc>())
return State->getRawSVal(*FieldL, FD->getType());
- return None;
+ return std::nullopt;
}
-static Optional<const llvm::APSInt *>
+static std::optional<const llvm::APSInt *>
getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) {
- if (Optional<SVal> V = getSValForVar(CondVarExpr, N))
+ if (std::optional<SVal> V = getSValForVar(CondVarExpr, N))
if (auto CI = V->getAs<nonloc::ConcreteInt>())
return &CI->getValue();
- return None;
+ return std::nullopt;
}
static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
@@ -248,8 +247,9 @@ static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
if (!B->getErrorNode()->getStackFrame()->isParentOf(N->getStackFrame()))
return false;
- if (Optional<SVal> V = getSValForVar(CondVarExpr, N))
- if (Optional<bugreporter::TrackingKind> K = B->getInterestingnessKind(*V))
+ if (std::optional<SVal> V = getSValForVar(CondVarExpr, N))
+ if (std::optional<bugreporter::TrackingKind> K =
+ B->getInterestingnessKind(*V))
return *K == bugreporter::TrackingKind::Condition;
return false;
@@ -257,7 +257,7 @@ static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
static bool isInterestingExpr(const Expr *E, const ExplodedNode *N,
const PathSensitiveBugReport *B) {
- if (Optional<SVal> V = getSValForVar(E, N))
+ if (std::optional<SVal> V = getSValForVar(E, N))
return B->getInterestingnessKind(*V).has_value();
return false;
}
@@ -538,8 +538,8 @@ private:
/// Dereferences fields up to a given recursion limit.
/// Note that \p Vec is passed by value, leading to quadratic copying cost,
/// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
- /// \return A chain fields leading to the region of interest or None.
- const Optional<RegionVector>
+ /// \return A chain fields leading to the region of interest or std::nullopt.
+ const std::optional<RegionVector>
findRegionOfInterestInRecord(const RecordDecl *RD, ProgramStateRef State,
const MemRegion *R, const RegionVector &Vec = {},
int depth = 0);
@@ -619,26 +619,26 @@ static bool potentiallyWritesIntoIvar(const Decl *Parent,
/// Dereferences fields up to a given recursion limit.
/// Note that \p Vec is passed by value, leading to quadratic copying cost,
/// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
-/// \return A chain fields leading to the region of interest or None.
-const Optional<NoStoreFuncVisitor::RegionVector>
+/// \return A chain fields leading to the region of interest or std::nullopt.
+const std::optional<NoStoreFuncVisitor::RegionVector>
NoStoreFuncVisitor::findRegionOfInterestInRecord(
const RecordDecl *RD, ProgramStateRef State, const MemRegion *R,
const NoStoreFuncVisitor::RegionVector &Vec /* = {} */,
int depth /* = 0 */) {
if (depth == DEREFERENCE_LIMIT) // Limit the recursion depth.
- return None;
+ return std::nullopt;
if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
if (!RDX->hasDefinition())
- return None;
+ return std::nullopt;
// Recursively examine the base classes.
// Note that following base classes does not increase the recursion depth.
if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD))
for (const auto &II : RDX->bases())
if (const RecordDecl *RRD = II.getType()->getAsRecordDecl())
- if (Optional<RegionVector> Out =
+ if (std::optional<RegionVector> Out =
findRegionOfInterestInRecord(RRD, State, R, Vec, depth))
return Out;
@@ -664,12 +664,12 @@ NoStoreFuncVisitor::findRegionOfInterestInRecord(
continue;
if (const RecordDecl *RRD = PT->getAsRecordDecl())
- if (Optional<RegionVector> Out =
+ if (std::optional<RegionVector> Out =
findRegionOfInterestInRecord(RRD, State, VR, VecF, depth + 1))
return Out;
}
- return None;
+ return std::nullopt;
}
PathDiagnosticPieceRef
@@ -730,7 +730,7 @@ PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNoteForParameters(
ProgramStateRef State = N->getState();
if (const RecordDecl *RD = PT->getAsRecordDecl())
- if (Optional<RegionVector> P =
+ if (std::optional<RegionVector> P =
findRegionOfInterestInRecord(RD, State, MR))
return maybeEmitNote(R, Call, N, *P, RegionOfInterest, ParamName,
ParamIsReferenceType, IndirectionLevel);
@@ -928,12 +928,12 @@ public:
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) {
+ std::optional<SourceLocation> matchAssignment(const ExplodedNode *N) {
const Stmt *S = N->getStmtForDiagnostics();
ProgramStateRef State = N->getState();
auto *LCtx = N->getLocationContext();
if (!S)
- return None;
+ return std::nullopt;
if (const auto *DS = dyn_cast<DeclStmt>(S)) {
if (const auto *VD = dyn_cast<VarDecl>(DS->getSingleDecl()))
@@ -948,7 +948,7 @@ private:
return RHS->getBeginLoc();
}
}
- return None;
+ return std::nullopt;
}
};
@@ -1001,7 +1001,7 @@ public:
if (N->getLocationContext() != CalleeSFC)
return nullptr;
- Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
+ std::optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
if (!SP)
return nullptr;
@@ -1023,7 +1023,7 @@ public:
assert(RetE && "Tracking a return value for a void function");
// Handle cases where a reference is returned and then immediately used.
- Optional<Loc> LValue;
+ std::optional<Loc> LValue;
if (RetE->isGLValue()) {
if ((LValue = V.getAs<Loc>())) {
SVal RValue = State->getRawSVal(*LValue, RetE->getType());
@@ -1122,7 +1122,7 @@ public:
assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
// Are we at the entry node for this call?
- Optional<CallEnter> CE = N->getLocationAs<CallEnter>();
+ std::optional<CallEnter> CE = N->getLocationAs<CallEnter>();
if (!CE)
return nullptr;
@@ -1140,7 +1140,7 @@ public:
ProgramStateRef State = N->getState();
CallEventRef<> Call = CallMgr.getCaller(CalleeSFC, State);
for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
- Optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
+ std::optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
if (!ArgV)
continue;
@@ -1187,8 +1187,6 @@ public:
}
};
-} // end of anonymous namespace
-
//===----------------------------------------------------------------------===//
// StoreSiteFinder
//===----------------------------------------------------------------------===//
@@ -1228,6 +1226,7 @@ public:
BugReporterContext &BRC,
PathSensitiveBugReport &BR) override;
};
+} // namespace
void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {
static int tag = 0;
@@ -1241,7 +1240,7 @@ void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {
/// Returns true if \p N represents the DeclStmt declaring and initializing
/// \p VR.
static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
- Optional<PostStmt> P = N->getLocationAs<PostStmt>();
+ std::optional<PostStmt> P = N->getLocationAs<PostStmt>();
if (!P)
return false;
@@ -1340,13 +1339,12 @@ static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) {
static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS,
StoreInfo SI) {
const auto *VR = cast<VarRegion>(SI.Dest);
- const auto *Param = cast<ParmVarDecl>(VR->getDecl());
+ const auto *D = VR->getDecl();
OS << "Passing ";
if (isa<loc::ConcreteInt>(SI.Value)) {
- OS << (isObjCPointer(Param) ? "nil object reference"
- : "null pointer value");
+ OS << (isObjCPointer(D) ? "nil object reference" : "null pointer value");
} else if (SI.Value.isUndef()) {
OS << "uninitialized value";
@@ -1361,12 +1359,19 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS,
OS << "value";
}
- // Printed parameter indexes are 1-based, not 0-based.
- unsigned Idx = Param->getFunctionScopeIndex() + 1;
- OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter";
- if (VR->canPrintPretty()) {
- OS << " ";
- VR->printPretty(OS);
+ if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
+ // Printed parameter indexes are 1-based, not 0-based.
+ unsigned Idx = Param->getFunctionScopeIndex() + 1;
+ OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter";
+ if (VR->canPrintPretty()) {
+ OS << " ";
+ VR->printPretty(OS);
+ }
+ } else if (const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
+ if (ImplParam->getParameterKind() ==
+ ImplicitParamDecl::ImplicitParamKind::ObjCSelf) {
+ OS << " via implicit parameter 'self'";
+ }
}
}
@@ -1410,6 +1415,83 @@ static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS,
}
}
+static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE) {
+ if (!CE)
+ return false;
+
+ const auto *CtorDecl = CE->getConstructor();
+
+ return CtorDecl->isCopyOrMoveConstructor() && CtorDecl->isTrivial();
+}
+
+static const Expr *tryExtractInitializerFromList(const InitListExpr *ILE,
+ const MemRegion *R) {
+
+ const auto *TVR = dyn_cast_or_null<TypedValueRegion>(R);
+
+ if (!TVR)
+ return nullptr;
+
+ const auto ITy = ILE->getType().getCanonicalType();
+
+ // Push each sub-region onto the stack.
+ std::stack<const TypedValueRegion *> TVRStack;
+ while (isa<FieldRegion>(TVR) || isa<ElementRegion>(TVR)) {
+ // We found a region that matches the type of the init list,
+ // so we assume this is the outer-most region. This can happen
+ // if the initializer list is inside a class. If our assumption
+ // is wrong, we return a nullptr in the end.
+ if (ITy == TVR->getValueType().getCanonicalType())
+ break;
+
+ TVRStack.push(TVR);
+ TVR = cast<TypedValueRegion>(TVR->getSuperRegion());
+ }
+
+ // If the type of the outer most region doesn't match the type
+ // of the ILE, we can't match the ILE and the region.
+ if (ITy != TVR->getValueType().getCanonicalType())
+ return nullptr;
+
+ const Expr *Init = ILE;
+ while (!TVRStack.empty()) {
+ TVR = TVRStack.top();
+ TVRStack.pop();
+
+ // We hit something that's not an init list before
+ // running out of regions, so we most likely failed.
+ if (!isa<InitListExpr>(Init))
+ return nullptr;
+
+ ILE = cast<InitListExpr>(Init);
+ auto NumInits = ILE->getNumInits();
+
+ if (const auto *FR = dyn_cast<FieldRegion>(TVR)) {
+ const auto *FD = FR->getDecl();
+
+ if (FD->getFieldIndex() >= NumInits)
+ return nullptr;
+
+ Init = ILE->getInit(FD->getFieldIndex());
+ } else if (const auto *ER = dyn_cast<ElementRegion>(TVR)) {
+ const auto Ind = ER->getIndex();
+
+ // If index is symbolic, we can't figure out which expression
+ // belongs to the region.
+ if (!Ind.isConstant())
+ return nullptr;
+
+ const auto IndVal = Ind.getAsInteger()->getLimitedValue();
+ if (IndVal >= NumInits)
+ return nullptr;
+
+ Init = ILE->getInit(IndVal);
+ }
+ }
+
+ return Init;
+}
+
PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
BugReporterContext &BRC,
PathSensitiveBugReport &BR) {
@@ -1431,7 +1513,8 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
// If this is a post initializer expression, initializing the region, we
// should track the initializer expression.
- if (Optional<PostInitializer> PIP = Pred->getLocationAs<PostInitializer>()) {
+ if (std::optional<PostInitializer> PIP =
+ Pred->getLocationAs<PostInitializer>()) {
const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();
if (FieldReg == R) {
StoreSite = Pred;
@@ -1449,25 +1532,101 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
return nullptr;
if (hasVisibleUpdate(Pred, Pred->getState()->getSVal(R), Succ, V)) {
- Optional<PostStore> PS = Succ->getLocationAs<PostStore>();
+ std::optional<PostStore> PS = Succ->getLocationAs<PostStore>();
if (!PS || PS->getLocationValue() != R)
return nullptr;
}
StoreSite = Succ;
- // If this is an assignment expression, we can track the value
- // being assigned.
- if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
- if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>())
+ if (std::optional<PostStmt> P = Succ->getLocationAs<PostStmt>()) {
+ // If this is an assignment expression, we can track the value
+ // being assigned.
+ if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
if (BO->isAssignmentOp())
InitE = BO->getRHS();
+ }
+ // If we have a declaration like 'S s{1,2}' that needs special
+ // handling, we handle it here.
+ else if (const auto *DS = P->getStmtAs<DeclStmt>()) {
+ const auto *Decl = DS->getSingleDecl();
+ if (isa<VarDecl>(Decl)) {
+ const auto *VD = cast<VarDecl>(Decl);
+
+ // FIXME: Here we only track the inner most region, so we lose
+ // information, but it's still better than a crash or no information
+ // at all.
+ //
+ // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y',
+ // and throw away the rest.
+ if (const auto *ILE = dyn_cast<InitListExpr>(VD->getInit()))
+ InitE = tryExtractInitializerFromList(ILE, R);
+ }
+ } else if (const auto *CE = P->getStmtAs<CXXConstructExpr>()) {
+
+ const auto State = Succ->getState();
+
+ if (isTrivialCopyOrMoveCtor(CE) && isa<SubRegion>(R)) {
+ // Migrate the field regions from the current object to
+ // the parent object. If we track 'a.y.e' and encounter
+ // 'S a = b' then we need to track 'b.y.e'.
+
+ // Push the regions to a stack, from last to first, so
+ // considering the example above the stack will look like
+ // (bottom) 'e' -> 'y' (top).
+
+ std::stack<const SubRegion *> SRStack;
+ const SubRegion *SR = cast<SubRegion>(R);
+ while (isa<FieldRegion>(SR) || isa<ElementRegion>(SR)) {
+ SRStack.push(SR);
+ SR = cast<SubRegion>(SR->getSuperRegion());
+ }
+
+ // Get the region for the object we copied/moved from.
+ const auto *OriginEx = CE->getArg(0);
+ const auto OriginVal =
+ State->getSVal(OriginEx, Succ->getLocationContext());
+
+ // Pop the stored field regions and apply them to the origin
+ // object in the same order we had them on the copy.
+ // OriginField will evolve like 'b' -> 'b.y' -> 'b.y.e'.
+ SVal OriginField = OriginVal;
+ while (!SRStack.empty()) {
+ const auto *TopR = SRStack.top();
+ SRStack.pop();
+
+ if (const auto *FR = dyn_cast<FieldRegion>(TopR)) {
+ OriginField = State->getLValue(FR->getDecl(), OriginField);
+ } else if (const auto *ER = dyn_cast<ElementRegion>(TopR)) {
+ OriginField = State->getLValue(ER->getElementType(),
+ ER->getIndex(), OriginField);
+ } else {
+ // FIXME: handle other region type
+ }
+ }
+
+ // Track 'b.y.e'.
+ getParentTracker().track(V, OriginField.getAsRegion(), Options);
+ InitE = OriginEx;
+ }
+ }
+ // This branch can occur in cases like `Ctor() : field{ x, y } {}'.
+ else if (const auto *ILE = P->getStmtAs<InitListExpr>()) {
+ // FIXME: Here we only track the top level region, so we lose
+ // information, but it's still better than a crash or no information
+ // at all.
+ //
+ // E.g.: The region we have is 's.s2.s3.s4.y' and we only track 'y', and
+ // throw away the rest.
+ InitE = tryExtractInitializerFromList(ILE, R);
+ }
+ }
// If this is a call entry, the variable should be a parameter.
// FIXME: Handle CXXThisRegion as well. (This is not a priority because
// 'this' should never be NULL, but this visitor isn't just for NULL and
// UndefinedVal.)
- if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
+ if (std::optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
if (const auto *VR = dyn_cast<VarRegion>(R)) {
if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
@@ -1590,7 +1749,7 @@ PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
R,
OldRegion};
- if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
+ if (std::optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
const Stmt *S = PS->getStmt();
const auto *DS = dyn_cast<DeclStmt>(S);
const auto *VR = dyn_cast<VarRegion>(R);
@@ -1983,7 +2142,7 @@ static const Expr *peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N) {
const ExplodedNode *NI = N;
do {
ProgramPoint ProgPoint = NI->getLocation();
- if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
+ if (std::optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
const CFGBlock *srcBlk = BE->getSrc();
if (const Stmt *term = srcBlk->getTerminatorStmt()) {
if (term == CO) {
@@ -2058,6 +2217,7 @@ PathDiagnosticPieceRef StoreHandler::constructNote(StoreInfo SI,
return std::make_shared<PathDiagnosticEventPiece>(L, NodeText);
}
+namespace {
class DefaultStoreHandler final : public StoreHandler {
public:
using StoreHandler::StoreHandler;
@@ -2255,7 +2415,8 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
do {
// If that is satisfied we found our statement as an inlined call.
- if (Optional<CallExitEnd> CEE = ExprNode->getLocationAs<CallExitEnd>())
+ if (std::optional<CallExitEnd> CEE =
+ ExprNode->getLocationAs<CallExitEnd>())
if (CEE->getCalleeContext()->getCallSite() == E)
break;
@@ -2270,7 +2431,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
// FIXME: This code currently bypasses the call site for the
// conservatively evaluated allocator.
if (!BypassCXXNewExprEval)
- if (Optional<StmtPoint> SP = ExprNode->getLocationAs<StmtPoint>())
+ if (std::optional<StmtPoint> SP = ExprNode->getLocationAs<StmtPoint>())
// See if we do not enter into another context.
if (SP->getStmt() == E && CurrentSFC == PredSFC)
break;
@@ -2285,7 +2446,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
return {};
// Finally, see if we inlined the call.
- Optional<CallExitEnd> CEE = ExprNode->getLocationAs<CallExitEnd>();
+ std::optional<CallExitEnd> CEE = ExprNode->getLocationAs<CallExitEnd>();
if (!CEE)
return {};
@@ -2299,7 +2460,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
// Handle cases where a reference is returned and then immediately used.
if (cast<Expr>(E)->isGLValue())
- if (Optional<Loc> LValue = RetVal.getAs<Loc>())
+ if (std::optional<Loc> LValue = RetVal.getAs<Loc>())
RetVal = State->getSVal(*LValue);
// See if the return value is NULL. If so, suppress the report.
@@ -2307,7 +2468,7 @@ class InlinedFunctionCallHandler final : public ExpressionHandler {
bool EnableNullFPSuppression = false;
if (Opts.EnableNullFPSuppression && Options.ShouldSuppressNullReturnPaths)
- if (Optional<Loc> RetLoc = RetVal.getAs<Loc>())
+ if (std::optional<Loc> RetLoc = RetVal.getAs<Loc>())
EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
PathSensitiveBugReport &Report = getParentTracker().getReport();
@@ -2342,7 +2503,7 @@ public:
// what is written inside the pointer.
bool CanDereference = true;
if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {
- if (SR->getSymbol()->getType()->getPointeeType()->isVoidType())
+ if (SR->getPointeeStaticType()->isVoidType())
CanDereference = false;
} else if (L->getRegionAs<AllocaRegion>())
CanDereference = false;
@@ -2395,6 +2556,29 @@ public:
if (!RVNode)
return {};
+ Tracker::Result CombinedResult;
+ Tracker &Parent = getParentTracker();
+
+ const auto track = [&CombinedResult, &Parent, ExprNode,
+ Opts](const Expr *Inner) {
+ CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));
+ };
+
+ // FIXME: Initializer lists can appear in many different contexts
+ // and most of them needs a special handling. For now let's handle
+ // what we can. If the initializer list only has 1 element, we track
+ // that.
+ // This snippet even handles nesting, e.g.: int *x{{{{{y}}}}};
+ if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
+ if (ILE->getNumInits() == 1) {
+ track(ILE->getInit(0));
+
+ return CombinedResult;
+ }
+
+ return {};
+ }
+
ProgramStateRef RVState = RVNode->getState();
SVal V = RVState->getSValAsScalarOrLoc(E, RVNode->getLocationContext());
const auto *BO = dyn_cast<BinaryOperator>(E);
@@ -2406,13 +2590,6 @@ public:
SVal LHSV = RVState->getSVal(BO->getLHS(), RVNode->getLocationContext());
// Track both LHS and RHS of a multiplication.
- Tracker::Result CombinedResult;
- Tracker &Parent = getParentTracker();
-
- const auto track = [&CombinedResult, &Parent, ExprNode, Opts](Expr *Inner) {
- CombinedResult.combineWith(Parent.track(Inner, ExprNode, Opts));
- };
-
if (BO->getOpcode() == BO_Mul) {
if (LHSV.isZeroConstant())
track(BO->getLHS());
@@ -2426,6 +2603,7 @@ public:
return CombinedResult;
}
};
+} // namespace
Tracker::Tracker(PathSensitiveBugReport &Report) : Report(Report) {
// Default expression handlers.
@@ -2524,7 +2702,7 @@ const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
PathDiagnosticPieceRef
NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
PathSensitiveBugReport &BR) {
- Optional<PreStmt> P = N->getLocationAs<PreStmt>();
+ std::optional<PreStmt> P = N->getLocationAs<PreStmt>();
if (!P)
return nullptr;
@@ -2588,7 +2766,7 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
// If an assumption was made on a branch, it should be caught
// here by looking at the state transition.
- if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
+ if (std::optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
const CFGBlock *SrcBlock = BE->getSrc();
if (const Stmt *Term = SrcBlock->getTerminatorStmt()) {
// If the tag of the previous node is 'Eagerly Assume...' the current
@@ -2605,7 +2783,7 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
return nullptr;
}
- if (Optional<PostStmt> PS = ProgPoint.getAs<PostStmt>()) {
+ if (std::optional<PostStmt> PS = ProgPoint.getAs<PostStmt>()) {
const ProgramPointTag *CurrentNodeTag = PS->getTag();
if (CurrentNodeTag != Tags.first && CurrentNodeTag != Tags.second)
return nullptr;
@@ -2744,13 +2922,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
Loc, TookTrue ? GenericTrueMessage : GenericFalseMessage);
}
-bool ConditionBRVisitor::patternMatch(const Expr *Ex,
- const Expr *ParentEx,
- raw_ostream &Out,
- BugReporterContext &BRC,
+bool ConditionBRVisitor::patternMatch(const Expr *Ex, const Expr *ParentEx,
+ raw_ostream &Out, BugReporterContext &BRC,
PathSensitiveBugReport &report,
const ExplodedNode *N,
- Optional<bool> &prunable,
+ std::optional<bool> &prunable,
bool IsSameFieldName) {
const Expr *OriginalExpr = Ex;
Ex = Ex->IgnoreParenCasts();
@@ -2836,7 +3012,7 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue,
bool IsAssuming) {
bool shouldInvert = false;
- Optional<bool> shouldPrune;
+ std::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'.
@@ -2947,7 +3123,7 @@ PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
PathDiagnosticLocation Loc(Cond, SM, LCtx);
auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Message);
if (shouldPrune)
- event->setPrunable(shouldPrune.value());
+ event->setPrunable(*shouldPrune);
return event;
}
@@ -3070,7 +3246,7 @@ bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
if (!Ty->isIntegralOrEnumerationType())
return false;
- Optional<const llvm::APSInt *> IntValue;
+ std::optional<const llvm::APSInt *> IntValue;
if (!IsAssuming)
IntValue = getConcreteIntegerValue(CondVarExpr, N);
@@ -3081,9 +3257,9 @@ bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
Out << (TookTrue ? "not equal to 0" : "0");
} else {
if (Ty->isBooleanType())
- Out << (IntValue.value()->getBoolValue() ? "true" : "false");
+ Out << ((*IntValue)->getBoolValue() ? "true" : "false");
else
- Out << *IntValue.value();
+ Out << **IntValue;
}
return true;
@@ -3196,7 +3372,7 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
ProgramPoint ProgLoc = N->getLocation();
// We are only interested in visiting CallEnter nodes.
- Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
+ std::optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
if (!CEnter)
return nullptr;
@@ -3275,11 +3451,11 @@ void FalsePositiveRefutationBRVisitor::finalizeVisitor(
}
// And check for satisfiability
- Optional<bool> IsSAT = RefutationSolver->check();
+ std::optional<bool> IsSAT = RefutationSolver->check();
if (!IsSAT)
return;
- if (!IsSAT.value())
+ if (!*IsSAT)
BR.markInvalid("Infeasible constraints", EndPathNode->getLocationContext());
}
@@ -3334,7 +3510,7 @@ PathDiagnosticPieceRef TagVisitor::VisitNode(const ExplodedNode *N,
if (!T)
return nullptr;
- if (Optional<std::string> Msg = T->generateMessage(BRC, R)) {
+ if (std::optional<std::string> Msg = T->generateMessage(BRC, R)) {
PathDiagnosticLocation Loc =
PathDiagnosticLocation::create(PP, BRC.getSourceManager());
auto Piece = std::make_shared<PathDiagnosticEventPiece>(Loc, *Msg);
diff --git a/clang/lib/StaticAnalyzer/Core/CallDescription.cpp b/clang/lib/StaticAnalyzer/Core/CallDescription.cpp
index bb8b7492e248..94b2fde0a6f3 100644
--- a/clang/lib/StaticAnalyzer/Core/CallDescription.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallDescription.cpp
@@ -17,13 +17,13 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/Optional.h"
#include <iterator>
+#include <optional>
using namespace llvm;
using namespace clang;
-using MaybeCount = Optional<unsigned>;
+using MaybeCount = std::optional<unsigned>;
// A constructor helper.
static MaybeCount readRequiredParams(MaybeCount RequiredArgs,
@@ -32,11 +32,11 @@ static MaybeCount readRequiredParams(MaybeCount RequiredArgs,
return RequiredParams;
if (RequiredArgs)
return RequiredArgs;
- return None;
+ return std::nullopt;
}
ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
- ArrayRef<const char *> QualifiedName,
+ ArrayRef<StringRef> QualifiedName,
MaybeCount RequiredArgs /*= None*/,
MaybeCount RequiredParams /*= None*/)
: RequiredArgs(RequiredArgs),
@@ -44,11 +44,12 @@ ento::CallDescription::CallDescription(CallDescriptionFlags Flags,
Flags(Flags) {
assert(!QualifiedName.empty());
this->QualifiedName.reserve(QualifiedName.size());
- llvm::copy(QualifiedName, std::back_inserter(this->QualifiedName));
+ llvm::transform(QualifiedName, std::back_inserter(this->QualifiedName),
+ [](StringRef From) { return From.str(); });
}
/// Construct a CallDescription with default flags.
-ento::CallDescription::CallDescription(ArrayRef<const char *> QualifiedName,
+ento::CallDescription::CallDescription(ArrayRef<StringRef> QualifiedName,
MaybeCount RequiredArgs /*= None*/,
MaybeCount RequiredParams /*= None*/)
: CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {}
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 3a8d69df7a64..8516e3643425 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -49,8 +49,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ImmutableList.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -62,6 +60,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <optional>
#include <utility>
#define DEBUG_TYPE "static-analyzer-call-event"
@@ -424,6 +423,38 @@ static SVal processArgument(SVal Value, const Expr *ArgumentExpr,
return Value;
}
+/// Cast the argument value to the type of the parameter at the function
+/// declaration.
+/// Returns the argument value if it didn't need a cast.
+/// Or returns the cast argument if it needed a cast.
+/// Or returns 'Unknown' if it would need a cast but the callsite and the
+/// runtime definition don't match in terms of argument and parameter count.
+static SVal castArgToParamTypeIfNeeded(const CallEvent &Call, unsigned ArgIdx,
+ SVal ArgVal, SValBuilder &SVB) {
+ const FunctionDecl *RTDecl =
+ Call.getRuntimeDefinition().getDecl()->getAsFunction();
+ const auto *CallExprDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+
+ if (!RTDecl || !CallExprDecl)
+ return ArgVal;
+
+ // The function decl of the Call (in the AST) will not have any parameter
+ // declarations, if it was 'only' declared without a prototype. However, the
+ // engine will find the appropriate runtime definition - basically a
+ // redeclaration, which has a function body (and a function prototype).
+ if (CallExprDecl->hasPrototype() || !RTDecl->hasPrototype())
+ return ArgVal;
+
+ // Only do this cast if the number arguments at the callsite matches with
+ // the parameters at the runtime definition.
+ if (Call.getNumArgs() != RTDecl->getNumParams())
+ return UnknownVal();
+
+ const Expr *ArgExpr = Call.getArgExpr(ArgIdx);
+ const ParmVarDecl *Param = RTDecl->getParamDecl(ArgIdx);
+ return SVB.evalCast(ArgVal, Param->getType(), ArgExpr->getType());
+}
+
static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
CallEvent::BindingsTy &Bindings,
SValBuilder &SVB,
@@ -449,12 +480,18 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
// which makes getArgSVal() fail and return UnknownVal.
SVal ArgVal = Call.getArgSVal(Idx);
const Expr *ArgExpr = Call.getArgExpr(Idx);
- if (!ArgVal.isUnknown()) {
- Loc ParamLoc = SVB.makeLoc(
- MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx));
- Bindings.push_back(
- std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB)));
- }
+
+ if (ArgVal.isUnknown())
+ continue;
+
+ // Cast the argument value to match the type of the parameter in some
+ // edge-cases.
+ ArgVal = castArgToParamTypeIfNeeded(Call, Idx, ArgVal, SVB);
+
+ Loc ParamLoc = SVB.makeLoc(
+ MRMgr.getParamVarRegion(Call.getOriginExpr(), Idx, CalleeCtx));
+ Bindings.push_back(
+ std::make_pair(ParamLoc, processArgument(ArgVal, ArgExpr, *I, SVB)));
}
// FIXME: Variadic arguments are not handled at all right now.
@@ -477,24 +514,23 @@ const ConstructionContext *CallEvent::getConstructionContext() const {
return nullptr;
}
-Optional<SVal>
-CallEvent::getReturnValueUnderConstruction() const {
+std::optional<SVal> CallEvent::getReturnValueUnderConstruction() const {
const auto *CC = getConstructionContext();
if (!CC)
- return None;
+ return std::nullopt;
EvalCallOptions CallOpts;
ExprEngine &Engine = getState()->getStateManager().getOwningEngine();
- SVal RetVal =
- Engine.computeObjectUnderConstruction(getOriginExpr(), getState(),
- getLocationContext(), CC, CallOpts);
+ SVal RetVal = Engine.computeObjectUnderConstruction(
+ getOriginExpr(), getState(), &Engine.getBuilderContext(),
+ getLocationContext(), CC, CallOpts);
return RetVal;
}
ArrayRef<ParmVarDecl*> AnyFunctionCall::parameters() const {
const FunctionDecl *D = getDecl();
if (!D)
- return None;
+ return std::nullopt;
return D->parameters();
}
@@ -770,7 +806,7 @@ void CXXInstanceCall::getInitialStackFrameContents(
QualType Ty = Ctx.getPointerType(Ctx.getRecordType(Class));
// FIXME: CallEvent maybe shouldn't be directly accessing StoreManager.
- Optional<SVal> V =
+ std::optional<SVal> V =
StateMgr.getStoreManager().evalBaseToDerived(ThisVal, Ty);
if (!V) {
// We might have suffered some sort of placement new earlier, so
@@ -819,7 +855,7 @@ const BlockDataRegion *BlockCall::getBlockRegion() const {
ArrayRef<ParmVarDecl*> BlockCall::parameters() const {
const BlockDecl *D = getDecl();
if (!D)
- return None;
+ return std::nullopt;
return D->parameters();
}
@@ -908,7 +944,7 @@ RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const {
ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const {
const ObjCMethodDecl *D = getDecl();
if (!D)
- return None;
+ return std::nullopt;
return D->parameters();
}
@@ -1124,7 +1160,7 @@ static const ObjCMethodDecl *findDefiningRedecl(const ObjCMethodDecl *MD) {
// Find the redeclaration that defines the method.
if (!MD->hasBody()) {
- for (auto I : MD->redecls())
+ for (auto *I : MD->redecls())
if (I->hasBody())
MD = cast<ObjCMethodDecl>(I);
}
@@ -1185,10 +1221,10 @@ lookupRuntimeDefinition(const ObjCInterfaceDecl *Interface,
// stays around until clang quits, which also may be bad if we
// need to release memory.
using PrivateMethodCache =
- llvm::DenseMap<PrivateMethodKey, Optional<const ObjCMethodDecl *>>;
+ llvm::DenseMap<PrivateMethodKey, std::optional<const ObjCMethodDecl *>>;
static PrivateMethodCache PMC;
- Optional<const ObjCMethodDecl *> &Val =
+ std::optional<const ObjCMethodDecl *> &Val =
PMC[{Interface, LookupSelector, InstanceMethod}];
// Query lookupPrivateMethod() if the cache does not hit.
@@ -1398,9 +1434,10 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
SVal ThisVal = State->getSVal(ThisPtr);
const Stmt *Trigger;
- if (Optional<CFGAutomaticObjDtor> AutoDtor = E.getAs<CFGAutomaticObjDtor>())
+ if (std::optional<CFGAutomaticObjDtor> AutoDtor =
+ E.getAs<CFGAutomaticObjDtor>())
Trigger = AutoDtor->getTriggerStmt();
- else if (Optional<CFGDeleteDtor> DeleteDtor = E.getAs<CFGDeleteDtor>())
+ else if (std::optional<CFGDeleteDtor> DeleteDtor = E.getAs<CFGDeleteDtor>())
Trigger = DeleteDtor->getDeleteExpr();
else
Trigger = Dtor->getBody();
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp b/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
index 626ae1ae8066..84ad20a54807 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
+#include <optional>
namespace clang {
@@ -110,14 +111,13 @@ Nullability getNullabilityAnnotation(QualType Type) {
return Nullability::Unspecified;
}
-llvm::Optional<int> tryExpandAsInteger(StringRef Macro,
- const Preprocessor &PP) {
+std::optional<int> tryExpandAsInteger(StringRef Macro, const Preprocessor &PP) {
const auto *MacroII = PP.getIdentifierInfo(Macro);
if (!MacroII)
- return llvm::None;
+ return std::nullopt;
const MacroInfo *MI = PP.getMacroInfo(MacroII);
if (!MI)
- return llvm::None;
+ return std::nullopt;
// Filter out parens.
std::vector<Token> FilteredTokens;
@@ -131,12 +131,12 @@ llvm::Optional<int> tryExpandAsInteger(StringRef Macro,
// FIXME: EOF macro token coming from a PCH file on macOS while marked as
// literal, doesn't contain any literal data
if (!T.isLiteral() || !T.getLiteralData())
- return llvm::None;
+ return std::nullopt;
StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength());
llvm::APInt IntValue;
constexpr unsigned AutoSenseRadix = 0;
if (ValueStr.getAsInteger(AutoSenseRadix, IntValue))
- return llvm::None;
+ return std::nullopt;
// Parse an optional minus sign.
size_t Size = FilteredTokens.size();
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 94287b7992dd..6fc16223ea82 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -28,6 +28,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include <cassert>
+#include <optional>
#include <vector>
using namespace clang;
@@ -35,10 +36,7 @@ using namespace ento;
bool CheckerManager::hasPathSensitiveCheckers() const {
const auto IfAnyAreNonEmpty = [](const auto &... Callbacks) -> bool {
- bool Result = false;
- // FIXME: Use fold expressions in C++17.
- LLVM_ATTRIBUTE_UNUSED int Unused[]{0, (Result |= !Callbacks.empty())...};
- return Result;
+ return (!Callbacks.empty() || ...);
};
return IfAnyAreNonEmpty(
StmtCheckers, PreObjCMessageCheckers, ObjCMessageNilCheckers,
@@ -656,7 +654,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
ExprEngine &Eng,
const EvalCallOptions &CallOpts) {
for (auto *const Pred : Src) {
- Optional<CheckerNameRef> evaluatorChecker;
+ std::optional<CheckerNameRef> evaluatorChecker;
ExplodedNodeSet checkDst;
NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index de90f4a71be0..386a34f6cd4a 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -26,7 +26,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
@@ -34,6 +33,7 @@
#include <algorithm>
#include <cassert>
#include <memory>
+#include <optional>
#include <utility>
using namespace clang;
@@ -273,10 +273,10 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
const ReturnStmt *RS = nullptr;
if (!L.getSrc()->empty()) {
CFGElement LastElement = L.getSrc()->back();
- if (Optional<CFGStmt> LastStmt = LastElement.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> LastStmt = LastElement.getAs<CFGStmt>()) {
RS = dyn_cast<ReturnStmt>(LastStmt->getStmt());
- } else if (Optional<CFGAutomaticObjDtor> AutoDtor =
- LastElement.getAs<CFGAutomaticObjDtor>()) {
+ } else if (std::optional<CFGAutomaticObjDtor> AutoDtor =
+ LastElement.getAs<CFGAutomaticObjDtor>()) {
RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt());
}
}
@@ -314,11 +314,10 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
setBlockCounter(Counter);
// Process the entrance of the block.
- if (Optional<CFGElement> E = L.getFirstElement()) {
+ if (std::optional<CFGElement> E = L.getFirstElement()) {
NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
ExprEng.processCFGElement(*E, Pred, 0, &Ctx);
- }
- else
+ } else
HandleBlockExit(L.getBlock(), Pred);
}
@@ -616,7 +615,7 @@ void CoreEngine::enqueue(ExplodedNodeSet &Set,
}
void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS) {
- for (auto I : Set) {
+ for (auto *I : Set) {
// If we are in an inlined call, generate CallExitBegin node.
if (I->getLocationContext()->getParent()) {
I = generateCallExitBeginNode(I, RS);
diff --git a/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp b/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
index db9698b4086e..6a86536492cd 100644
--- a/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
@@ -44,6 +44,7 @@ DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
const MemRegion *MR,
SValBuilder &SVB,
QualType ElementTy) {
+ assert(MR != nullptr && "Not-null region expected");
MR = MR->StripCasts();
DefinedOrUnknownSVal Size = getDynamicExtent(State, MR, SVB);
diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp
index 719793fa224c..3d017b81762a 100644
--- a/clang/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp
@@ -274,7 +274,8 @@ void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
const Stmt *S = I->first.getStmt();
Indent(Out, InnerSpace, IsDot)
- << "{ \"stmt_id\": " << S->getID(Ctx) << ", \"pretty\": ";
+ << "{ \"stmt_id\": " << S->getID(Ctx) << ", \"kind\": \""
+ << S->getStmtClassName() << "\", \"pretty\": ";
S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);
Out << ", \"value\": ";
diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index 294572b7dbe4..d274d4d16db3 100644
--- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -25,12 +25,12 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include <cassert>
#include <memory>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -139,7 +139,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// Condition 10.
const ProgramPoint SuccLoc = succ->getLocation();
- if (Optional<StmtPoint> SP = SuccLoc.getAs<StmtPoint>())
+ if (std::optional<StmtPoint> SP = SuccLoc.getAs<StmtPoint>())
if (CallEvent::isCallStmt(SP->getStmt()))
return false;
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 19149d079822..977c2b7f51fd 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -48,6 +48,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h"
@@ -64,7 +65,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
@@ -77,6 +77,7 @@
#include <cassert>
#include <cstdint>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -187,7 +188,7 @@ REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction,
// This trait is responsible for storing the index of the element that is to be
// constructed in the next iteration. As a result a CXXConstructExpr is only
-// stored if it is array type. Also the index is the index of the continous
+// stored if it is array type. Also the index is the index of the continuous
// memory region, which is important for multi-dimensional arrays. E.g:: int
// arr[2][2]; assume arr[1][1] will be the next element under construction, so
// the index is 3.
@@ -204,6 +205,12 @@ typedef llvm::ImmutableMap<
std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned>
PendingInitLoopMap;
REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingInitLoop, PendingInitLoopMap)
+
+typedef llvm::ImmutableMap<const LocationContext *, unsigned>
+ PendingArrayDestructionMap;
+REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingArrayDestruction,
+ PendingArrayDestructionMap)
+
//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
@@ -263,7 +270,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
svalBuilder.makeZeroVal(T),
svalBuilder.getConditionType());
- Optional<DefinedOrUnknownSVal> Constraint =
+ std::optional<DefinedOrUnknownSVal> Constraint =
Constraint_untested.getAs<DefinedOrUnknownSVal>();
if (!Constraint)
@@ -283,7 +290,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
const MemRegion *R = state->getRegion(SelfD, InitLoc);
SVal V = state->getSVal(loc::MemRegionVal(R));
- if (Optional<Loc> LV = V.getAs<Loc>()) {
+ if (std::optional<Loc> LV = V.getAs<Loc>()) {
// Assume that the pointer value in 'self' is non-null.
state = state->assume(*LV, true);
assert(state && "'self' cannot be null");
@@ -299,7 +306,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
if (SFC->getParent() == nullptr) {
loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC);
SVal V = state->getSVal(L);
- if (Optional<Loc> LV = V.getAs<Loc>()) {
+ if (std::optional<Loc> LV = V.getAs<Loc>()) {
state = state->assume(*LV, true);
assert(state && "'this' cannot be null");
}
@@ -375,7 +382,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded(
// into that region. This is not correct, but it is better than nothing.
const TypedValueRegion *TR = nullptr;
if (const auto *MT = dyn_cast<MaterializeTemporaryExpr>(Result)) {
- if (Optional<SVal> V = getObjectUnderConstruction(State, MT, LC)) {
+ if (std::optional<SVal> V = getObjectUnderConstruction(State, MT, LC)) {
State = finishObjectConstruction(State, MT, LC);
State = State->BindExpr(Result, LC, *V);
return State;
@@ -470,12 +477,11 @@ ProgramStateRef ExprEngine::setIndexOfElementToConstruct(
return State->set<IndexOfElementToConstruct>(Key, Idx);
}
-Optional<unsigned> ExprEngine::getPendingInitLoop(ProgramStateRef State,
- const CXXConstructExpr *E,
- const LocationContext *LCtx) {
-
- return Optional<unsigned>::create(
- State->get<PendingInitLoop>({E, LCtx->getStackFrame()}));
+std::optional<unsigned>
+ExprEngine::getPendingInitLoop(ProgramStateRef State, const CXXConstructExpr *E,
+ const LocationContext *LCtx) {
+ const unsigned *V = State->get<PendingInitLoop>({E, LCtx->getStackFrame()});
+ return V ? std::make_optional(*V) : std::nullopt;
}
ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State,
@@ -498,13 +504,13 @@ ProgramStateRef ExprEngine::setPendingInitLoop(ProgramStateRef State,
return State->set<PendingInitLoop>(Key, Size);
}
-Optional<unsigned>
+std::optional<unsigned>
ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State,
const CXXConstructExpr *E,
const LocationContext *LCtx) {
-
- return Optional<unsigned>::create(
- State->get<IndexOfElementToConstruct>({E, LCtx->getStackFrame()}));
+ const unsigned *V =
+ State->get<IndexOfElementToConstruct>({E, LCtx->getStackFrame()});
+ return V ? std::make_optional(*V) : std::nullopt;
}
ProgramStateRef
@@ -517,6 +523,36 @@ ExprEngine::removeIndexOfElementToConstruct(ProgramStateRef State,
return State->remove<IndexOfElementToConstruct>(Key);
}
+std::optional<unsigned>
+ExprEngine::getPendingArrayDestruction(ProgramStateRef State,
+ const LocationContext *LCtx) {
+ assert(LCtx && "LocationContext shouldn't be null!");
+
+ const unsigned *V =
+ State->get<PendingArrayDestruction>(LCtx->getStackFrame());
+ return V ? std::make_optional(*V) : std::nullopt;
+}
+
+ProgramStateRef ExprEngine::setPendingArrayDestruction(
+ ProgramStateRef State, const LocationContext *LCtx, unsigned Idx) {
+ assert(LCtx && "LocationContext shouldn't be null!");
+
+ auto Key = LCtx->getStackFrame();
+
+ return State->set<PendingArrayDestruction>(Key, Idx);
+}
+
+ProgramStateRef
+ExprEngine::removePendingArrayDestruction(ProgramStateRef State,
+ const LocationContext *LCtx) {
+ assert(LCtx && "LocationContext shouldn't be null!");
+
+ auto Key = LCtx->getStackFrame();
+
+ assert(LCtx && State->contains<PendingArrayDestruction>(Key));
+ return State->remove<PendingArrayDestruction>(Key);
+}
+
ProgramStateRef
ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
const ConstructionContextItem &Item,
@@ -537,9 +573,10 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
Init = Item.getCXXCtorInitializer()->getInit();
// In an ArrayInitLoopExpr the real initializer is returned by
- // getSubExpr().
+ // getSubExpr(). Note that AILEs can be nested in case of
+ // multidimesnional arrays.
if (const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init))
- Init = AILE->getSubExpr();
+ Init = extractElementInitializerFromNestedAILE(AILE);
// FIXME: Currently the state might already contain the marker due to
// incorrect handling of temporaries bound to default parameters.
@@ -557,12 +594,13 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
return State->set<ObjectsUnderConstruction>(Key, V);
}
-Optional<SVal>
+std::optional<SVal>
ExprEngine::getObjectUnderConstruction(ProgramStateRef State,
const ConstructionContextItem &Item,
const LocationContext *LC) {
ConstructedObjectKey Key(Item, LC->getStackFrame());
- return Optional<SVal>::create(State->get<ObjectsUnderConstruction>(Key));
+ const SVal *V = State->get<ObjectsUnderConstruction>(Key);
+ return V ? std::make_optional(*V) : std::nullopt;
}
ProgramStateRef
@@ -656,7 +694,7 @@ printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State,
continue;
if (!HasItem) {
- Out << "[" << NL;
+ Out << '[' << NL;
HasItem = true;
}
@@ -687,12 +725,11 @@ printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State,
static void printIndicesOfElementsToConstructJson(
raw_ostream &Out, ProgramStateRef State, const char *NL,
- const LocationContext *LCtx, const ASTContext &Context,
- unsigned int Space = 0, bool IsDot = false) {
+ const LocationContext *LCtx, unsigned int Space = 0, bool IsDot = false) {
using KeyT = std::pair<const Expr *, const LocationContext *>;
- PrintingPolicy PP =
- LCtx->getAnalysisDeclContext()->getASTContext().getPrintingPolicy();
+ const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext();
+ PrintingPolicy PP = Context.getPrintingPolicy();
++Space;
bool HasItem = false;
@@ -705,7 +742,7 @@ static void printIndicesOfElementsToConstructJson(
continue;
if (!HasItem) {
- Out << "[" << NL;
+ Out << '[' << NL;
HasItem = true;
}
@@ -724,17 +761,17 @@ static void printIndicesOfElementsToConstructJson(
const Expr *E = Key.first;
Out << "\"stmt_id\": " << E->getID(Context);
- // Kind - hack to display the current index
- Out << ", \"kind\": \"Cur: " << Value - 1 << "\"";
+ // Kind
+ Out << ", \"kind\": null";
// Pretty-print
Out << ", \"pretty\": ";
- Out << "\"" << E->getStmtClassName() << " "
+ Out << "\"" << E->getStmtClassName() << ' '
<< E->getSourceRange().printToString(Context.getSourceManager()) << " '"
<< QualType::getAsString(E->getType().split(), PP);
Out << "'\"";
- Out << ", \"value\": \"Next: " << Value << "\" }";
+ Out << ", \"value\": \"Current index: " << Value - 1 << "\" }";
if (Key != LastKey)
Out << ',';
@@ -748,40 +785,168 @@ static void printIndicesOfElementsToConstructJson(
}
}
-void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State,
- const LocationContext *LCtx, const char *NL,
- unsigned int Space, bool IsDot) const {
- Indent(Out, Space, IsDot) << "\"constructing_objects\": ";
+static void printPendingInitLoopJson(raw_ostream &Out, ProgramStateRef State,
+ const char *NL,
+ const LocationContext *LCtx,
+ unsigned int Space = 0,
+ bool IsDot = false) {
+ using KeyT = std::pair<const CXXConstructExpr *, const LocationContext *>;
- if (LCtx && !State->get<ObjectsUnderConstruction>().isEmpty()) {
- ++Space;
- Out << '[' << NL;
- LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
- printObjectsUnderConstructionJson(Out, State, NL, LC, Space, IsDot);
- });
+ const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext();
+ PrintingPolicy PP = Context.getPrintingPolicy();
- --Space;
- Indent(Out, Space, IsDot) << "]," << NL; // End of "constructing_objects".
- } else {
- Out << "null," << NL;
+ ++Space;
+ bool HasItem = false;
+
+ // Store the last key.
+ KeyT LastKey;
+ for (const auto &I : State->get<PendingInitLoop>()) {
+ const KeyT &Key = I.first;
+ if (Key.second != LCtx)
+ continue;
+
+ if (!HasItem) {
+ Out << '[' << NL;
+ HasItem = true;
+ }
+
+ LastKey = Key;
}
- Indent(Out, Space, IsDot) << "\"index_of_element\": ";
- if (LCtx && !State->get<IndexOfElementToConstruct>().isEmpty()) {
- ++Space;
+ for (const auto &I : State->get<PendingInitLoop>()) {
+ const KeyT &Key = I.first;
+ unsigned Value = I.second;
+ if (Key.second != LCtx)
+ continue;
+
+ Indent(Out, Space, IsDot) << "{ ";
+
+ const CXXConstructExpr *E = Key.first;
+ Out << "\"stmt_id\": " << E->getID(Context);
+
+ Out << ", \"kind\": null";
+ Out << ", \"pretty\": ";
+ Out << '\"' << E->getStmtClassName() << ' '
+ << E->getSourceRange().printToString(Context.getSourceManager()) << " '"
+ << QualType::getAsString(E->getType().split(), PP);
+ Out << "'\"";
+
+ Out << ", \"value\": \"Flattened size: " << Value << "\"}";
+
+ if (Key != LastKey)
+ Out << ',';
+ Out << NL;
+ }
+
+ if (HasItem)
+ Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
+ else {
+ Out << "null ";
+ }
+}
+
+static void
+printPendingArrayDestructionsJson(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const LocationContext *LCtx,
+ unsigned int Space = 0, bool IsDot = false) {
+ using KeyT = const LocationContext *;
+
+ ++Space;
+ bool HasItem = false;
+
+ // Store the last key.
+ KeyT LastKey = nullptr;
+ for (const auto &I : State->get<PendingArrayDestruction>()) {
+ const KeyT &Key = I.first;
+ if (Key != LCtx)
+ continue;
+
+ if (!HasItem) {
+ Out << '[' << NL;
+ HasItem = true;
+ }
+
+ LastKey = Key;
+ }
+
+ for (const auto &I : State->get<PendingArrayDestruction>()) {
+ const KeyT &Key = I.first;
+ if (Key != LCtx)
+ continue;
+
+ Indent(Out, Space, IsDot) << "{ ";
+
+ Out << "\"stmt_id\": null";
+ Out << ", \"kind\": null";
+ Out << ", \"pretty\": \"Current index: \"";
+ Out << ", \"value\": \"" << I.second << "\" }";
+
+ if (Key != LastKey)
+ Out << ',';
+ Out << NL;
+ }
+
+ if (HasItem)
+ Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
+ else {
+ Out << "null ";
+ }
+}
- auto &Context = getContext();
+/// A helper function to generalize program state trait printing.
+/// The function invokes Printer as 'Printer(Out, State, NL, LC, Space, IsDot,
+/// std::forward<Args>(args)...)'. \n One possible type for Printer is
+/// 'void()(raw_ostream &, ProgramStateRef, const char *, const LocationContext
+/// *, unsigned int, bool, ...)' \n \param Trait The state trait to be printed.
+/// \param Printer A void function that prints Trait.
+/// \param Args An additional parameter pack that is passed to Print upon
+/// invocation.
+template <typename Trait, typename Printer, typename... Args>
+static void printStateTraitWithLocationContextJson(
+ raw_ostream &Out, ProgramStateRef State, const LocationContext *LCtx,
+ const char *NL, unsigned int Space, bool IsDot,
+ const char *jsonPropertyName, Printer printer, Args &&...args) {
+
+ using RequiredType =
+ void (*)(raw_ostream &, ProgramStateRef, const char *,
+ const LocationContext *, unsigned int, bool, Args &&...);
+
+ // Try to do as much compile time checking as possible.
+ // FIXME: check for invocable instead of function?
+ static_assert(std::is_function_v<std::remove_pointer_t<Printer>>,
+ "Printer is not a function!");
+ static_assert(std::is_convertible_v<Printer, RequiredType>,
+ "Printer doesn't have the required type!");
+
+ if (LCtx && !State->get<Trait>().isEmpty()) {
+ Indent(Out, Space, IsDot) << '\"' << jsonPropertyName << "\": ";
+ ++Space;
Out << '[' << NL;
LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
- printIndicesOfElementsToConstructJson(Out, State, NL, LC, Context, Space,
- IsDot);
+ printer(Out, State, NL, LC, Space, IsDot, std::forward<Args>(args)...);
});
--Space;
- Indent(Out, Space, IsDot) << "]," << NL; // End of "index_of_element".
- } else {
- Out << "null," << NL;
+ Indent(Out, Space, IsDot) << "]," << NL; // End of "jsonPropertyName".
}
+}
+
+void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State,
+ const LocationContext *LCtx, const char *NL,
+ unsigned int Space, bool IsDot) const {
+
+ printStateTraitWithLocationContextJson<ObjectsUnderConstruction>(
+ Out, State, LCtx, NL, Space, IsDot, "constructing_objects",
+ printObjectsUnderConstructionJson);
+ printStateTraitWithLocationContextJson<IndexOfElementToConstruct>(
+ Out, State, LCtx, NL, Space, IsDot, "index_of_element",
+ printIndicesOfElementsToConstructJson);
+ printStateTraitWithLocationContextJson<PendingInitLoop>(
+ Out, State, LCtx, NL, Space, IsDot, "pending_init_loops",
+ printPendingInitLoopJson);
+ printStateTraitWithLocationContextJson<PendingArrayDestruction>(
+ Out, State, LCtx, NL, Space, IsDot, "pending_destructors",
+ printPendingArrayDestructionsJson);
getCheckerManager().runCheckersForPrintStateJson(Out, State, NL, Space,
IsDot);
@@ -1034,7 +1199,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
SVal LValue = State->getSVal(Init, stackFrame);
if (!Field->getType()->isReferenceType())
- if (Optional<Loc> LValueLoc = LValue.getAs<Loc>())
+ if (std::optional<Loc> LValueLoc = LValue.getAs<Loc>())
InitVal = State->getSVal(*LValueLoc);
// If we fail to get the value for some reason, use a symbolic value.
@@ -1071,6 +1236,43 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
+std::pair<ProgramStateRef, uint64_t>
+ExprEngine::prepareStateForArrayDestruction(const ProgramStateRef State,
+ const MemRegion *Region,
+ const QualType &ElementTy,
+ const LocationContext *LCtx,
+ SVal *ElementCountVal) {
+ assert(Region != nullptr && "Not-null region expected");
+
+ QualType Ty = ElementTy.getDesugaredType(getContext());
+ while (const auto *NTy = dyn_cast<ArrayType>(Ty))
+ Ty = NTy->getElementType().getDesugaredType(getContext());
+
+ auto ElementCount = getDynamicElementCount(State, Region, svalBuilder, Ty);
+
+ if (ElementCountVal)
+ *ElementCountVal = ElementCount;
+
+ // Note: the destructors are called in reverse order.
+ unsigned Idx = 0;
+ if (auto OptionalIdx = getPendingArrayDestruction(State, LCtx)) {
+ Idx = *OptionalIdx;
+ } else {
+ // The element count is either unknown, or an SVal that's not an integer.
+ if (!ElementCount.isConstant())
+ return {State, 0};
+
+ Idx = ElementCount.getAsInteger()->getLimitedValue();
+ }
+
+ if (Idx == 0)
+ return {State, 0};
+
+ --Idx;
+
+ return {setPendingArrayDestruction(State, LCtx, Idx), Idx};
+}
+
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
ExplodedNode *Pred) {
ExplodedNodeSet Dst;
@@ -1120,11 +1322,14 @@ void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
+ const auto *DtorDecl = Dtor.getDestructorDecl(getContext());
const VarDecl *varDecl = Dtor.getVarDecl();
QualType varType = varDecl->getType();
ProgramStateRef state = Pred->getState();
- SVal dest = state->getLValue(varDecl, Pred->getLocationContext());
+ const LocationContext *LCtx = Pred->getLocationContext();
+
+ SVal dest = state->getLValue(varDecl, LCtx);
const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
if (varType->isReferenceType()) {
@@ -1140,14 +1345,46 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
varType = cast<TypedValueRegion>(Region)->getValueType();
}
- // 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
- // invalidate the entire array).
+ unsigned Idx = 0;
+ if (isa<ArrayType>(varType)) {
+ SVal ElementCount;
+ std::tie(state, Idx) = prepareStateForArrayDestruction(
+ state, Region, varType, LCtx, &ElementCount);
+
+ if (ElementCount.isConstant()) {
+ uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
+ assert(ArrayLength &&
+ "An automatic dtor for a 0 length array shouldn't be triggered!");
+
+ // Still handle this case if we don't have assertions enabled.
+ if (!ArrayLength) {
+ static SimpleProgramPointTag PT(
+ "ExprEngine", "Skipping automatic 0 length array destruction, "
+ "which shouldn't be in the CFG.");
+ PostImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT);
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ Bldr.generateSink(PP, Pred->getState(), Pred);
+ return;
+ }
+ }
+ }
+
EvalCallOptions CallOpts;
Region = makeElementRegion(state, loc::MemRegionVal(Region), varType,
- CallOpts.IsArrayCtorOrDtor)
+ CallOpts.IsArrayCtorOrDtor, Idx)
.getAsRegion();
+ NodeBuilder Bldr(Pred, Dst, getBuilderContext());
+
+ static SimpleProgramPointTag PT("ExprEngine",
+ "Prepare for object destruction");
+ PreImplicitCall PP(DtorDecl, varDecl->getLocation(), LCtx, &PT);
+ Pred = Bldr.generateNode(PP, state, Pred);
+
+ if (!Pred)
+ return;
+ Bldr.takeNodes(Pred);
+
VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(),
/*IsBase=*/false, Pred, Dst, CallOpts);
}
@@ -1175,20 +1412,54 @@ void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
return;
}
+ auto getDtorDecl = [](const QualType &DTy) {
+ const CXXRecordDecl *RD = DTy->getAsCXXRecordDecl();
+ return RD->getDestructor();
+ };
+
+ unsigned Idx = 0;
EvalCallOptions CallOpts;
const MemRegion *ArgR = ArgVal.getAsRegion();
+
if (DE->isArrayForm()) {
- // 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
- // invalidate the entire array).
CallOpts.IsArrayCtorOrDtor = true;
// Yes, it may even be a multi-dimensional array.
while (const auto *AT = getContext().getAsArrayType(DTy))
DTy = AT->getElementType();
- if (ArgR)
- ArgR = getStoreManager().GetElementZeroRegion(cast<SubRegion>(ArgR), DTy);
+
+ if (ArgR) {
+ SVal ElementCount;
+ std::tie(State, Idx) = prepareStateForArrayDestruction(
+ State, ArgR, DTy, LCtx, &ElementCount);
+
+ // If we're about to destruct a 0 length array, don't run any of the
+ // destructors.
+ if (ElementCount.isConstant() &&
+ ElementCount.getAsInteger()->getLimitedValue() == 0) {
+
+ static SimpleProgramPointTag PT(
+ "ExprEngine", "Skipping 0 length array delete destruction");
+ PostImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT);
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ Bldr.generateNode(PP, Pred->getState(), Pred);
+ return;
+ }
+
+ ArgR = State->getLValue(DTy, svalBuilder.makeArrayIndex(Idx), ArgVal)
+ .getAsRegion();
+ }
}
+ NodeBuilder Bldr(Pred, Dst, getBuilderContext());
+ static SimpleProgramPointTag PT("ExprEngine",
+ "Prepare for object destruction");
+ PreImplicitCall PP(getDtorDecl(DTy), DE->getBeginLoc(), LCtx, &PT);
+ Pred = Bldr.generateNode(PP, State, Pred);
+
+ if (!Pred)
+ return;
+ Bldr.takeNodes(Pred);
+
VisitCXXDestructor(DTy, ArgR, DE, /*IsBase=*/false, Pred, Dst, CallOpts);
}
@@ -1214,6 +1485,7 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ const auto *DtorDecl = D.getDestructorDecl(getContext());
const FieldDecl *Member = D.getFieldDecl();
QualType T = Member->getType();
ProgramStateRef State = Pred->getState();
@@ -1225,11 +1497,44 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
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
- // invalidate the entire array).
+ unsigned Idx = 0;
+ if (isa<ArrayType>(T)) {
+ SVal ElementCount;
+ std::tie(State, Idx) = prepareStateForArrayDestruction(
+ State, FieldVal.getAsRegion(), T, LCtx, &ElementCount);
+
+ if (ElementCount.isConstant()) {
+ uint64_t ArrayLength = ElementCount.getAsInteger()->getLimitedValue();
+ assert(ArrayLength &&
+ "A member dtor for a 0 length array shouldn't be triggered!");
+
+ // Still handle this case if we don't have assertions enabled.
+ if (!ArrayLength) {
+ static SimpleProgramPointTag PT(
+ "ExprEngine", "Skipping member 0 length array destruction, which "
+ "shouldn't be in the CFG.");
+ PostImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT);
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ Bldr.generateSink(PP, Pred->getState(), Pred);
+ return;
+ }
+ }
+ }
+
EvalCallOptions CallOpts;
- FieldVal = makeElementRegion(State, FieldVal, T, CallOpts.IsArrayCtorOrDtor);
+ FieldVal =
+ makeElementRegion(State, FieldVal, T, CallOpts.IsArrayCtorOrDtor, Idx);
+
+ NodeBuilder Bldr(Pred, Dst, getBuilderContext());
+
+ static SimpleProgramPointTag PT("ExprEngine",
+ "Prepare for object destruction");
+ PreImplicitCall PP(DtorDecl, Member->getLocation(), LCtx, &PT);
+ Pred = Bldr.generateNode(PP, State, Pred);
+
+ if (!Pred)
+ return;
+ Bldr.takeNodes(Pred);
VisitCXXDestructor(T, FieldVal.getAsRegion(), CurDtor->getBody(),
/*IsBase=*/false, Pred, Dst, CallOpts);
@@ -1243,9 +1548,8 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
const LocationContext *LC = Pred->getLocationContext();
const MemRegion *MR = nullptr;
- if (Optional<SVal> V =
- getObjectUnderConstruction(State, D.getBindTemporaryExpr(),
- Pred->getLocationContext())) {
+ if (std::optional<SVal> V = getObjectUnderConstruction(
+ State, D.getBindTemporaryExpr(), Pred->getLocationContext())) {
// FIXME: Currently we insert temporary destructors for default parameters,
// but we don't insert the constructors, so the entry in
// ObjectsUnderConstruction may be missing.
@@ -1280,15 +1584,31 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
EvalCallOptions CallOpts;
CallOpts.IsTemporaryCtorOrDtor = true;
if (!MR) {
- // 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.
+ // FIXME: If we have no MR, we still need to unwrap the array to avoid
+ // destroying the whole array at once.
+ //
+ // For this case there is no universal solution as there is no way to
+ // directly create an array of temporary objects. There are some expressions
+ // however which can create temporary objects and have an array type.
+ //
+ // E.g.: std::initializer_list<S>{S(), S()};
+ //
+ // The expression above has a type of 'const struct S[2]' but it's a single
+ // 'std::initializer_list<>'. The destructors of the 2 temporary 'S()'
+ // objects will be called anyway, because they are 2 separate objects in 2
+ // separate clusters, i.e.: not an array.
+ //
+ // Now the 'std::initializer_list<>' is not an array either even though it
+ // has the type of an array. The point is, we only want to invoke the
+ // destructor for the initializer list once not twice or so.
while (const ArrayType *AT = getContext().getAsArrayType(T)) {
T = AT->getElementType();
- CallOpts.IsArrayCtorOrDtor = true;
+
+ // FIXME: Enable this flag once we handle this case properly.
+ // CallOpts.IsArrayCtorOrDtor = true;
}
} else {
- // We'd eventually need to makeElementRegion() trick here,
+ // FIXME: We'd eventually need to makeElementRegion() trick here,
// but for now we don't have the respective construction contexts,
// so MR would always be null in this case. Do nothing for now.
}
@@ -1426,6 +1746,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPTaskyieldDirectiveClass:
case Stmt::OMPBarrierDirectiveClass:
case Stmt::OMPTaskwaitDirectiveClass:
+ case Stmt::OMPErrorDirectiveClass:
case Stmt::OMPTaskgroupDirectiveClass:
case Stmt::OMPFlushDirectiveClass:
case Stmt::OMPDepobjDirectiveClass:
@@ -1579,6 +1900,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::ConceptSpecializationExprClass:
case Stmt::CXXRewrittenBinaryOperatorClass:
case Stmt::RequiresExprClass:
+ case Expr::CXXParenListInitExprClass:
// Fall through.
// Cases we intentionally don't evaluate, since they don't need
@@ -1638,7 +1960,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
IsTemporary = true;
}
- Optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE);
+ std::optional<SVal> ConstantVal = svalBuilder.getConstantVal(ArgE);
if (!ConstantVal)
ConstantVal = UnknownVal();
@@ -1793,7 +2115,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
}
}
// FALLTHROUGH
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case Stmt::CallExprClass:
@@ -2104,7 +2426,7 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
continue;
if (L.getAs<CallEnter>())
continue;
- if (Optional<StmtPoint> SP = L.getAs<StmtPoint>())
+ if (std::optional<StmtPoint> SP = L.getAs<StmtPoint>())
if (SP->getStmt() == CE)
continue;
break;
@@ -2117,8 +2439,9 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
// Build an Epsilon node from which we will restart the analyzes.
// Note that CE is permitted to be NULL!
- ProgramPoint NewNodeLoc =
- EpsilonPoint(BeforeProcessingCall->getLocationContext(), CE);
+ static SimpleProgramPointTag PT("ExprEngine", "Replay without inlining");
+ ProgramPoint NewNodeLoc = EpsilonPoint(
+ BeforeProcessingCall->getLocationContext(), CE, nullptr, &PT);
// Add the special flag to GDM to signal retrying with no inlining.
// Note, changing the state ensures that we are not going to cache out.
ProgramStateRef NewNodeState = BeforeProcessingCall->getState();
@@ -2310,7 +2633,7 @@ static const Stmt *ResolveCondition(const Stmt *Condition,
CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend();
for (; I != E; ++I) {
CFGElement Elem = *I;
- Optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
+ std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
if (!CS)
continue;
const Stmt *LastStmt = CS->getStmt();
@@ -2348,9 +2671,9 @@ bool ExprEngine::hasMoreIteration(ProgramStateRef State,
}
/// Split the state on whether there are any more iterations left for this loop.
-/// Returns a (HasMoreIteration, HasNoMoreIteration) pair, or None when the
-/// acquisition of the loop condition value failed.
-static Optional<std::pair<ProgramStateRef, ProgramStateRef>>
+/// Returns a (HasMoreIteration, HasNoMoreIteration) pair, or std::nullopt when
+/// the acquisition of the loop condition value failed.
+static std::optional<std::pair<ProgramStateRef, ProgramStateRef>>
assumeCondition(const Stmt *Condition, ExplodedNode *N) {
ProgramStateRef State = N->getState();
if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(Condition)) {
@@ -2389,7 +2712,7 @@ assumeCondition(const Stmt *Condition, ExplodedNode *N) {
// If the condition is still unknown, give up.
if (X.isUnknownOrUndef())
- return None;
+ return std::nullopt;
DefinedSVal V = X.castAs<DefinedSVal>();
@@ -2514,7 +2837,7 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
using iterator = IndirectGotoNodeBuilder::iterator;
- if (Optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) {
+ if (std::optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) {
const LabelDecl *L = LV->getLabel();
for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) {
@@ -2666,7 +2989,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
V2 = V1;
ProgramStateRef StateCase;
- if (Optional<NonLoc> NL = CondV.getAs<NonLoc>())
+ if (std::optional<NonLoc> NL = CondV.getAs<NonLoc>())
std::tie(StateCase, DefaultSt) =
DefaultSt->assumeInclusiveRange(*NL, V1, V2);
else // UnknownVal
@@ -2725,14 +3048,14 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
const Decl *D = LocCtxt->getDecl();
const auto *MD = dyn_cast_or_null<CXXMethodDecl>(D);
const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex);
- Optional<std::pair<SVal, QualType>> VInfo;
+ std::optional<std::pair<SVal, QualType>> VInfo;
if (AMgr.options.ShouldInlineLambdas && DeclRefEx &&
DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
MD->getParent()->isLambda()) {
// Lookup the field of the lambda.
const CXXRecordDecl *CXXRec = MD->getParent();
- llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
FieldDecl *LambdaThisCaptureField;
CXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
@@ -2839,6 +3162,12 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
return;
}
+ if (const auto *TPO = dyn_cast<TemplateParamObjectDecl>(D)) {
+ // FIXME: We should meaningfully implement this.
+ (void)TPO;
+ return;
+ }
+
llvm_unreachable("Support for this Decl not implemented.");
}
@@ -2857,7 +3186,7 @@ void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
for (auto *Node : CheckerPreStmt) {
// The constructor visitior has already taken care of everything.
- if (auto *CE = dyn_cast<CXXConstructExpr>(Ex->getSubExpr()))
+ if (isa<CXXConstructExpr>(Ex->getSubExpr()))
break;
const LocationContext *LCtx = Node->getLocationContext();
@@ -3035,6 +3364,14 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
SVal baseExprVal =
MR ? loc::MemRegionVal(MR) : state->getSVal(BaseExpr, LCtx);
+ // FIXME: Copied from RegionStoreManager::bind()
+ if (const auto *SR =
+ dyn_cast_or_null<SymbolicRegion>(baseExprVal.getAsRegion())) {
+ QualType T = SR->getPointeeStaticType();
+ baseExprVal =
+ loc::MemRegionVal(getStoreManager().GetElementZeroRegion(SR, T));
+ }
+
const auto *field = cast<FieldDecl>(Member);
SVal L = state->getLValue(field, baseExprVal);
@@ -3124,7 +3461,8 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(
for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
// Cases (1) and (2).
const MemRegion *MR = LocAndVal.first.getAsRegion();
- if (!MR || !MR->hasStackStorage()) {
+ if (!MR ||
+ !isa<StackSpaceRegion, StaticGlobalSpaceRegion>(MR->getMemorySpace())) {
Escaped.push_back(LocAndVal.second);
continue;
}
@@ -3248,7 +3586,7 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
Val, LC, /* notifyChanges = */ !atDeclInit);
const MemRegion *LocReg = nullptr;
- if (Optional<loc::MemRegionVal> LocRegVal =
+ if (std::optional<loc::MemRegionVal> LocRegVal =
location.getAs<loc::MemRegionVal>()) {
LocReg = LocRegVal->getRegion();
}
@@ -3389,7 +3727,7 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(Ex, Pred->getLocationContext());
- Optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
+ std::optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
geteagerlyAssumeBinOpBifurcationTags();
@@ -3430,7 +3768,7 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
SVal X = state->getSVal(O, Pred->getLocationContext());
assert(!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
- if (Optional<Loc> LV = X.getAs<Loc>())
+ if (std::optional<Loc> LV = X.getAs<Loc>())
state = state->bindLoc(*LV, UnknownVal(), Pred->getLocationContext());
}
@@ -3522,7 +3860,7 @@ 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 << ", \"node_id\": " << OtherNode->getID() <<
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 43e298f3de08..6652c065e04f 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -446,10 +447,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// Check if the value being cast does not evaluates to 0.
if (!val.isZeroConstant())
- if (Optional<SVal> V =
+ if (std::optional<SVal> V =
StateMgr.getStoreManager().evalBaseToDerived(val, T)) {
- val = *V;
- Failed = false;
+ val = *V;
+ Failed = false;
}
if (Failed) {
@@ -484,7 +485,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
resultType = getContext().getPointerType(resultType);
if (!val.isConstant()) {
- Optional<SVal> V = getStoreManager().evalBaseToDerived(val, T);
+ std::optional<SVal> V = getStoreManager().evalBaseToDerived(val, T);
val = V ? *V : UnknownVal();
}
@@ -524,7 +525,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
}
// Explicitly proceed with default handler for this case cascade.
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
// Various C++ casts that are not handled yet.
case CK_ToUnion:
case CK_MatrixCast:
@@ -823,7 +824,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
SVal V;
for (CFGElement CE : llvm::reverse(*SrcBlock)) {
- if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
const Expr *ValEx = cast<Expr>(CS->getStmt());
ValEx = ValEx->IgnoreParens();
@@ -1001,7 +1002,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
}
case UO_Plus:
assert(!U->isGLValue());
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case UO_Deref:
case UO_Extension: {
handleUOExtension(I, U, Bldr);
@@ -1043,16 +1044,15 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred,
// Note: technically we do "E == 0", but this is the same in the
// transfer functions as "0 == E".
SVal Result;
- if (Optional<Loc> LV = V.getAs<Loc>()) {
- Loc X = svalBuilder.makeNullWithType(Ex->getType());
- Result = evalBinOp(state, BO_EQ, *LV, X, U->getType());
+ if (std::optional<Loc> LV = V.getAs<Loc>()) {
+ Loc X = svalBuilder.makeNullWithType(Ex->getType());
+ Result = evalBinOp(state, BO_EQ, *LV, X, U->getType());
} else if (Ex->getType()->isFloatingType()) {
- // FIXME: handle floating point types.
- Result = UnknownVal();
+ // FIXME: handle floating point types.
+ Result = UnknownVal();
} else {
- nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
- Result = evalBinOp(state, BO_EQ, V.castAs<NonLoc>(), X,
- U->getType());
+ nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
+ Result = evalBinOp(state, BO_EQ, V.castAs<NonLoc>(), X, U->getType());
}
state = state->BindExpr(U, LCtx, Result);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 04e00274b2a7..6eb37287b136 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -10,15 +10,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/Analysis/ConstructionContext.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtCXX.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/ConstructionContext.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -74,7 +76,7 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
// If the value being copied is not unknown, load from its location to get
// an aggregate rvalue.
- if (Optional<Loc> L = V.getAs<Loc>())
+ if (std::optional<Loc> L = V.getAs<Loc>())
V = Pred->getState()->getSVal(*L);
else
assert(V.isUnknownOrUndef());
@@ -111,9 +113,15 @@ SVal ExprEngine::makeElementRegion(ProgramStateRef State, SVal LValue,
return LValue;
}
+// In case when the prvalue is returned from the function (kind is one of
+// SimpleReturnedValueKind, CXX17ElidedCopyReturnedValueKind), then
+// it's materialization happens in context of the caller.
+// We pass BldrCtx explicitly, as currBldrCtx always refers to callee's context.
SVal ExprEngine::computeObjectUnderConstruction(
- const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
- const ConstructionContext *CC, EvalCallOptions &CallOpts, unsigned Idx) {
+ const Expr *E, ProgramStateRef State, const NodeBuilderContext *BldrCtx,
+ const LocationContext *LCtx, const ConstructionContext *CC,
+ EvalCallOptions &CallOpts, unsigned Idx) {
+
SValBuilder &SVB = getSValBuilder();
MemRegionManager &MRMgr = SVB.getRegionManager();
ASTContext &ACtx = SVB.getContext();
@@ -171,13 +179,14 @@ SVal ExprEngine::computeObjectUnderConstruction(
if (const SubRegion *MR =
dyn_cast_or_null<SubRegion>(V.getAsRegion())) {
if (NE->isArray()) {
- // TODO: In fact, we need to call the constructor for every
- // allocated element, not just the first one!
CallOpts.IsArrayCtorOrDtor = true;
- auto R = MRMgr.getElementRegion(NE->getType()->getPointeeType(),
- svalBuilder.makeArrayIndex(Idx), MR,
- SVB.getContext());
+ auto Ty = NE->getType()->getPointeeType();
+ while (const auto *AT = getContext().getAsArrayType(Ty))
+ Ty = AT->getElementType();
+
+ auto R = MRMgr.getElementRegion(Ty, svalBuilder.makeArrayIndex(Idx),
+ MR, SVB.getContext());
return loc::MemRegionVal(R);
}
@@ -209,8 +218,11 @@ SVal ExprEngine::computeObjectUnderConstruction(
CallerLCtx = CallerLCtx->getParent();
assert(!isa<BlockInvocationContext>(CallerLCtx));
}
+
+ NodeBuilderContext CallerBldrCtx(getCoreEngine(),
+ SFC->getCallSiteBlock(), CallerLCtx);
return computeObjectUnderConstruction(
- cast<Expr>(SFC->getCallSite()), State, CallerLCtx,
+ cast<Expr>(SFC->getCallSite()), State, &CallerBldrCtx, CallerLCtx,
RTC->getConstructionContext(), CallOpts);
} else {
// We are on the top frame of the analysis. We do not know where is the
@@ -250,7 +262,7 @@ SVal ExprEngine::computeObjectUnderConstruction(
EvalCallOptions PreElideCallOpts = CallOpts;
SVal V = computeObjectUnderConstruction(
- TCC->getConstructorAfterElision(), State, LCtx,
+ TCC->getConstructorAfterElision(), State, BldrCtx, LCtx,
TCC->getConstructionContextAfterElision(), CallOpts);
// FIXME: This definition of "copy elision has not failed" is unreliable.
@@ -263,7 +275,7 @@ SVal ExprEngine::computeObjectUnderConstruction(
// a simple temporary.
CallOpts = PreElideCallOpts;
CallOpts.IsElidableCtorThatHasNotBeenElided = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case ConstructionContext::SimpleTemporaryObjectKind: {
const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
@@ -316,13 +328,13 @@ SVal ExprEngine::computeObjectUnderConstruction(
unsigned Idx = ACC->getIndex();
CallEventManager &CEMgr = getStateManager().getCallEventManager();
- auto getArgLoc = [&](CallEventRef<> Caller) -> Optional<SVal> {
+ auto getArgLoc = [&](CallEventRef<> Caller) -> std::optional<SVal> {
const LocationContext *FutureSFC =
- Caller->getCalleeStackFrame(currBldrCtx->blockCount());
+ Caller->getCalleeStackFrame(BldrCtx->blockCount());
// Return early if we are unable to reliably foresee
// the future stack frame.
if (!FutureSFC)
- return None;
+ return std::nullopt;
// This should be equivalent to Caller->getDecl() for now, but
// FutureSFC->getDecl() is likely to support better stuff (like
@@ -331,22 +343,22 @@ SVal ExprEngine::computeObjectUnderConstruction(
// FIXME: Support for variadic arguments is not implemented here yet.
if (CallEvent::isVariadic(CalleeD))
- return None;
+ return std::nullopt;
// Operator arguments do not correspond to operator parameters
// because this-argument is implemented as a normal argument in
// operator call expressions but not in operator declarations.
const TypedValueRegion *TVR = Caller->getParameterLocation(
- *Caller->getAdjustedParameterIndex(Idx), currBldrCtx->blockCount());
+ *Caller->getAdjustedParameterIndex(Idx), BldrCtx->blockCount());
if (!TVR)
- return None;
+ return std::nullopt;
return loc::MemRegionVal(TVR);
};
if (const auto *CE = dyn_cast<CallExpr>(E)) {
CallEventRef<> Caller = CEMgr.getSimpleCall(CE, State, LCtx);
- if (Optional<SVal> V = getArgLoc(Caller))
+ if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
break;
@@ -355,13 +367,13 @@ SVal ExprEngine::computeObjectUnderConstruction(
// constructor because we won't need it.
CallEventRef<> Caller =
CEMgr.getCXXConstructorCall(CCE, /*Target=*/nullptr, State, LCtx);
- if (Optional<SVal> V = getArgLoc(Caller))
+ if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
break;
} else if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
CallEventRef<> Caller = CEMgr.getObjCMethodCall(ME, State, LCtx);
- if (Optional<SVal> V = getArgLoc(Caller))
+ if (std::optional<SVal> V = getArgLoc(Caller))
return *V;
else
break;
@@ -455,7 +467,7 @@ ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
}
// If we decided not to elide the constructor, proceed as if
// it's a simple temporary.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case ConstructionContext::SimpleTemporaryObjectKind: {
const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
@@ -524,16 +536,32 @@ bindRequiredArrayElementToEnvironment(ProgramStateRef State,
// | `-DeclRefExpr
// `-ArrayInitIndexExpr
//
+ // The resulting expression for a multidimensional array.
+ // ArrayInitLoopExpr <-- we're here
+ // |-OpaqueValueExpr
+ // | `-DeclRefExpr <-- match this
+ // `-ArrayInitLoopExpr
+ // |-OpaqueValueExpr
+ // | `-ArraySubscriptExpr
+ // | |-ImplicitCastExpr
+ // | | `-OpaqueValueExpr
+ // | | `-DeclRefExpr
+ // | `-ArrayInitIndexExpr
+ // `-CXXConstructExpr <-- extract this
+ // ` ...
+
+ const auto *OVESrc = AILE->getCommonExpr()->getSourceExpr();
+
// HACK: There is no way we can put the index of the array element into the
// CFG unless we unroll the loop, so we manually select and bind the required
// parameter to the environment.
- const auto *CE = cast<CXXConstructExpr>(AILE->getSubExpr());
- const auto *OVESrc = AILE->getCommonExpr()->getSourceExpr();
+ const auto *CE =
+ cast<CXXConstructExpr>(extractElementInitializerFromNestedAILE(AILE));
SVal Base = UnknownVal();
if (const auto *ME = dyn_cast<MemberExpr>(OVESrc))
Base = State->getSVal(ME, LCtx);
- else if (const auto *DRE = cast<DeclRefExpr>(OVESrc))
+ else if (const auto *DRE = dyn_cast<DeclRefExpr>(OVESrc))
Base = State->getLValue(cast<VarDecl>(DRE->getDecl()), LCtx);
else
llvm_unreachable("ArrayInitLoopExpr contains unexpected source expression");
@@ -556,18 +584,18 @@ void ExprEngine::handleConstructor(const Expr *E,
SVal Target = UnknownVal();
if (CE) {
- if (Optional<SVal> ElidedTarget =
+ if (std::optional<SVal> ElidedTarget =
getObjectUnderConstruction(State, CE, LCtx)) {
- // We've previously modeled an elidable constructor by pretending that it
- // in fact constructs into the correct target. This constructor can
- // therefore be skipped.
- Target = *ElidedTarget;
- StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx);
- State = finishObjectConstruction(State, CE, LCtx);
- if (auto L = Target.getAs<Loc>())
- State = State->BindExpr(CE, LCtx, State->getSVal(*L, CE->getType()));
- Bldr.generateNode(CE, Pred, State);
- return;
+ // We've previously modeled an elidable constructor by pretending that
+ // it in fact constructs into the correct target. This constructor can
+ // therefore be skipped.
+ Target = *ElidedTarget;
+ StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx);
+ State = finishObjectConstruction(State, CE, LCtx);
+ if (auto L = Target.getAs<Loc>())
+ State = State->BindExpr(CE, LCtx, State->getSVal(*L, CE->getType()));
+ Bldr.generateNode(CE, Pred, State);
+ return;
}
}
@@ -589,6 +617,27 @@ void ExprEngine::handleConstructor(const Expr *E,
unsigned Idx = 0;
if (CE->getType()->isArrayType() || AILE) {
+
+ auto isZeroSizeArray = [&] {
+ uint64_t Size = 1;
+
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(CE->getType()))
+ Size = getContext().getConstantArrayElementCount(CAT);
+ else if (AILE)
+ Size = getContext().getArrayInitLoopExprElementCount(AILE);
+
+ return Size == 0;
+ };
+
+ // No element construction will happen in a 0 size array.
+ if (isZeroSizeArray()) {
+ StmtNodeBuilder Bldr(Pred, destNodes, *currBldrCtx);
+ static SimpleProgramPointTag T{"ExprEngine",
+ "Skipping 0 size array construction"};
+ Bldr.generateNode(CE, Pred, State, &T);
+ return;
+ }
+
Idx = getIndexOfElementToConstruct(State, CE, LCtx).value_or(0u);
State = setIndexOfElementToConstruct(State, CE, LCtx, Idx + 1);
}
@@ -596,16 +645,17 @@ void ExprEngine::handleConstructor(const Expr *E,
if (AILE) {
// Only set this once even though we loop through it multiple times.
if (!getPendingInitLoop(State, CE, LCtx))
- State = setPendingInitLoop(State, CE, LCtx,
- AILE->getArraySize().getLimitedValue());
+ State = setPendingInitLoop(
+ State, CE, LCtx,
+ getContext().getArrayInitLoopExprElementCount(AILE));
State = bindRequiredArrayElementToEnvironment(
State, AILE, LCtx, svalBuilder.makeArrayIndex(Idx));
}
// The target region is found from construction context.
- std::tie(State, Target) =
- handleConstructionContext(CE, State, LCtx, CC, CallOpts, Idx);
+ std::tie(State, Target) = handleConstructionContext(
+ CE, State, currBldrCtx, LCtx, CC, CallOpts, Idx);
break;
}
case CXXConstructExpr::CK_VirtualBase: {
@@ -620,7 +670,7 @@ void ExprEngine::handleConstructor(const Expr *E,
("This virtual base should have already been initialized by "
"the most derived class!"));
(void)OuterCtor;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case CXXConstructExpr::CK_NonVirtualBase:
// In C++17, classes with non-virtual bases may be aggregates, so they would
@@ -640,7 +690,7 @@ void ExprEngine::handleConstructor(const Expr *E,
CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CXXConstructExpr::CK_Delegating: {
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
@@ -905,6 +955,11 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
// skip it for now.
ProgramStateRef State = I->getState();
SVal RetVal = State->getSVal(CNE, LCtx);
+ // [basic.stc.dynamic.allocation] (on the return value of an allocation
+ // function):
+ // "The order, contiguity, and initial value of storage allocated by
+ // successive calls to an allocation function are unspecified."
+ State = State->bindDefaultInitial(RetVal, UndefinedVal{}, LCtx);
// If this allocation function is not declared as non-throwing, failures
// /must/ be signalled by exceptions, and thus the return value will never
@@ -1143,20 +1198,26 @@ void ExprEngine::VisitLambdaExpr(const LambdaExpr *LE, ExplodedNode *Pred,
SVal InitVal;
if (!FieldForCapture->hasCapturedVLAType()) {
- Expr *InitExpr = *i;
-
- if (const auto AILE = dyn_cast<ArrayInitLoopExpr>(InitExpr)) {
- // If the AILE initializes a POD array, we need to keep it as the
- // InitExpr.
- if (dyn_cast<CXXConstructExpr>(AILE->getSubExpr()))
- InitExpr = AILE->getSubExpr();
- }
+ const Expr *InitExpr = *i;
assert(InitExpr && "Capture missing initialization expression");
- if (dyn_cast<CXXConstructExpr>(InitExpr)) {
- InitVal = *getObjectUnderConstruction(State, {LE, Idx}, LocCtxt);
- InitVal = State->getSVal(InitVal.getAsRegion());
+ // Capturing a 0 length array is a no-op, so we ignore it to get a more
+ // accurate analysis. If it's not ignored, it would set the default
+ // binding of the lambda to 'Unknown', which can lead to falsely detecting
+ // 'Uninitialized' values as 'Unknown' and not reporting a warning.
+ const auto FTy = FieldForCapture->getType();
+ if (FTy->isConstantArrayType() &&
+ getContext().getConstantArrayElementCount(
+ getContext().getAsConstantArrayType(FTy)) == 0)
+ continue;
+
+ // With C++17 copy elision the InitExpr can be anything, so instead of
+ // pattern matching all cases, we simple check if the current field is
+ // under construction or not, regardless what it's InitExpr is.
+ if (const auto OUC =
+ getObjectUnderConstruction(State, {LE, Idx}, LocCtxt)) {
+ InitVal = State->getSVal(OUC->getAsRegion());
State = finishObjectConstruction(State, {LE, Idx}, LocCtxt);
} else
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 8fb2ce9cd18f..54528475cb31 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -25,6 +25,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/SaveAndRestore.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -85,10 +86,10 @@ static std::pair<const Stmt*,
const ProgramPoint &PP = Node->getLocation();
if (PP.getStackFrame() == SF) {
- if (Optional<StmtPoint> SP = PP.getAs<StmtPoint>()) {
+ if (std::optional<StmtPoint> SP = PP.getAs<StmtPoint>()) {
S = SP->getStmt();
break;
- } else if (Optional<CallExitEnd> CEE = PP.getAs<CallExitEnd>()) {
+ } else if (std::optional<CallExitEnd> CEE = PP.getAs<CallExitEnd>()) {
S = CEE->getCalleeContext()->getCallSite();
if (S)
break;
@@ -96,17 +97,17 @@ static std::pair<const Stmt*,
// If there is no statement, this is an implicitly-generated call.
// We'll walk backwards over it and then continue the loop to find
// an actual statement.
- Optional<CallEnter> CE;
+ std::optional<CallEnter> CE;
do {
Node = Node->getFirstPred();
CE = Node->getLocationAs<CallEnter>();
} while (!CE || CE->getCalleeContext() != CEE->getCalleeContext());
// Continue searching the graph.
- } else if (Optional<BlockEdge> BE = PP.getAs<BlockEdge>()) {
+ } else if (std::optional<BlockEdge> BE = PP.getAs<BlockEdge>()) {
Blk = BE->getSrc();
}
- } else if (Optional<CallEnter> CE = PP.getAs<CallEnter>()) {
+ } else if (std::optional<CallEnter> CE = PP.getAs<CallEnter>()) {
// If we reached the CallEnter for this function, it has no statements.
if (CE->getCalleeContext() == SF)
break;
@@ -195,6 +196,53 @@ static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl();
}
+// Returns the number of elements in the array currently being destructed.
+// If the element count is not found 0 will be returned.
+static unsigned getElementCountOfArrayBeingDestructed(
+ const CallEvent &Call, const ProgramStateRef State, SValBuilder &SVB) {
+ assert(isa<CXXDestructorCall>(Call) &&
+ "The call event is not a destructor call!");
+
+ const auto &DtorCall = cast<CXXDestructorCall>(Call);
+
+ auto ThisVal = DtorCall.getCXXThisVal();
+
+ if (auto ThisElementRegion = dyn_cast<ElementRegion>(ThisVal.getAsRegion())) {
+ auto ArrayRegion = ThisElementRegion->getAsArrayOffset().getRegion();
+ auto ElementType = ThisElementRegion->getElementType();
+
+ auto ElementCount =
+ getDynamicElementCount(State, ArrayRegion, SVB, ElementType);
+
+ if (!ElementCount.isConstant())
+ return 0;
+
+ return ElementCount.getAsInteger()->getLimitedValue();
+ }
+
+ return 0;
+}
+
+ProgramStateRef ExprEngine::removeStateTraitsUsedForArrayEvaluation(
+ ProgramStateRef State, const CXXConstructExpr *E,
+ const LocationContext *LCtx) {
+
+ assert(LCtx && "Location context must be provided!");
+
+ if (E) {
+ if (getPendingInitLoop(State, E, LCtx))
+ State = removePendingInitLoop(State, E, LCtx);
+
+ if (getIndexOfElementToConstruct(State, E, LCtx))
+ State = removeIndexOfElementToConstruct(State, E, LCtx);
+ }
+
+ if (getPendingArrayDestruction(State, LCtx))
+ State = removePendingArrayDestruction(State, LCtx);
+
+ return State;
+}
+
/// The call exit is simulated with a sequence of nodes, which occur between
/// CallExitBegin and CallExitEnd. The following operations occur between the
/// two program points:
@@ -234,6 +282,16 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// but we want to evaluate it as many times as many elements the array has.
bool ShouldRepeatCall = false;
+ if (const auto *DtorDecl =
+ dyn_cast_or_null<CXXDestructorDecl>(Call->getDecl())) {
+ if (auto Idx = getPendingArrayDestruction(state, callerCtx)) {
+ ShouldRepeatCall = *Idx > 0;
+
+ auto ThisVal = svalBuilder.getCXXThis(DtorDecl->getParent(), calleeCtx);
+ state = state->killBinding(ThisVal);
+ }
+ }
+
// If the callee returns an expression, bind its value to CallExpr.
if (CE) {
if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
@@ -264,14 +322,6 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
state = state->BindExpr(CCE, callerCtx, ThisV);
ShouldRepeatCall = shouldRepeatCtorCall(state, CCE, callerCtx);
-
- if (!ShouldRepeatCall) {
- if (getIndexOfElementToConstruct(state, CCE, callerCtx))
- state = removeIndexOfElementToConstruct(state, CCE, callerCtx);
-
- if (getPendingInitLoop(state, CCE, callerCtx))
- state = removePendingInitLoop(state, CCE, callerCtx);
- }
}
if (const auto *CNE = dyn_cast<CXXNewExpr>(CE)) {
@@ -290,6 +340,11 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
}
}
+ if (!ShouldRepeatCall) {
+ state = removeStateTraitsUsedForArrayEvaluation(
+ state, dyn_cast_or_null<CXXConstructExpr>(CE), callerCtx);
+ }
+
// Step 3: BindedRetNode -> CleanedNodes
// If we can find a statement and a block in the inlined function, run remove
// dead bindings before returning from the call. This is important to ensure
@@ -337,9 +392,8 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
// result onto the work list.
// CEENode -> Dst -> WorkList
NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode);
- SaveAndRestore<const NodeBuilderContext*> NBCSave(currBldrCtx,
- &Ctx);
- SaveAndRestore<unsigned> CBISave(currStmtIdx, calleeCtx->getIndex());
+ SaveAndRestore<const NodeBuilderContext *> NBCSave(currBldrCtx, &Ctx);
+ SaveAndRestore CBISave(currStmtIdx, calleeCtx->getIndex());
CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState);
@@ -586,8 +640,7 @@ ProgramStateRef ExprEngine::finishArgumentConstruction(ProgramStateRef State,
const LocationContext *LC = Call.getLocationContext();
for (unsigned CallI = 0, CallN = Call.getNumArgs(); CallI != CallN; ++CallI) {
unsigned I = Call.getASTArgumentIndex(CallI);
- if (Optional<SVal> V =
- getObjectUnderConstruction(State, {E, I}, LC)) {
+ if (std::optional<SVal> V = getObjectUnderConstruction(State, {E, I}, LC)) {
SVal VV = *V;
(void)VV;
assert(cast<VarRegion>(VV.castAs<loc::MemRegionVal>().getRegion())
@@ -720,9 +773,9 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
SVal Target;
assert(RTC->getStmt() == Call.getOriginExpr());
EvalCallOptions CallOpts; // FIXME: We won't really need those.
- std::tie(State, Target) =
- handleConstructionContext(Call.getOriginExpr(), State, LCtx,
- RTC->getConstructionContext(), CallOpts);
+ std::tie(State, Target) = handleConstructionContext(
+ Call.getOriginExpr(), State, currBldrCtx, LCtx,
+ RTC->getConstructionContext(), CallOpts);
const MemRegion *TargetR = Target.getAsRegion();
assert(TargetR);
// Invalidate the region so that it didn't look uninitialized. If this is
@@ -762,6 +815,11 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
svalBuilder.evalBinOp(State, BO_Mul, ElementCount, ElementSize,
svalBuilder.getArrayIndexType());
+ // FIXME: This line is to prevent a crash. For more details please check
+ // issue #56264.
+ if (Size.isUndef())
+ Size = UnknownVal();
+
State = setDynamicExtent(State, MR, Size.castAs<DefinedOrUnknownSVal>(),
svalBuilder);
} else {
@@ -813,11 +871,6 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
!Opts.MayInlineCXXAllocator)
return CIP_DisallowedOnce;
- // FIXME: We don't handle constructors or destructors for arrays properly.
- // Even once we do, we still need to be careful about implicitly-generated
- // initializers for array fields in default move/copy constructors.
- // We still allow construction into ElementRegion targets when they don't
- // represent array elements.
if (CallOpts.IsArrayCtorOrDtor) {
if (!shouldInlineArrayConstruction(Pred->getState(), CtorExpr, CurLC))
return CIP_DisallowedOnce;
@@ -872,9 +925,12 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
(void)ADC;
- // FIXME: We don't handle destructors for arrays properly.
- if (CallOpts.IsArrayCtorOrDtor)
- return CIP_DisallowedOnce;
+ if (CallOpts.IsArrayCtorOrDtor) {
+ if (!shouldInlineArrayDestruction(getElementCountOfArrayBeingDestructed(
+ Call, Pred->getState(), svalBuilder))) {
+ return CIP_DisallowedOnce;
+ }
+ }
// Allow disabling temporary destructor inlining with a separate option.
if (CallOpts.IsTemporaryCtorOrDtor &&
@@ -889,7 +945,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
break;
}
case CE_CXXDeallocator:
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case CE_CXXAllocator:
if (Opts.MayInlineCXXAllocator)
break;
@@ -1034,9 +1090,9 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
return false;
// Check if this function has been marked as non-inlinable.
- Optional<bool> MayInline = Engine.FunctionSummaries->mayInline(D);
+ std::optional<bool> MayInline = Engine.FunctionSummaries->mayInline(D);
if (MayInline) {
- if (!MayInline.value())
+ if (!*MayInline)
return false;
} else {
@@ -1091,22 +1147,36 @@ bool ExprEngine::shouldInlineArrayConstruction(const ProgramStateRef State,
if (!CE)
return false;
- auto Type = CE->getType();
-
// FIXME: Handle other arrays types.
- if (const auto *CAT = dyn_cast<ConstantArrayType>(Type)) {
- unsigned Size = getContext().getConstantArrayElementCount(CAT);
-
- return Size <= AMgr.options.maxBlockVisitOnPath;
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(CE->getType())) {
+ unsigned ArrSize = getContext().getConstantArrayElementCount(CAT);
+
+ // This might seem conter-intuitive at first glance, but the functions are
+ // closely related. Reasoning about destructors depends only on the type
+ // of the expression that initialized the memory region, which is the
+ // CXXConstructExpr. So to avoid code repetition, the work is delegated
+ // to the function that reasons about destructor inlining. Also note that
+ // if the constructors of the array elements are inlined, the destructors
+ // can also be inlined and if the destructors can be inline, it's safe to
+ // inline the constructors.
+ return shouldInlineArrayDestruction(ArrSize);
}
// Check if we're inside an ArrayInitLoopExpr, and it's sufficiently small.
if (auto Size = getPendingInitLoop(State, CE, LCtx))
- return *Size <= AMgr.options.maxBlockVisitOnPath;
+ return shouldInlineArrayDestruction(*Size);
return false;
}
+bool ExprEngine::shouldInlineArrayDestruction(uint64_t Size) {
+
+ uint64_t maxAllowedSize = AMgr.options.maxBlockVisitOnPath;
+
+ // Declaring a 0 element array is also possible.
+ return Size <= maxAllowedSize && Size > 0;
+}
+
bool ExprEngine::shouldRepeatCtorCall(ProgramStateRef State,
const CXXConstructExpr *E,
const LocationContext *LCtx) {
@@ -1189,7 +1259,12 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
}
}
- // If we can't inline it, handle the return value and invalidate the regions.
+ // If we can't inline it, clean up the state traits used only if the function
+ // is inlined.
+ State = removeStateTraitsUsedForArrayEvaluation(
+ State, dyn_cast_or_null<CXXConstructExpr>(E), Call->getLocationContext());
+
+ // Also handle the return value and invalidate the regions.
conservativeEvalCall(*Call, Bldr, Pred, State);
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 5a55e81497b0..25c36e9aea24 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -206,7 +206,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNodeSet dstPostCheckers;
getCheckerManager().runCheckersForObjCMessageNil(dstPostCheckers, Pred,
*Msg, *this);
- for (auto I : dstPostCheckers)
+ for (auto *I : dstPostCheckers)
finishArgumentConstruction(Dst, I, *Msg);
return;
}
@@ -270,7 +270,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
// If there were constructors called for object-type arguments, clean them up.
ExplodedNodeSet dstArgCleanup;
- for (auto I : dstEval)
+ for (auto *I : dstEval)
finishArgumentConstruction(dstArgCleanup, I, *Msg);
ExplodedNodeSet dstPostvisit;
diff --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
index 506d61d94d5f..a80352816be6 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -24,6 +25,7 @@ using namespace clang::ast_matchers;
static const int MAXIMUM_STEP_UNROLLED = 128;
+namespace {
struct LoopState {
private:
enum Kind { Normal, Unrolled } K;
@@ -56,6 +58,7 @@ public:
ID.AddInteger(maxStep);
}
};
+} // namespace
// The tracked stack of loops. The stack indicates that which loops the
// simulated element contained by. The loops are marked depending if we decided
@@ -175,7 +178,7 @@ static bool isCapturedByReference(ExplodedNode *N, const DeclRefExpr *DR) {
const CXXRecordDecl *LambdaCXXRec = MD->getParent();
// Lookup the fields of the lambda
- llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
FieldDecl *LambdaThisCaptureField;
LambdaCXXRec->getCaptureFields(LambdaCaptureFields, LambdaThisCaptureField);
@@ -284,7 +287,7 @@ bool madeNewBranch(ExplodedNode *N, const Stmt *LoopStmt) {
return true;
ProgramPoint P = N->getLocation();
- if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>())
+ if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>())
S = BE->getBlock()->getTerminatorStmt();
if (S == LoopStmt)
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 81c11099e93f..0c126a632f74 100644
--- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -35,7 +35,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
@@ -51,6 +50,7 @@
#include <cstdint>
#include <functional>
#include <iterator>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -790,18 +790,30 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
return true;
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+ const FAMKind StrictFlexArraysLevel =
+ Ctx.getLangOpts().getStrictFlexArraysLevel();
+ const AnalyzerOptions &Opts = SVB.getAnalyzerOptions();
const llvm::APInt &Size = CAT->getSize();
- if (Size.isZero())
- return true;
-
- if (getContext().getLangOpts().StrictFlexArrays >= 2)
- return false;
- const AnalyzerOptions &Opts = SVB.getAnalyzerOptions();
- // FIXME: this option is probably redundant with -fstrict-flex-arrays=1.
- if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers &&
- Size.isOne())
+ if (StrictFlexArraysLevel <= FAMKind::ZeroOrIncomplete && Size.isZero())
return true;
+
+ // The "-fstrict-flex-arrays" should have precedence over
+ // consider-single-element-arrays-as-flexible-array-members
+ // analyzer-config when checking single element arrays.
+ if (StrictFlexArraysLevel == FAMKind::Default) {
+ // FIXME: After clang-17 released, we should remove this branch.
+ if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers &&
+ Size.isOne())
+ return true;
+ } else {
+ // -fstrict-flex-arrays was specified, since it's not the default, so
+ // ignore analyzer-config.
+ if (StrictFlexArraysLevel <= FAMKind::OneZeroOrIncomplete &&
+ Size.isOne())
+ return true;
+ }
}
return false;
};
@@ -1029,7 +1041,7 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
T = getContext().VoidTy;
if (!T->getAs<FunctionType>()) {
FunctionProtoType::ExtProtoInfo Ext;
- T = getContext().getFunctionType(T, None, Ext);
+ T = getContext().getFunctionType(T, std::nullopt, Ext);
}
T = getContext().getBlockPointerType(T);
@@ -1076,14 +1088,18 @@ MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind);
}
else {
- if (LC) {
+ bool IsArcManagedBlock = Ctx.getLangOpts().ObjCAutoRefCount;
+
+ // ARC managed blocks can be initialized on stack or directly in heap
+ // depending on the implementations. So we initialize them with
+ // UnknownRegion.
+ if (!IsArcManagedBlock && LC) {
// FIXME: Once we implement scope handling, we want the parent region
// to be the scope.
const StackFrameContext *STC = LC->getStackFrame();
assert(STC);
sReg = getStackLocalsRegion(STC);
- }
- else {
+ } else {
// We allow 'LC' to be NULL for cases where want BlockDataRegions
// without context-sensitivity.
sReg = getUnknownRegion();
@@ -1286,8 +1302,8 @@ bool MemRegion::hasGlobalsOrParametersStorage() const {
return isa<StackArgumentsSpaceRegion, GlobalsSpaceRegion>(getMemorySpace());
}
-// getBaseRegion strips away all elements and fields, and get the base region
-// of them.
+// Strips away all elements and fields.
+// Returns the base region of them.
const MemRegion *MemRegion::getBaseRegion() const {
const MemRegion *R = this;
while (true) {
@@ -1307,8 +1323,7 @@ const MemRegion *MemRegion::getBaseRegion() const {
return R;
}
-// getgetMostDerivedObjectRegion gets the region of the root class of a C++
-// class hierarchy.
+// Returns the region of the root class of a C++ class hierarchy.
const MemRegion *MemRegion::getMostDerivedObjectRegion() const {
const MemRegion *R = this;
while (const auto *BR = dyn_cast<CXXBaseObjectRegion>(R))
@@ -1482,7 +1497,7 @@ static RegionOffset calculateOffset(const MemRegion *R) {
// If our base region is symbolic, we don't know what type it really is.
// Pretend the type of the symbol is the true dynamic type.
// (This will at least be self-consistent for the life of the symbol.)
- Ty = SR->getSymbol()->getType()->getPointeeType();
+ Ty = SR->getPointeeStaticType();
RootIsSymbolic = true;
}
@@ -1539,7 +1554,7 @@ static RegionOffset calculateOffset(const MemRegion *R) {
}
SVal Index = ER->getIndex();
- if (Optional<nonloc::ConcreteInt> CI =
+ if (std::optional<nonloc::ConcreteInt> CI =
Index.getAs<nonloc::ConcreteInt>()) {
// Don't bother calculating precise offsets if we already have a
// symbolic offset somewhere in the chain.
diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index d35646bfba91..a3b08d4581a5 100644
--- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -28,6 +28,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
#include <memory>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -165,7 +166,7 @@ static void printCoverage(const PathDiagnostic *D,
FIDMap &FM,
llvm::raw_fd_ostream &o);
-static Optional<StringRef> getExpandedMacro(
+static std::optional<StringRef> getExpandedMacro(
SourceLocation MacroLoc, const cross_tu::CrossTranslationUnitContext &CTU,
const MacroExpansionContext &MacroExpansions, const SourceManager &SM);
@@ -384,9 +385,9 @@ void PlistPrinter::ReportMacroExpansions(raw_ostream &o, unsigned indent) {
SourceLocation MacroExpansionLoc =
P->getLocation().asLocation().getExpansionLoc();
- const Optional<StringRef> MacroName =
+ const std::optional<StringRef> MacroName =
MacroExpansions.getOriginalText(MacroExpansionLoc);
- const Optional<StringRef> ExpansionText =
+ const std::optional<StringRef> ExpansionText =
getExpandedMacro(MacroExpansionLoc, CTU, MacroExpansions, SM);
if (!MacroName || !ExpansionText)
@@ -407,11 +408,11 @@ void PlistPrinter::ReportMacroExpansions(raw_ostream &o, unsigned indent) {
// Output the macro name.
Indent(o, indent) << "<key>name</key>";
- EmitString(o, MacroName.value()) << '\n';
+ EmitString(o, *MacroName) << '\n';
// Output what it expands into.
Indent(o, indent) << "<key>expansion</key>";
- EmitString(o, ExpansionText.value()) << '\n';
+ EmitString(o, *ExpansionText) << '\n';
// Finish up.
--indent;
@@ -825,7 +826,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Definitions of helper functions and methods for expanding macros.
//===----------------------------------------------------------------------===//
-static Optional<StringRef>
+static std::optional<StringRef>
getExpandedMacro(SourceLocation MacroExpansionLoc,
const cross_tu::CrossTranslationUnitContext &CTU,
const MacroExpansionContext &MacroExpansions,
diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index a6d0e242924b..90ebbaad2bf3 100644
--- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -216,8 +217,6 @@ ProgramState::invalidateRegionsImpl(ValueList Values,
}
ProgramStateRef ProgramState::killBinding(Loc LV) const {
- assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead.");
-
Store OldStore = getStore();
const StoreRef &newStore =
getStateManager().StoreMgr->killBinding(OldStore, LV);
@@ -314,7 +313,7 @@ ProgramStateRef ProgramState::BindExpr(const Stmt *S,
return getStateManager().getPersistentState(NewSt);
}
-LLVM_NODISCARD std::pair<ProgramStateRef, ProgramStateRef>
+[[nodiscard]] std::pair<ProgramStateRef, ProgramStateRef>
ProgramState::assumeInBoundDual(DefinedOrUnknownSVal Idx,
DefinedOrUnknownSVal UpperBound,
QualType indexTy) const {
@@ -580,20 +579,20 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
}
bool ScanReachableSymbols::scan(SVal val) {
- if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>())
+ if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>())
return scan(X->getRegion());
- if (Optional<nonloc::LazyCompoundVal> X =
+ if (std::optional<nonloc::LazyCompoundVal> X =
val.getAs<nonloc::LazyCompoundVal>())
return scan(*X);
- if (Optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())
+ if (std::optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())
return scan(X->getLoc());
if (SymbolRef Sym = val.getAsSymbol())
return scan(Sym);
- if (Optional<nonloc::CompoundVal> X = val.getAs<nonloc::CompoundVal>())
+ if (std::optional<nonloc::CompoundVal> X = val.getAs<nonloc::CompoundVal>())
return scan(*X);
return true;
diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 2d4dfae1e750..1017dff2b0f3 100644
--- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <iterator>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -913,20 +914,20 @@ namespace {
class EquivalenceClass : public llvm::FoldingSetNode {
public:
/// Find equivalence class for the given symbol in the given state.
- LLVM_NODISCARD static inline EquivalenceClass find(ProgramStateRef State,
- SymbolRef Sym);
+ [[nodiscard]] static inline EquivalenceClass find(ProgramStateRef State,
+ SymbolRef Sym);
/// Merge classes for the given symbols and return a new state.
- LLVM_NODISCARD static inline ProgramStateRef merge(RangeSet::Factory &F,
- ProgramStateRef State,
- SymbolRef First,
- SymbolRef Second);
+ [[nodiscard]] static inline ProgramStateRef merge(RangeSet::Factory &F,
+ ProgramStateRef State,
+ SymbolRef First,
+ SymbolRef Second);
// Merge this class with the given class and return a new state.
- LLVM_NODISCARD inline ProgramStateRef
+ [[nodiscard]] inline ProgramStateRef
merge(RangeSet::Factory &F, ProgramStateRef State, EquivalenceClass Other);
/// Return a set of class members for the given state.
- LLVM_NODISCARD inline SymbolSet getClassMembers(ProgramStateRef State) const;
+ [[nodiscard]] inline SymbolSet getClassMembers(ProgramStateRef State) const;
/// Return true if the current class is trivial in the given state.
/// A class is trivial if and only if there is not any member relations stored
@@ -939,43 +940,42 @@ public:
/// members and then during the removal of dead symbols we remove one of its
/// members. In this case, the class is still non-trivial (it still has the
/// mappings in ClassMembers), even though it has only one member.
- LLVM_NODISCARD inline bool isTrivial(ProgramStateRef State) const;
+ [[nodiscard]] inline bool isTrivial(ProgramStateRef State) const;
/// Return true if the current class is trivial and its only member is dead.
- LLVM_NODISCARD inline bool isTriviallyDead(ProgramStateRef State,
- SymbolReaper &Reaper) const;
+ [[nodiscard]] inline bool isTriviallyDead(ProgramStateRef State,
+ SymbolReaper &Reaper) const;
- LLVM_NODISCARD static inline ProgramStateRef
+ [[nodiscard]] static inline ProgramStateRef
markDisequal(RangeSet::Factory &F, ProgramStateRef State, SymbolRef First,
SymbolRef Second);
- LLVM_NODISCARD static inline ProgramStateRef
+ [[nodiscard]] static inline ProgramStateRef
markDisequal(RangeSet::Factory &F, ProgramStateRef State,
EquivalenceClass First, EquivalenceClass Second);
- LLVM_NODISCARD inline ProgramStateRef
+ [[nodiscard]] inline ProgramStateRef
markDisequal(RangeSet::Factory &F, ProgramStateRef State,
EquivalenceClass Other) const;
- LLVM_NODISCARD static inline ClassSet
- getDisequalClasses(ProgramStateRef State, SymbolRef Sym);
- LLVM_NODISCARD inline ClassSet
- getDisequalClasses(ProgramStateRef State) const;
- LLVM_NODISCARD inline ClassSet
+ [[nodiscard]] static inline ClassSet getDisequalClasses(ProgramStateRef State,
+ SymbolRef Sym);
+ [[nodiscard]] inline ClassSet getDisequalClasses(ProgramStateRef State) const;
+ [[nodiscard]] inline ClassSet
getDisequalClasses(DisequalityMapTy Map, ClassSet::Factory &Factory) const;
- LLVM_NODISCARD static inline Optional<bool> areEqual(ProgramStateRef State,
- EquivalenceClass First,
- EquivalenceClass Second);
- LLVM_NODISCARD static inline Optional<bool>
+ [[nodiscard]] static inline std::optional<bool>
+ areEqual(ProgramStateRef State, EquivalenceClass First,
+ EquivalenceClass Second);
+ [[nodiscard]] static inline std::optional<bool>
areEqual(ProgramStateRef State, SymbolRef First, SymbolRef Second);
/// Remove one member from the class.
- LLVM_NODISCARD ProgramStateRef removeMember(ProgramStateRef State,
- const SymbolRef Old);
+ [[nodiscard]] ProgramStateRef removeMember(ProgramStateRef State,
+ const SymbolRef Old);
/// Iterate over all symbols and try to simplify them.
- LLVM_NODISCARD static inline ProgramStateRef simplify(SValBuilder &SVB,
- RangeSet::Factory &F,
- ProgramStateRef State,
- EquivalenceClass Class);
+ [[nodiscard]] static inline ProgramStateRef simplify(SValBuilder &SVB,
+ RangeSet::Factory &F,
+ ProgramStateRef State,
+ EquivalenceClass Class);
void dumpToStream(ProgramStateRef State, raw_ostream &os) const;
LLVM_DUMP_METHOD void dump(ProgramStateRef State) const {
@@ -983,10 +983,10 @@ public:
}
/// Check equivalence data for consistency.
- LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED static bool
+ [[nodiscard]] LLVM_ATTRIBUTE_UNUSED static bool
isClassDataConsistent(ProgramStateRef State);
- LLVM_NODISCARD QualType getType() const {
+ [[nodiscard]] QualType getType() const {
return getRepresentativeSymbol()->getType();
}
@@ -1041,7 +1041,7 @@ private:
// Constraint functions
//===----------------------------------------------------------------------===//
-LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED bool
+[[nodiscard]] LLVM_ATTRIBUTE_UNUSED bool
areFeasible(ConstraintRangeTy Constraints) {
return llvm::none_of(
Constraints,
@@ -1050,24 +1050,24 @@ areFeasible(ConstraintRangeTy Constraints) {
});
}
-LLVM_NODISCARD inline const RangeSet *getConstraint(ProgramStateRef State,
- EquivalenceClass Class) {
+[[nodiscard]] inline const RangeSet *getConstraint(ProgramStateRef State,
+ EquivalenceClass Class) {
return State->get<ConstraintRange>(Class);
}
-LLVM_NODISCARD inline const RangeSet *getConstraint(ProgramStateRef State,
- SymbolRef Sym) {
+[[nodiscard]] inline const RangeSet *getConstraint(ProgramStateRef State,
+ SymbolRef Sym) {
return getConstraint(State, EquivalenceClass::find(State, Sym));
}
-LLVM_NODISCARD ProgramStateRef setConstraint(ProgramStateRef State,
- EquivalenceClass Class,
- RangeSet Constraint) {
+[[nodiscard]] ProgramStateRef setConstraint(ProgramStateRef State,
+ EquivalenceClass Class,
+ RangeSet Constraint) {
return State->set<ConstraintRange>(Class, Constraint);
}
-LLVM_NODISCARD ProgramStateRef setConstraints(ProgramStateRef State,
- ConstraintRangeTy Constraints) {
+[[nodiscard]] ProgramStateRef setConstraints(ProgramStateRef State,
+ ConstraintRangeTy Constraints) {
return State->set<ConstraintRange>(Constraints);
}
@@ -1084,7 +1084,7 @@ LLVM_NODISCARD ProgramStateRef setConstraints(ProgramStateRef State,
/// \returns true if assuming this Sym to be true means equality of operands
/// false if it means disequality of operands
/// None otherwise
-Optional<bool> meansEquality(const SymSymExpr *Sym) {
+std::optional<bool> meansEquality(const SymSymExpr *Sym) {
switch (Sym->getOpcode()) {
case BO_Sub:
// This case is: A - B != 0 -> disequality check.
@@ -1096,7 +1096,7 @@ Optional<bool> meansEquality(const SymSymExpr *Sym) {
// This case is: A != B != 0 -> diseqiality check.
return false;
default:
- return llvm::None;
+ return std::nullopt;
}
}
@@ -1105,8 +1105,8 @@ Optional<bool> meansEquality(const SymSymExpr *Sym) {
//===----------------------------------------------------------------------===//
template <class SecondTy, class... RestTy>
-LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head,
- SecondTy Second, RestTy... Tail);
+[[nodiscard]] inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head,
+ SecondTy Second, RestTy... Tail);
template <class... RangeTy> struct IntersectionTraits;
@@ -1118,7 +1118,7 @@ template <class... TailTy> struct IntersectionTraits<RangeSet, TailTy...> {
template <> struct IntersectionTraits<> {
// We ran out of types, and we didn't find any RangeSet, so the result should
// be optional.
- using Type = Optional<RangeSet>;
+ using Type = std::optional<RangeSet>;
};
template <class OptionalOrPointer, class... TailTy>
@@ -1128,32 +1128,33 @@ struct IntersectionTraits<OptionalOrPointer, TailTy...> {
};
template <class EndTy>
-LLVM_NODISCARD inline EndTy intersect(RangeSet::Factory &F, EndTy End) {
- // If the list contains only RangeSet or Optional<RangeSet>, simply return
- // that range set.
+[[nodiscard]] inline EndTy intersect(RangeSet::Factory &F, EndTy End) {
+ // If the list contains only RangeSet or std::optional<RangeSet>, simply
+ // return that range set.
return End;
}
-LLVM_NODISCARD LLVM_ATTRIBUTE_UNUSED inline Optional<RangeSet>
+[[nodiscard]] LLVM_ATTRIBUTE_UNUSED inline std::optional<RangeSet>
intersect(RangeSet::Factory &F, const RangeSet *End) {
- // This is an extraneous conversion from a raw pointer into Optional<RangeSet>
+ // This is an extraneous conversion from a raw pointer into
+ // std::optional<RangeSet>
if (End) {
return *End;
}
- return llvm::None;
+ return std::nullopt;
}
template <class... RestTy>
-LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head,
- RangeSet Second, RestTy... Tail) {
+[[nodiscard]] inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head,
+ RangeSet Second, RestTy... Tail) {
// Here we call either the <RangeSet,RangeSet,...> or <RangeSet,...> version
// of the function and can be sure that the result is RangeSet.
return intersect(F, F.intersect(Head, Second), Tail...);
}
template <class SecondTy, class... RestTy>
-LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head,
- SecondTy Second, RestTy... Tail) {
+[[nodiscard]] inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head,
+ SecondTy Second, RestTy... Tail) {
if (Second) {
// Here we call the <RangeSet,RangeSet,...> version of the function...
return intersect(F, Head, *Second, Tail...);
@@ -1165,11 +1166,12 @@ LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head,
/// Main generic intersect function.
/// It intersects all of the given range sets. If some of the given arguments
-/// don't hold a range set (nullptr or llvm::None), the function will skip them.
+/// don't hold a range set (nullptr or std::nullopt), the function will skip
+/// them.
///
/// Available representations for the arguments are:
/// * RangeSet
-/// * Optional<RangeSet>
+/// * std::optional<RangeSet>
/// * RangeSet *
/// Pointer to a RangeSet is automatically assumed to be nullable and will get
/// checked as well as the optional version. If this behaviour is undesired,
@@ -1177,13 +1179,14 @@ LLVM_NODISCARD inline RangeSet intersect(RangeSet::Factory &F, RangeSet Head,
///
/// Return type depends on the arguments' types. If we can be sure in compile
/// time that there will be a range set as a result, the returning type is
-/// simply RangeSet, in other cases we have to back off to Optional<RangeSet>.
+/// simply RangeSet, in other cases we have to back off to
+/// std::optional<RangeSet>.
///
/// Please, prefer optional range sets to raw pointers. If the last argument is
-/// a raw pointer and all previous arguments are None, it will cost one
-/// additional check to convert RangeSet * into Optional<RangeSet>.
+/// a raw pointer and all previous arguments are std::nullopt, it will cost one
+/// additional check to convert RangeSet * into std::optional<RangeSet>.
template <class HeadTy, class SecondTy, class... RestTy>
-LLVM_NODISCARD inline
+[[nodiscard]] inline
typename IntersectionTraits<HeadTy, SecondTy, RestTy...>::Type
intersect(RangeSet::Factory &F, HeadTy Head, SecondTy Second,
RestTy... Tail) {
@@ -1213,7 +1216,7 @@ public:
}
RangeSet VisitSymExpr(SymbolRef Sym) {
- if (Optional<RangeSet> RS = getRangeForNegatedSym(Sym))
+ if (std::optional<RangeSet> RS = getRangeForNegatedSym(Sym))
return *RS;
// If we've reached this line, the actual type of the symbolic
// expression is not supported for advanced inference.
@@ -1223,7 +1226,7 @@ public:
}
RangeSet VisitUnarySymExpr(const UnarySymExpr *USE) {
- if (Optional<RangeSet> RS = getRangeForNegatedUnarySym(USE))
+ if (std::optional<RangeSet> RS = getRangeForNegatedUnarySym(USE))
return *RS;
return infer(USE->getType());
}
@@ -1333,18 +1336,7 @@ private:
}
RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
- RangeSet RHS, QualType T) {
- switch (Op) {
- case BO_Or:
- return VisitBinaryOperator<BO_Or>(LHS, RHS, T);
- case BO_And:
- return VisitBinaryOperator<BO_And>(LHS, RHS, T);
- case BO_Rem:
- return VisitBinaryOperator<BO_Rem>(LHS, RHS, T);
- default:
- return infer(T);
- }
- }
+ RangeSet RHS, QualType T);
//===----------------------------------------------------------------------===//
// Ranges and operators
@@ -1362,11 +1354,11 @@ private:
/// Try to convert given range into the given type.
///
- /// It will return llvm::None only when the trivial conversion is possible.
- llvm::Optional<Range> convert(const Range &Origin, APSIntType To) {
+ /// It will return std::nullopt only when the trivial conversion is possible.
+ std::optional<Range> convert(const Range &Origin, APSIntType To) {
if (To.testInRange(Origin.From(), false) != APSIntType::RTR_Within ||
To.testInRange(Origin.To(), false) != APSIntType::RTR_Within) {
- return llvm::None;
+ return std::nullopt;
}
return Range(ValueFactory.Convert(To, Origin.From()),
ValueFactory.Convert(To, Origin.To()));
@@ -1374,11 +1366,7 @@ private:
template <BinaryOperator::Opcode Op>
RangeSet VisitBinaryOperator(RangeSet LHS, RangeSet RHS, QualType T) {
- // We should propagate information about unfeasbility of one of the
- // operands to the resulting range.
- if (LHS.isEmpty() || RHS.isEmpty()) {
- return RangeFactory.getEmptySet();
- }
+ assert(!LHS.isEmpty() && !RHS.isEmpty());
Range CoarseLHS = fillGaps(LHS);
Range CoarseRHS = fillGaps(RHS);
@@ -1451,21 +1439,21 @@ private:
}
template <typename ProduceNegatedSymFunc>
- Optional<RangeSet> getRangeForNegatedExpr(ProduceNegatedSymFunc F,
- QualType T) {
+ std::optional<RangeSet> getRangeForNegatedExpr(ProduceNegatedSymFunc F,
+ QualType T) {
// Do not negate if the type cannot be meaningfully negated.
if (!T->isUnsignedIntegerOrEnumerationType() &&
!T->isSignedIntegerOrEnumerationType())
- return llvm::None;
+ return std::nullopt;
if (SymbolRef NegatedSym = F())
if (const RangeSet *NegatedRange = getConstraint(State, NegatedSym))
return RangeFactory.negate(*NegatedRange);
- return llvm::None;
+ return std::nullopt;
}
- Optional<RangeSet> getRangeForNegatedUnarySym(const UnarySymExpr *USE) {
+ std::optional<RangeSet> getRangeForNegatedUnarySym(const UnarySymExpr *USE) {
// Just get the operand when we negate a symbol that is already negated.
// -(-a) == a
return getRangeForNegatedExpr(
@@ -1477,7 +1465,7 @@ private:
USE->getType());
}
- Optional<RangeSet> getRangeForNegatedSymSym(const SymSymExpr *SSE) {
+ std::optional<RangeSet> getRangeForNegatedSymSym(const SymSymExpr *SSE) {
return getRangeForNegatedExpr(
[SSE, State = this->State]() -> SymbolRef {
if (SSE->getOpcode() == BO_Sub)
@@ -1488,7 +1476,7 @@ private:
SSE->getType());
}
- Optional<RangeSet> getRangeForNegatedSym(SymbolRef Sym) {
+ std::optional<RangeSet> getRangeForNegatedSym(SymbolRef Sym) {
return getRangeForNegatedExpr(
[Sym, State = this->State]() {
return State->getSymbolManager().getUnarySymExpr(Sym, UO_Minus,
@@ -1507,12 +1495,12 @@ private:
// It covers all possible combinations (see CmpOpTable description).
// Note that `x` and `y` can also stand for subexpressions,
// not only for actual symbols.
- Optional<RangeSet> getRangeForComparisonSymbol(const SymSymExpr *SSE) {
+ std::optional<RangeSet> getRangeForComparisonSymbol(const SymSymExpr *SSE) {
const BinaryOperatorKind CurrentOP = SSE->getOpcode();
// We currently do not support <=> (C++20).
if (!BinaryOperator::isComparisonOp(CurrentOP) || (CurrentOP == BO_Cmp))
- return llvm::None;
+ return std::nullopt;
static const OperatorRelationsTable CmpOpTable{};
@@ -1582,16 +1570,16 @@ private:
: getFalseRange(T);
}
- return llvm::None;
+ return std::nullopt;
}
- Optional<RangeSet> getRangeForEqualities(const SymSymExpr *Sym) {
- Optional<bool> Equality = meansEquality(Sym);
+ std::optional<RangeSet> getRangeForEqualities(const SymSymExpr *Sym) {
+ std::optional<bool> Equality = meansEquality(Sym);
if (!Equality)
- return llvm::None;
+ return std::nullopt;
- if (Optional<bool> AreEqual =
+ if (std::optional<bool> AreEqual =
EquivalenceClass::areEqual(State, Sym->getLHS(), Sym->getRHS())) {
// Here we cover two cases at once:
// * if Sym is equality and its operands are known to be equal -> true
@@ -1603,7 +1591,7 @@ private:
return getFalseRange(Sym->getType());
}
- return llvm::None;
+ return std::nullopt;
}
RangeSet getTrueRange(QualType T) {
@@ -1626,6 +1614,57 @@ private:
//===----------------------------------------------------------------------===//
template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_NE>(RangeSet LHS,
+ RangeSet RHS,
+ QualType T) {
+ assert(!LHS.isEmpty() && !RHS.isEmpty());
+
+ if (LHS.getAPSIntType() == RHS.getAPSIntType()) {
+ if (intersect(RangeFactory, LHS, RHS).isEmpty())
+ return getTrueRange(T);
+
+ } else {
+ // We can only lose information if we are casting smaller signed type to
+ // bigger unsigned type. For e.g.,
+ // LHS (unsigned short): [2, USHRT_MAX]
+ // RHS (signed short): [SHRT_MIN, 0]
+ //
+ // Casting RHS to LHS type will leave us with overlapping values
+ // CastedRHS : [0, 0] U [SHRT_MAX + 1, USHRT_MAX]
+ //
+ // We can avoid this by checking if signed type's maximum value is lesser
+ // than unsigned type's minimum value.
+
+ // If both have different signs then only we can get more information.
+ if (LHS.isUnsigned() != RHS.isUnsigned()) {
+ if (LHS.isUnsigned() && (LHS.getBitWidth() >= RHS.getBitWidth())) {
+ if (RHS.getMaxValue().isNegative() ||
+ LHS.getAPSIntType().convert(RHS.getMaxValue()) < LHS.getMinValue())
+ return getTrueRange(T);
+
+ } else if (RHS.isUnsigned() && (LHS.getBitWidth() <= RHS.getBitWidth())) {
+ if (LHS.getMaxValue().isNegative() ||
+ RHS.getAPSIntType().convert(LHS.getMaxValue()) < RHS.getMinValue())
+ return getTrueRange(T);
+ }
+ }
+
+ // Both RangeSets should be casted to bigger unsigned type.
+ APSIntType CastingType(std::max(LHS.getBitWidth(), RHS.getBitWidth()),
+ LHS.isUnsigned() || RHS.isUnsigned());
+
+ RangeSet CastedLHS = RangeFactory.castTo(LHS, CastingType);
+ RangeSet CastedRHS = RangeFactory.castTo(RHS, CastingType);
+
+ if (intersect(RangeFactory, CastedLHS, CastedRHS).isEmpty())
+ return getTrueRange(T);
+ }
+
+ // In all other cases, the resulting range cannot be deduced.
+ return infer(T);
+}
+
+template <>
RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Or>(Range LHS, Range RHS,
QualType T) {
APSIntType ResultType = ValueFactory.getAPSIntType(T);
@@ -1785,6 +1824,29 @@ RangeSet SymbolicRangeInferrer::VisitBinaryOperator<BO_Rem>(Range LHS,
return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};
}
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
+ BinaryOperator::Opcode Op,
+ RangeSet RHS, QualType T) {
+ // We should propagate information about unfeasbility of one of the
+ // operands to the resulting range.
+ if (LHS.isEmpty() || RHS.isEmpty()) {
+ return RangeFactory.getEmptySet();
+ }
+
+ switch (Op) {
+ case BO_NE:
+ return VisitBinaryOperator<BO_NE>(LHS, RHS, T);
+ case BO_Or:
+ return VisitBinaryOperator<BO_Or>(LHS, RHS, T);
+ case BO_And:
+ return VisitBinaryOperator<BO_And>(LHS, RHS, T);
+ case BO_Rem:
+ return VisitBinaryOperator<BO_Rem>(LHS, RHS, T);
+ default:
+ return infer(T);
+ }
+}
+
//===----------------------------------------------------------------------===//
// Constraint manager implementation details
//===----------------------------------------------------------------------===//
@@ -1995,7 +2057,7 @@ public:
class ConstraintAssignor : public ConstraintAssignorBase<ConstraintAssignor> {
public:
template <class ClassOrSymbol>
- LLVM_NODISCARD static ProgramStateRef
+ [[nodiscard]] static ProgramStateRef
assign(ProgramStateRef State, SValBuilder &Builder, RangeSet::Factory &F,
ClassOrSymbol CoS, RangeSet NewConstraint) {
if (!State || NewConstraint.isEmpty())
@@ -2037,7 +2099,7 @@ private:
using Base = ConstraintAssignorBase<ConstraintAssignor>;
/// Base method for handling new constraints for symbols.
- LLVM_NODISCARD ProgramStateRef assign(SymbolRef Sym, RangeSet NewConstraint) {
+ [[nodiscard]] ProgramStateRef assign(SymbolRef Sym, RangeSet NewConstraint) {
// All constraints are actually associated with equivalence classes, and
// that's what we are going to do first.
State = assign(EquivalenceClass::find(State, Sym), NewConstraint);
@@ -2051,8 +2113,8 @@ private:
}
/// Base method for handling new constraints for classes.
- LLVM_NODISCARD ProgramStateRef assign(EquivalenceClass Class,
- RangeSet NewConstraint) {
+ [[nodiscard]] ProgramStateRef assign(EquivalenceClass Class,
+ RangeSet NewConstraint) {
// There is a chance that we might need to update constraints for the
// classes that are known to be disequal to Class.
//
@@ -2098,7 +2160,7 @@ private:
return EquivalenceClass::merge(RangeFactory, State, LHS, RHS);
}
- LLVM_NODISCARD Optional<bool> interpreteAsBool(RangeSet Constraint) {
+ [[nodiscard]] std::optional<bool> interpreteAsBool(RangeSet Constraint) {
assert(!Constraint.isEmpty() && "Empty ranges shouldn't get here");
if (Constraint.getConcreteValue())
@@ -2107,7 +2169,7 @@ private:
if (!Constraint.containsZero())
return true;
- return llvm::None;
+ return std::nullopt;
}
ProgramStateRef State;
@@ -2115,7 +2177,6 @@ private:
RangeSet::Factory &RangeFactory;
};
-
bool ConstraintAssignor::assignSymExprToConst(const SymExpr *Sym,
const llvm::APSInt &Constraint) {
llvm::SmallSet<EquivalenceClass, 4> SimplifiedClasses;
@@ -2162,12 +2223,12 @@ bool ConstraintAssignor::assignSymSymExprToRangeSet(const SymSymExpr *Sym,
if (!handleRemainderOp(Sym, Constraint))
return false;
- Optional<bool> ConstraintAsBool = interpreteAsBool(Constraint);
+ std::optional<bool> ConstraintAsBool = interpreteAsBool(Constraint);
if (!ConstraintAsBool)
return true;
- if (Optional<bool> Equality = meansEquality(Sym)) {
+ if (std::optional<bool> Equality = meansEquality(Sym)) {
// Here we cover two cases:
// * if Sym is equality and the new constraint is true -> Sym's operands
// should be marked as equal
@@ -2305,7 +2366,7 @@ EquivalenceClass::mergeImpl(RangeSet::Factory &RangeFactory,
//
// Intersection here makes perfect sense because both of these constraints
// must hold for the whole new class.
- if (Optional<RangeSet> NewClassConstraint =
+ if (std::optional<RangeSet> NewClassConstraint =
intersect(RangeFactory, getConstraint(State, *this),
getConstraint(State, Other))) {
// NOTE: Essentially, NewClassConstraint should NEVER be infeasible because
@@ -2503,16 +2564,16 @@ inline bool EquivalenceClass::addToDisequalityInfo(
return true;
}
-inline Optional<bool> EquivalenceClass::areEqual(ProgramStateRef State,
- SymbolRef FirstSym,
- SymbolRef SecondSym) {
+inline std::optional<bool> EquivalenceClass::areEqual(ProgramStateRef State,
+ SymbolRef FirstSym,
+ SymbolRef SecondSym) {
return EquivalenceClass::areEqual(State, find(State, FirstSym),
find(State, SecondSym));
}
-inline Optional<bool> EquivalenceClass::areEqual(ProgramStateRef State,
- EquivalenceClass First,
- EquivalenceClass Second) {
+inline std::optional<bool> EquivalenceClass::areEqual(ProgramStateRef State,
+ EquivalenceClass First,
+ EquivalenceClass Second) {
// The same equivalence class => symbols are equal.
if (First == Second)
return true;
@@ -2524,10 +2585,10 @@ inline Optional<bool> EquivalenceClass::areEqual(ProgramStateRef State,
return false;
// It is not clear.
- return llvm::None;
+ return std::nullopt;
}
-LLVM_NODISCARD ProgramStateRef
+[[nodiscard]] ProgramStateRef
EquivalenceClass::removeMember(ProgramStateRef State, const SymbolRef Old) {
SymbolSet ClsMembers = getClassMembers(State);
@@ -2556,9 +2617,8 @@ EquivalenceClass::removeMember(ProgramStateRef State, const SymbolRef Old) {
}
// Re-evaluate an SVal with top-level `State->assume` logic.
-LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State,
- const RangeSet *Constraint,
- SVal TheValue) {
+[[nodiscard]] ProgramStateRef
+reAssume(ProgramStateRef State, const RangeSet *Constraint, SVal TheValue) {
if (!Constraint)
return State;
@@ -2587,7 +2647,7 @@ LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State,
// class to this class. This way, we simplify not just the symbols but the
// classes as well: we strive to keep the number of the classes to be the
// absolute minimum.
-LLVM_NODISCARD ProgramStateRef
+[[nodiscard]] ProgramStateRef
EquivalenceClass::simplify(SValBuilder &SVB, RangeSet::Factory &F,
ProgramStateRef State, EquivalenceClass Class) {
SymbolSet ClassMembers = Class.getClassMembers(State);
@@ -2717,7 +2777,7 @@ bool EquivalenceClass::isClassDataConsistent(ProgramStateRef State) {
//===----------------------------------------------------------------------===//
bool RangeConstraintManager::canReasonAbout(SVal X) const {
- Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
+ std::optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
if (SymVal && SymVal->isExpression()) {
const SymExpr *SE = SymVal->getSymbol();
diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index d8ece9f39a25..46948c12617c 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -28,8 +28,8 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
#include <utility>
using namespace clang;
@@ -212,11 +212,11 @@ public:
removeBinding(R, BindingKey::Default);
}
- Optional<SVal> getDirectBinding(const MemRegion *R) const;
+ std::optional<SVal> getDirectBinding(const MemRegion *R) const;
/// getDefaultBinding - Returns an SVal* representing an optional default
/// binding associated with a region and its subregions.
- Optional<SVal> getDefaultBinding(const MemRegion *R) const;
+ std::optional<SVal> getDefaultBinding(const MemRegion *R) const;
/// Return the internal tree as a Store.
Store asStore() const {
@@ -262,12 +262,16 @@ public:
typedef const RegionBindingsRef& RegionBindingsConstRef;
-Optional<SVal> RegionBindingsRef::getDirectBinding(const MemRegion *R) const {
- return Optional<SVal>::create(lookup(R, BindingKey::Direct));
+std::optional<SVal>
+RegionBindingsRef::getDirectBinding(const MemRegion *R) const {
+ const SVal *V = lookup(R, BindingKey::Direct);
+ return V ? std::optional<SVal>(*V) : std::nullopt;
}
-Optional<SVal> RegionBindingsRef::getDefaultBinding(const MemRegion *R) const {
- return Optional<SVal>::create(lookup(R, BindingKey::Default));
+std::optional<SVal>
+RegionBindingsRef::getDefaultBinding(const MemRegion *R) const {
+ const SVal *V = lookup(R, BindingKey::Default);
+ return V ? std::optional<SVal>(*V) : std::nullopt;
}
RegionBindingsRef RegionBindingsRef::addBinding(BindingKey K, SVal V) const {
@@ -421,10 +425,10 @@ public:
RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B,
const SubRegion *R);
- Optional<SVal>
+ std::optional<SVal>
getConstantValFromConstArrayInitializer(RegionBindingsConstRef B,
const ElementRegion *R);
- Optional<SVal>
+ std::optional<SVal>
getSValFromInitListExpr(const InitListExpr *ILE,
const SmallVector<uint64_t, 2> &ConcreteOffsets,
QualType ElemT);
@@ -483,12 +487,11 @@ public: // Part of public interface to class.
/// than using a Default binding at the base of the entire region. This is a
/// heuristic attempting to avoid building long chains of LazyCompoundVals.
///
- /// \returns The updated store bindings, or \c None if binding non-lazily
- /// would be too expensive.
- Optional<RegionBindingsRef> tryBindSmallStruct(RegionBindingsConstRef B,
- const TypedValueRegion *R,
- const RecordDecl *RD,
- nonloc::LazyCompoundVal LCV);
+ /// \returns The updated store bindings, or \c std::nullopt if binding
+ /// non-lazily would be too expensive.
+ std::optional<RegionBindingsRef>
+ tryBindSmallStruct(RegionBindingsConstRef B, const TypedValueRegion *R,
+ const RecordDecl *RD, nonloc::LazyCompoundVal LCV);
/// BindStruct - Bind a compound value to a structure.
RegionBindingsRef bindStruct(RegionBindingsConstRef B,
@@ -498,10 +501,9 @@ public: // Part of public interface to class.
RegionBindingsRef bindVector(RegionBindingsConstRef B,
const TypedValueRegion* R, SVal V);
- Optional<RegionBindingsRef> tryBindSmallArray(RegionBindingsConstRef B,
- const TypedValueRegion *R,
- const ArrayType *AT,
- nonloc::LazyCompoundVal LCV);
+ std::optional<RegionBindingsRef>
+ tryBindSmallArray(RegionBindingsConstRef B, const TypedValueRegion *R,
+ const ArrayType *AT, nonloc::LazyCompoundVal LCV);
RegionBindingsRef bindArray(RegionBindingsConstRef B,
const TypedValueRegion* R,
@@ -548,7 +550,7 @@ public: // Part of public interface to class.
return getBinding(getRegionBindings(S), L, T);
}
- Optional<SVal> getDefaultBinding(Store S, const MemRegion *R) override {
+ std::optional<SVal> getDefaultBinding(Store S, const MemRegion *R) override {
RegionBindingsRef B = getRegionBindings(S);
// Default bindings are always applied over a base region so look up the
// base region's default binding, otherwise the lookup will fail when R
@@ -589,10 +591,10 @@ public: // Part of public interface to class.
///
/// Note that callers may need to specially handle LazyCompoundVals, which
/// are returned as is in case the caller needs to treat them differently.
- Optional<SVal> getBindingForDerivedDefaultValue(RegionBindingsConstRef B,
- const MemRegion *superR,
- const TypedValueRegion *R,
- QualType Ty);
+ std::optional<SVal>
+ getBindingForDerivedDefaultValue(RegionBindingsConstRef B,
+ const MemRegion *superR,
+ const TypedValueRegion *R, QualType Ty);
/// Get the state and region whose binding this region \p R corresponds to.
///
@@ -608,6 +610,10 @@ public: // Part of public interface to class.
/// The precise value of "interesting" is determined for the purposes of
/// RegionStore's internal analysis. It must always contain all regions and
/// symbols, but may omit constants and other kinds of SVal.
+ ///
+ /// In contrast to compound values, LazyCompoundVals are also added
+ /// to the 'interesting values' list in addition to the child interesting
+ /// values.
const SValListTy &getInterestingValues(nonloc::LazyCompoundVal LCV);
//===------------------------------------------------------------------===//
@@ -857,7 +863,7 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
// Find the length (in bits) of the region being invalidated.
uint64_t Length = UINT64_MAX;
SVal Extent = Top->getMemRegionManager().getStaticSize(Top, SVB);
- if (Optional<nonloc::ConcreteInt> ExtentCI =
+ if (std::optional<nonloc::ConcreteInt> ExtentCI =
Extent.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt &ExtentInt = ExtentCI->getValue();
assert(ExtentInt.isNonNegative() || ExtentInt.isUnsigned());
@@ -1029,15 +1035,14 @@ void InvalidateRegionsWorker::VisitBinding(SVal V) {
}
// Is it a LazyCompoundVal? All references get invalidated as well.
- if (Optional<nonloc::LazyCompoundVal> LCS =
+ if (std::optional<nonloc::LazyCompoundVal> LCS =
V.getAs<nonloc::LazyCompoundVal>()) {
- const RegionStoreManager::SValListTy &Vals = RM.getInterestingValues(*LCS);
-
- for (RegionStoreManager::SValListTy::const_iterator I = Vals.begin(),
- E = Vals.end();
- I != E; ++I)
- VisitBinding(*I);
+ // `getInterestingValues()` returns SVals contained within LazyCompoundVals,
+ // so there is no need to visit them.
+ for (SVal V : RM.getInterestingValues(*LCS))
+ if (!isa<nonloc::LazyCompoundVal>(V))
+ VisitBinding(V);
return;
}
@@ -1103,7 +1108,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
// a pointer value, but the thing pointed by that pointer may
// get invalidated.
SVal V = RM.getBinding(B, loc::MemRegionVal(VR));
- if (Optional<Loc> L = V.getAs<Loc>()) {
+ if (std::optional<Loc> L = V.getAs<Loc>()) {
if (const MemRegion *LR = L->getAsRegion())
AddToWorkList(LR);
}
@@ -1163,7 +1168,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
if (doNotInvalidateSuperRegion) {
// We are not doing blank invalidation of the whole array region so we
// have to manually invalidate each elements.
- Optional<uint64_t> NumElements;
+ std::optional<uint64_t> NumElements;
// Compute lower and upper offsets for region within array.
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
@@ -1198,8 +1203,8 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E;
++I) {
const BindingKey &BK = I.getKey();
- Optional<uint64_t> ROffset =
- BK.hasSymbolicOffset() ? Optional<uint64_t>() : BK.getOffset();
+ std::optional<uint64_t> ROffset =
+ BK.hasSymbolicOffset() ? std::optional<uint64_t>() : BK.getOffset();
// Check offset is not symbolic and within array's boundaries.
// Handles arrays of 0 elements and of 0-sized elements as well.
@@ -1287,18 +1292,13 @@ void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W,
for (ArrayRef<SVal>::iterator I = Values.begin(),
E = Values.end(); I != E; ++I) {
SVal V = *I;
- if (Optional<nonloc::LazyCompoundVal> LCS =
- V.getAs<nonloc::LazyCompoundVal>()) {
-
- const SValListTy &Vals = getInterestingValues(*LCS);
+ if (std::optional<nonloc::LazyCompoundVal> LCS =
+ V.getAs<nonloc::LazyCompoundVal>()) {
- for (SValListTy::const_iterator I = Vals.begin(),
- E = Vals.end(); I != E; ++I) {
- // Note: the last argument is false here because these are
- // non-top-level regions.
- if (const MemRegion *R = (*I).getAsRegion())
+ for (SVal S : getInterestingValues(*LCS))
+ if (const MemRegion *R = S.getAsRegion())
W.AddToWorkList(R);
- }
+
continue;
}
@@ -1354,11 +1354,11 @@ RegionStoreManager::invalidateRegions(Store store,
case GFK_All:
B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GFK_SystemOnly:
B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case GFK_None:
break;
}
@@ -1416,19 +1416,20 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
return UnknownVal();
}
- if (!isa<TypedValueRegion>(MR)) {
- if (T.isNull()) {
- if (const TypedRegion *TR = dyn_cast<TypedRegion>(MR))
- T = TR->getLocationType()->getPointeeType();
- else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
- T = SR->getSymbol()->getType()->getPointeeType();
- }
- assert(!T.isNull() && "Unable to auto-detect binding type!");
- assert(!T->isVoidType() && "Attempting to dereference a void pointer!");
- MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
- } else {
- T = cast<TypedValueRegion>(MR)->getValueType();
+ // Auto-detect the binding type.
+ if (T.isNull()) {
+ if (const auto *TVR = dyn_cast<TypedValueRegion>(MR))
+ T = TVR->getValueType();
+ else if (const auto *TR = dyn_cast<TypedRegion>(MR))
+ T = TR->getLocationType()->getPointeeType();
+ else if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
+ T = SR->getPointeeStaticType();
}
+ assert(!T.isNull() && "Unable to auto-detect binding type!");
+ assert(!T->isVoidType() && "Attempting to dereference a void pointer!");
+
+ if (!isa<TypedValueRegion>(MR))
+ MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
// instead of 'Loc', and have the other Loc cases handled at a higher level.
@@ -1537,16 +1538,17 @@ static QualType getUnderlyingType(const SubRegion *R) {
///
/// Note that unlike RegionStoreManager::findLazyBinding, this will not search
/// for lazy bindings for super-regions of \p R.
-static Optional<nonloc::LazyCompoundVal>
+static std::optional<nonloc::LazyCompoundVal>
getExistingLazyBinding(SValBuilder &SVB, RegionBindingsConstRef B,
const SubRegion *R, bool AllowSubregionBindings) {
- Optional<SVal> V = B.getDefaultBinding(R);
+ std::optional<SVal> V = B.getDefaultBinding(R);
if (!V)
- return None;
+ return std::nullopt;
- Optional<nonloc::LazyCompoundVal> LCV = V->getAs<nonloc::LazyCompoundVal>();
+ std::optional<nonloc::LazyCompoundVal> LCV =
+ V->getAs<nonloc::LazyCompoundVal>();
if (!LCV)
- return None;
+ return std::nullopt;
// If the LCV is for a subregion, the types might not match, and we shouldn't
// reuse the binding.
@@ -1555,7 +1557,7 @@ getExistingLazyBinding(SValBuilder &SVB, RegionBindingsConstRef B,
!RegionTy->isVoidPointerType()) {
QualType SourceRegionTy = LCV->getRegion()->getValueType();
if (!SVB.getContext().hasSameUnqualifiedType(RegionTy, SourceRegionTy))
- return None;
+ return std::nullopt;
}
if (!AllowSubregionBindings) {
@@ -1565,20 +1567,19 @@ getExistingLazyBinding(SValBuilder &SVB, RegionBindingsConstRef B,
collectSubRegionBindings(Bindings, SVB, *B.lookup(R->getBaseRegion()), R,
/*IncludeAllDefaultBindings=*/true);
if (Bindings.size() > 1)
- return None;
+ return std::nullopt;
}
return *LCV;
}
-
std::pair<Store, const SubRegion *>
RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
const SubRegion *R,
const SubRegion *originalRegion) {
if (originalRegion != R) {
- if (Optional<nonloc::LazyCompoundVal> V =
- getExistingLazyBinding(svalBuilder, B, R, true))
+ if (std::optional<nonloc::LazyCompoundVal> V =
+ getExistingLazyBinding(svalBuilder, B, R, true))
return std::make_pair(V->getStore(), V->getRegion());
}
@@ -1666,7 +1667,7 @@ getElementRegionOffsetsWithBase(const ElementRegion *ER) {
/// \param ArrayExtents [in] The array of extents.
/// \param DstOffsets [out] The array of offsets of type `uint64_t`.
/// \returns:
-/// - `None` for successful convertion.
+/// - `std::nullopt` for successful convertion.
/// - `UndefinedVal` or `UnknownVal` otherwise. It's expected that this SVal
/// will be returned as a suitable value of the access operation.
/// which should be returned as a correct
@@ -1675,10 +1676,10 @@ getElementRegionOffsetsWithBase(const ElementRegion *ER) {
/// const int arr[10][20][30] = {}; // ArrayExtents { 10, 20, 30 }
/// int x1 = arr[4][5][6]; // SrcOffsets { NonLoc(6), NonLoc(5), NonLoc(4) }
/// // DstOffsets { 4, 5, 6 }
-/// // returns None
+/// // returns std::nullopt
/// int x2 = arr[42][5][-6]; // returns UndefinedVal
/// int x3 = arr[4][5][x2]; // returns UnknownVal
-static Optional<SVal>
+static std::optional<SVal>
convertOffsetsFromSvalToUnsigneds(const SmallVector<SVal, 2> &SrcOffsets,
const SmallVector<uint64_t, 2> ArrayExtents,
SmallVector<uint64_t, 2> &DstOffsets) {
@@ -1718,10 +1719,10 @@ convertOffsetsFromSvalToUnsigneds(const SmallVector<SVal, 2> &SrcOffsets,
// account.
return UnknownVal();
}
- return None;
+ return std::nullopt;
}
-Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
+std::optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
RegionBindingsConstRef B, const ElementRegion *R) {
assert(R && "ElementRegion should not be null");
@@ -1731,7 +1732,7 @@ Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
std::tie(SValOffsets, Base) = getElementRegionOffsetsWithBase(R);
const VarRegion *VR = dyn_cast<VarRegion>(Base);
if (!VR)
- return None;
+ return std::nullopt;
assert(!SValOffsets.empty() && "getElementRegionOffsets guarantees the "
"offsets vector is not empty.");
@@ -1742,7 +1743,7 @@ Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
if (!VD->getType().isConstQualified() &&
!R->getElementType().isConstQualified() &&
(!B.isMainAnalysis() || !VD->hasGlobalStorage()))
- return None;
+ return std::nullopt;
// Array's declaration should have `ConstantArrayType` type, because only this
// type contains an array extent. It may happen that array type can be of
@@ -1757,13 +1758,13 @@ Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
// NOTE: If `Init` is non-null, then a new `VD` is non-null for sure. So check
// `Init` for null only and don't worry about the replaced `VD`.
if (!Init)
- return None;
+ return std::nullopt;
// Array's declaration should have ConstantArrayType type, because only this
// type contains an array extent.
const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(VD->getType());
if (!CAT)
- return None;
+ return std::nullopt;
// Get array extents.
SmallVector<uint64_t, 2> Extents = getConstantArrayExtents(CAT);
@@ -1775,11 +1776,11 @@ Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
// auto x = ptr[4][2]; // UB
// FIXME: Should return UndefinedVal.
if (SValOffsets.size() != Extents.size())
- return None;
+ return std::nullopt;
SmallVector<uint64_t, 2> ConcreteOffsets;
- if (Optional<SVal> V = convertOffsetsFromSvalToUnsigneds(SValOffsets, Extents,
- ConcreteOffsets))
+ if (std::optional<SVal> V = convertOffsetsFromSvalToUnsigneds(
+ SValOffsets, Extents, ConcreteOffsets))
return *V;
// Handle InitListExpr.
@@ -1797,7 +1798,7 @@ Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
// FIXME: Handle CompoundLiteralExpr.
- return None;
+ return std::nullopt;
}
/// Returns an SVal, if possible, for the specified position of an
@@ -1817,7 +1818,7 @@ Optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
/// NOTE: Inorder to get a valid SVal, a caller shall guarantee valid offsets
/// for the given initialization list. Otherwise SVal can be an equivalent to 0
/// or lead to assertion.
-Optional<SVal> RegionStoreManager::getSValFromInitListExpr(
+std::optional<SVal> RegionStoreManager::getSValFromInitListExpr(
const InitListExpr *ILE, const SmallVector<uint64_t, 2> &Offsets,
QualType ElemT) {
assert(ILE && "InitListExpr should not be null");
@@ -1888,7 +1889,7 @@ SVal RegionStoreManager::getSValFromStringLiteral(const StringLiteral *SL,
return svalBuilder.makeIntVal(Code, ElemT);
}
-static Optional<SVal> getDerivedSymbolForBinding(
+static std::optional<SVal> getDerivedSymbolForBinding(
RegionBindingsConstRef B, const TypedValueRegion *BaseRegion,
const TypedValueRegion *SubReg, const ASTContext &Ctx, SValBuilder &SVB) {
assert(BaseRegion);
@@ -1896,7 +1897,8 @@ static Optional<SVal> getDerivedSymbolForBinding(
QualType Ty = SubReg->getValueType();
if (BaseTy->isScalarType() && Ty->isScalarType()) {
if (Ctx.getTypeSizeInChars(BaseTy) >= Ctx.getTypeSizeInChars(Ty)) {
- if (const Optional<SVal> &ParentValue = B.getDirectBinding(BaseRegion)) {
+ if (const std::optional<SVal> &ParentValue =
+ B.getDirectBinding(BaseRegion)) {
if (SymbolRef ParentValueAsSym = ParentValue->getAsSymbol())
return SVB.getDerivedRegionValueSymbolVal(ParentValueAsSym, SubReg);
@@ -1909,13 +1911,13 @@ static Optional<SVal> getDerivedSymbolForBinding(
}
}
}
- return None;
+ return std::nullopt;
}
SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
const ElementRegion* R) {
// Check if the region has a binding.
- if (const Optional<SVal> &V = B.getDirectBinding(R))
+ if (const std::optional<SVal> &V = B.getDirectBinding(R))
return *V;
const MemRegion* superR = R->getSuperRegion();
@@ -1936,7 +1938,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
return getSValFromStringLiteral(SL, Idx.getZExtValue(), T);
}
} else if (isa<ElementRegion, VarRegion>(superR)) {
- if (Optional<SVal> V = getConstantValFromConstArrayInitializer(B, R))
+ if (std::optional<SVal> V = getConstantValFromConstArrayInitializer(B, R))
return *V;
}
@@ -1967,7 +1969,7 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
const FieldRegion* R) {
// Check if the region has a binding.
- if (const Optional<SVal> &V = B.getDirectBinding(R))
+ if (const std::optional<SVal> &V = B.getDirectBinding(R))
return *V;
// If the containing record was initialized, try to get its constant value.
@@ -1987,7 +1989,7 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
if (Index < InitList->getNumInits()) {
if (const Expr *FieldInit = InitList->getInit(Index))
- if (Optional<SVal> V = svalBuilder.getConstantVal(FieldInit))
+ if (std::optional<SVal> V = svalBuilder.getConstantVal(FieldInit))
return *V;
} else {
return svalBuilder.makeZeroVal(Ty);
@@ -2018,13 +2020,11 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
return getBindingForFieldOrElementCommon(B, R, Ty);
}
-Optional<SVal>
-RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindingsConstRef B,
- const MemRegion *superR,
- const TypedValueRegion *R,
- QualType Ty) {
+std::optional<SVal> RegionStoreManager::getBindingForDerivedDefaultValue(
+ RegionBindingsConstRef B, const MemRegion *superR,
+ const TypedValueRegion *R, QualType Ty) {
- if (const Optional<SVal> &D = B.getDefaultBinding(superR)) {
+ if (const std::optional<SVal> &D = B.getDefaultBinding(superR)) {
const SVal &val = *D;
if (SymbolRef parentSym = val.getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -2043,7 +2043,7 @@ RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindingsConstRef B,
llvm_unreachable("Unknown default value");
}
- return None;
+ return std::nullopt;
}
SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion,
@@ -2114,7 +2114,8 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
const SubRegion *SR = R;
while (SR) {
const MemRegion *Base = SR->getSuperRegion();
- if (Optional<SVal> D = getBindingForDerivedDefaultValue(B, Base, R, Ty)) {
+ if (std::optional<SVal> D =
+ getBindingForDerivedDefaultValue(B, Base, R, Ty)) {
if (D->getAs<nonloc::LazyCompoundVal>()) {
hasPartialLazyBinding = true;
break;
@@ -2156,7 +2157,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
// Try to get direct binding if all other attempts failed thus far.
// Else, return UndefinedVal()
if (!hasPartialLazyBinding && !isa<BlockDataRegion>(R->getBaseRegion())) {
- if (const Optional<SVal> &V = B.getDefaultBinding(R))
+ if (const std::optional<SVal> &V = B.getDefaultBinding(R))
return *V;
return UndefinedVal();
}
@@ -2169,13 +2170,13 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
SVal RegionStoreManager::getBindingForObjCIvar(RegionBindingsConstRef B,
const ObjCIvarRegion* R) {
// Check if the region has a binding.
- if (const Optional<SVal> &V = B.getDirectBinding(R))
+ if (const std::optional<SVal> &V = B.getDirectBinding(R))
return *V;
const MemRegion *superR = R->getSuperRegion();
// Check if the super region has a default binding.
- if (const Optional<SVal> &V = B.getDefaultBinding(superR)) {
+ if (const std::optional<SVal> &V = B.getDefaultBinding(superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -2190,10 +2191,10 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
const VarRegion *R) {
// Check if the region has a binding.
- if (Optional<SVal> V = B.getDirectBinding(R))
+ if (std::optional<SVal> V = B.getDirectBinding(R))
return *V;
- if (Optional<SVal> V = B.getDefaultBinding(R))
+ if (std::optional<SVal> V = B.getDefaultBinding(R))
return *V;
// Lazily derive a value for the VarRegion.
@@ -2207,7 +2208,7 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
// Is 'VD' declared constant? If so, retrieve the constant value.
if (VD->getType().isConstQualified()) {
if (const Expr *Init = VD->getAnyInitializer()) {
- if (Optional<SVal> V = svalBuilder.getConstantVal(Init))
+ if (std::optional<SVal> V = svalBuilder.getConstantVal(Init))
return *V;
// If the variable is const qualified and has an initializer but
@@ -2228,7 +2229,7 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
// 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))
+ if (std::optional<SVal> V = svalBuilder.getConstantVal(Init))
return *V;
// Function-scoped static variables are default-initialized to 0; if they
@@ -2238,7 +2239,7 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
if (isa<StaticGlobalSpaceRegion>(MS))
return svalBuilder.makeZeroVal(T);
- if (Optional<SVal> V = getBindingForDerivedDefaultValue(B, MS, R, T)) {
+ if (std::optional<SVal> V = getBindingForDerivedDefaultValue(B, MS, R, T)) {
assert(!V->getAs<nonloc::LazyCompoundVal>());
return *V;
}
@@ -2283,11 +2284,9 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
if (V.isUnknownOrUndef() || V.isConstant())
continue;
- if (Optional<nonloc::LazyCompoundVal> InnerLCV =
- V.getAs<nonloc::LazyCompoundVal>()) {
+ if (auto InnerLCV = V.getAs<nonloc::LazyCompoundVal>()) {
const SValListTy &InnerList = getInterestingValues(*InnerLCV);
List.insert(List.end(), InnerList.begin(), InnerList.end());
- continue;
}
List.push_back(V);
@@ -2298,8 +2297,8 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B,
const TypedValueRegion *R) {
- if (Optional<nonloc::LazyCompoundVal> V =
- getExistingLazyBinding(svalBuilder, B, R, false))
+ if (std::optional<nonloc::LazyCompoundVal> V =
+ getExistingLazyBinding(svalBuilder, B, R, false))
return *V;
return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
@@ -2359,7 +2358,7 @@ bool RegionStoreManager::includedInBindings(Store store,
//===----------------------------------------------------------------------===//
StoreRef RegionStoreManager::killBinding(Store ST, Loc L) {
- if (Optional<loc::MemRegionVal> LV = L.getAs<loc::MemRegionVal>())
+ if (std::optional<loc::MemRegionVal> LV = L.getAs<loc::MemRegionVal>())
if (const MemRegion* R = LV->getRegion())
return StoreRef(getRegionBindings(ST).removeBinding(R)
.asImmutableMap()
@@ -2390,22 +2389,21 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
return bindAggregate(B, TR, V);
}
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
- // Binding directly to a symbolic region should be treated as binding
- // to element 0.
- QualType T = SR->getSymbol()->getType();
- if (T->isAnyPointerType() || T->isReferenceType())
- T = T->getPointeeType();
-
- R = GetElementZeroRegion(SR, T);
- }
+ // Binding directly to a symbolic region should be treated as binding
+ // to element 0.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ R = GetElementZeroRegion(SR, SR->getPointeeStaticType());
assert((!isa<CXXThisRegion>(R) || !B.lookup(R)) &&
"'this' pointer is not an l-value and is not assignable");
// Clear out bindings that may overlap with this binding.
RegionBindingsRef NewB = removeSubRegionBindings(B, cast<SubRegion>(R));
- return NewB.addBinding(BindingKey::Make(R, BindingKey::Direct), V);
+
+ // LazyCompoundVals should be always bound as 'default' bindings.
+ auto KeyKind = isa<nonloc::LazyCompoundVal>(V) ? BindingKey::Default
+ : BindingKey::Direct;
+ return NewB.addBinding(BindingKey::Make(R, KeyKind), V);
}
RegionBindingsRef
@@ -2435,7 +2433,7 @@ RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B,
return B.addBinding(R, BindingKey::Default, V);
}
-Optional<RegionBindingsRef> RegionStoreManager::tryBindSmallArray(
+std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallArray(
RegionBindingsConstRef B, const TypedValueRegion *R, const ArrayType *AT,
nonloc::LazyCompoundVal LCV) {
@@ -2443,16 +2441,16 @@ Optional<RegionBindingsRef> RegionStoreManager::tryBindSmallArray(
// If we don't know the size, create a lazyCompoundVal instead.
if (!CAT)
- return None;
+ return std::nullopt;
QualType Ty = CAT->getElementType();
if (!(Ty->isScalarType() || Ty->isReferenceType()))
- return None;
+ return std::nullopt;
// If the array is too big, create a LCV instead.
uint64_t ArrSize = CAT->getSize().getLimitedValue();
if (ArrSize > SmallArrayLimit)
- return None;
+ return std::nullopt;
RegionBindingsRef NewB = B;
@@ -2476,7 +2474,7 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B,
const ArrayType *AT =cast<ArrayType>(Ctx.getCanonicalType(R->getValueType()));
QualType ElementTy = AT->getElementType();
- Optional<uint64_t> Size;
+ std::optional<uint64_t> Size;
if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT))
Size = CAT->getSize().getZExtValue();
@@ -2484,15 +2482,16 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B,
// Check if the init expr is a literal. If so, bind the rvalue instead.
// FIXME: It's not responsibility of the Store to transform this lvalue
// to rvalue. ExprEngine or maybe even CFG should do this before binding.
- if (Optional<loc::MemRegionVal> MRV = Init.getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> MRV = Init.getAs<loc::MemRegionVal>()) {
SVal V = getBinding(B.asStore(), *MRV, R->getValueType());
return bindAggregate(B, R, V);
}
// Handle lazy compound values.
- if (Optional<nonloc::LazyCompoundVal> LCV =
+ if (std::optional<nonloc::LazyCompoundVal> LCV =
Init.getAs<nonloc::LazyCompoundVal>()) {
- if (Optional<RegionBindingsRef> NewB = tryBindSmallArray(B, R, AT, *LCV))
+ if (std::optional<RegionBindingsRef> NewB =
+ tryBindSmallArray(B, R, AT, *LCV))
return *NewB;
return bindAggregate(B, R, Init);
@@ -2573,16 +2572,14 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
return NewB;
}
-Optional<RegionBindingsRef>
-RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B,
- const TypedValueRegion *R,
- const RecordDecl *RD,
- nonloc::LazyCompoundVal LCV) {
+std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallStruct(
+ RegionBindingsConstRef B, const TypedValueRegion *R, const RecordDecl *RD,
+ nonloc::LazyCompoundVal LCV) {
FieldVector Fields;
if (const CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(RD))
if (Class->getNumBases() != 0 || Class->getNumVBases() != 0)
- return None;
+ return std::nullopt;
for (const auto *FD : RD->fields()) {
if (FD->isUnnamedBitfield())
@@ -2591,11 +2588,17 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B,
// If there are too many fields, or if any of the fields are aggregates,
// just use the LCV as a default binding.
if (Fields.size() == SmallStructLimit)
- return None;
+ return std::nullopt;
QualType Ty = FD->getType();
+
+ // Zero length arrays are basically no-ops, so we also ignore them here.
+ if (Ty->isConstantArrayType() &&
+ Ctx.getConstantArrayElementCount(Ctx.getAsConstantArrayType(Ty)) == 0)
+ continue;
+
if (!(Ty->isScalarType() || Ty->isReferenceType()))
- return None;
+ return std::nullopt;
Fields.push_back(FD);
}
@@ -2626,9 +2629,10 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B,
return B;
// Handle lazy compound values and symbolic values.
- if (Optional<nonloc::LazyCompoundVal> LCV =
- V.getAs<nonloc::LazyCompoundVal>()) {
- if (Optional<RegionBindingsRef> NewB = tryBindSmallStruct(B, R, RD, *LCV))
+ if (std::optional<nonloc::LazyCompoundVal> LCV =
+ V.getAs<nonloc::LazyCompoundVal>()) {
+ if (std::optional<RegionBindingsRef> NewB =
+ tryBindSmallStruct(B, R, RD, *LCV))
return *NewB;
return bindAggregate(B, R, V);
}
@@ -2830,16 +2834,17 @@ void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
}
void RemoveDeadBindingsWorker::VisitBinding(SVal V) {
- // Is it a LazyCompoundVal? All referenced regions are live as well.
- if (Optional<nonloc::LazyCompoundVal> LCS =
- V.getAs<nonloc::LazyCompoundVal>()) {
-
- const RegionStoreManager::SValListTy &Vals = RM.getInterestingValues(*LCS);
-
- for (RegionStoreManager::SValListTy::const_iterator I = Vals.begin(),
- E = Vals.end();
- I != E; ++I)
- VisitBinding(*I);
+ // Is it a LazyCompoundVal? All referenced regions are live as well.
+ // The LazyCompoundVal itself is not live but should be readable.
+ if (auto LCS = V.getAs<nonloc::LazyCompoundVal>()) {
+ SymReaper.markLazilyCopied(LCS->getRegion());
+
+ for (SVal V : RM.getInterestingValues(*LCS)) {
+ if (auto DepLCS = V.getAs<nonloc::LazyCompoundVal>())
+ SymReaper.markLazilyCopied(DepLCS->getRegion());
+ else
+ VisitBinding(V);
+ }
return;
}
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index d90e869196eb..fed17c77f03d 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -34,11 +34,10 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include <cassert>
+#include <optional>
#include <tuple>
using namespace clang;
@@ -124,7 +123,8 @@ SVal SValBuilder::convertToArrayIndex(SVal val) {
return val;
// Common case: we have an appropriately sized integer.
- if (Optional<nonloc::ConcreteInt> CI = val.getAs<nonloc::ConcreteInt>()) {
+ if (std::optional<nonloc::ConcreteInt> CI =
+ val.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt& I = CI->getValue();
if (I.getBitWidth() == ArrayIndexWidth && I.isSigned())
return val;
@@ -297,11 +297,11 @@ DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block,
return loc::MemRegionVal(BD);
}
-Optional<loc::MemRegionVal>
+std::optional<loc::MemRegionVal>
SValBuilder::getCastedMemRegionVal(const MemRegion *R, QualType Ty) {
if (auto OptR = StateMgr.getStoreManager().castRegion(R, Ty))
return loc::MemRegionVal(*OptR);
- return None;
+ return std::nullopt;
}
/// Return a memory region for the 'this' object reference.
@@ -319,7 +319,7 @@ loc::MemRegionVal SValBuilder::getCXXThis(const CXXRecordDecl *D,
return loc::MemRegionVal(getRegionManager().getCXXThisRegion(PT, SFC));
}
-Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
+std::optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
E = E->IgnoreParens();
switch (E->getStmtClass()) {
@@ -389,21 +389,21 @@ Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
case CK_NoOp:
case CK_BitCast: {
const Expr *SE = CE->getSubExpr();
- Optional<SVal> Val = getConstantVal(SE);
+ std::optional<SVal> Val = getConstantVal(SE);
if (!Val)
- return None;
+ return std::nullopt;
return evalCast(*Val, CE->getType(), SE->getType());
}
}
// FALLTHROUGH
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
// If we don't have a special case, fall back to the AST's constant evaluator.
default: {
// Don't try to come up with a value for materialized temporaries.
if (E->isGLValue())
- return None;
+ return std::nullopt;
ASTContext &Ctx = getContext();
Expr::EvalResult Result;
@@ -414,7 +414,7 @@ Optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
if (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
return makeNullWithType(E->getType());
- return None;
+ return std::nullopt;
}
}
}
@@ -434,11 +434,13 @@ SVal SValBuilder::makeSymExprValNN(BinaryOperator::Opcode Op,
return makeNonLoc(symLHS, Op, symRHS, ResultTy);
if (symLHS && symLHS->computeComplexity() < MaxComp)
- if (Optional<nonloc::ConcreteInt> rInt = RHS.getAs<nonloc::ConcreteInt>())
+ if (std::optional<nonloc::ConcreteInt> rInt =
+ RHS.getAs<nonloc::ConcreteInt>())
return makeNonLoc(symLHS, Op, rInt->getValue(), ResultTy);
if (symRHS && symRHS->computeComplexity() < MaxComp)
- if (Optional<nonloc::ConcreteInt> lInt = LHS.getAs<nonloc::ConcreteInt>())
+ if (std::optional<nonloc::ConcreteInt> lInt =
+ LHS.getAs<nonloc::ConcreteInt>())
return makeNonLoc(lInt->getValue(), Op, symRHS, ResultTy);
return UnknownVal();
@@ -501,14 +503,14 @@ SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
return UnknownVal();
}
- if (Optional<Loc> LV = lhs.getAs<Loc>()) {
- if (Optional<Loc> RV = rhs.getAs<Loc>())
+ if (std::optional<Loc> LV = lhs.getAs<Loc>()) {
+ if (std::optional<Loc> RV = rhs.getAs<Loc>())
return evalBinOpLL(state, op, *LV, *RV, type);
return evalBinOpLN(state, op, *LV, rhs.castAs<NonLoc>(), type);
}
- if (const Optional<Loc> RV = rhs.getAs<Loc>()) {
+ if (const std::optional<Loc> RV = rhs.getAs<Loc>()) {
const auto IsCommutative = [](BinaryOperatorKind Op) {
return Op == BO_Mul || Op == BO_Add || Op == BO_And || Op == BO_Xor ||
Op == BO_Or;
diff --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp b/clang/lib/StaticAnalyzer/Core/SVals.cpp
index 31725926cd0d..bc9c1e40d808 100644
--- a/clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp
@@ -25,12 +25,12 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -44,7 +44,7 @@ using namespace ento;
//===----------------------------------------------------------------------===//
const FunctionDecl *SVal::getAsFunctionDecl() const {
- if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>())
if (const auto *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
@@ -78,7 +78,7 @@ SymbolRef SVal::getAsLocSymbol(bool IncludeBaseRegions) const {
/// Get the symbol in the SVal or its base region.
SymbolRef SVal::getLocSymbolInBase() const {
- Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
+ std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
if (!X)
return nullptr;
@@ -103,7 +103,7 @@ SymbolRef SVal::getLocSymbolInBase() const {
/// should continue to the base regions if the region is not symbolic.
SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const {
// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
- if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
+ if (std::optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
return X->getSymbol();
return getAsLocSymbol(IncludeBaseRegions);
@@ -118,10 +118,10 @@ const llvm::APSInt *SVal::getAsInteger() const {
}
const MemRegion *SVal::getAsRegion() const {
- if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
+ if (std::optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
return X->getRegion();
- if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
+ if (std::optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
return X->getLoc().getAsRegion();
return nullptr;
@@ -251,9 +251,9 @@ bool SVal::isConstant() const {
}
bool SVal::isConstant(int I) const {
- if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
+ if (std::optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
return LV->getValue() == I;
- if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
+ if (std::optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
return NV->getValue() == I;
return false;
}
diff --git a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
index ad3110792592..fab520098f13 100644
--- a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
@@ -13,6 +13,8 @@
#include "clang/Analysis/MacroExpansionContext.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Sarif.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
@@ -30,10 +32,12 @@ namespace {
class SarifDiagnostics : public PathDiagnosticConsumer {
std::string OutputFile;
const LangOptions &LO;
+ SarifDocumentWriter SarifWriter;
public:
- SarifDiagnostics(const std::string &Output, const LangOptions &LO)
- : OutputFile(Output), LO(LO) {}
+ SarifDiagnostics(const std::string &Output, const LangOptions &LO,
+ const SourceManager &SM)
+ : OutputFile(Output), LO(LO), SarifWriter(SM) {}
~SarifDiagnostics() override = default;
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
@@ -56,250 +60,12 @@ void ento::createSarifDiagnosticConsumer(
if (Output.empty())
return;
- C.push_back(new SarifDiagnostics(Output, PP.getLangOpts()));
+ C.push_back(
+ new SarifDiagnostics(Output, PP.getLangOpts(), PP.getSourceManager()));
createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, Output, PP,
CTU, MacroExpansions);
}
-static StringRef getFileName(const FileEntry &FE) {
- StringRef Filename = FE.tryGetRealPathName();
- if (Filename.empty())
- Filename = FE.getName();
- return Filename;
-}
-
-static std::string percentEncodeURICharacter(char C) {
- // RFC 3986 claims alpha, numeric, and this handful of
- // characters are not reserved for the path component and
- // should be written out directly. Otherwise, percent
- // encode the character and write that out instead of the
- // reserved character.
- if (llvm::isAlnum(C) ||
- StringRef::npos != StringRef("-._~:@!$&'()*+,;=").find(C))
- return std::string(&C, 1);
- return "%" + llvm::toHex(StringRef(&C, 1));
-}
-
-static std::string fileNameToURI(StringRef Filename) {
- llvm::SmallString<32> Ret = StringRef("file://");
-
- // Get the root name to see if it has a URI authority.
- StringRef Root = sys::path::root_name(Filename);
- if (Root.startswith("//")) {
- // There is an authority, so add it to the URI.
- Ret += Root.drop_front(2).str();
- } else if (!Root.empty()) {
- // There is no authority, so end the component and add the root to the URI.
- Ret += Twine("/" + Root).str();
- }
-
- auto Iter = sys::path::begin(Filename), End = sys::path::end(Filename);
- assert(Iter != End && "Expected there to be a non-root path component.");
- // Add the rest of the path components, encoding any reserved characters;
- // we skip past the first path component, as it was handled it above.
- for (StringRef Component : llvm::make_range(++Iter, End)) {
- // For reasons unknown to me, we may get a backslash with Windows native
- // paths for the initial backslash following the drive component, which
- // we need to ignore as a URI path part.
- if (Component == "\\")
- continue;
-
- // Add the separator between the previous path part and the one being
- // currently processed.
- Ret += "/";
-
- // URI encode the part.
- for (char C : Component) {
- Ret += percentEncodeURICharacter(C);
- }
- }
-
- return std::string(Ret);
-}
-
-static json::Object createArtifactLocation(const FileEntry &FE) {
- return json::Object{{"uri", fileNameToURI(getFileName(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 createArtifactLocation(const FileEntry &FE,
- json::Array &Artifacts) {
- std::string FileURI = fileNameToURI(getFileName(FE));
-
- // 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("location")) {
- Optional<StringRef> URI = FileLoc->getString("uri");
- return URI && URI->equals(FileURI);
- }
- }
- return false;
- });
-
- // Calculate the index within the artifact array so it can be stored in
- // the JSON object.
- auto Index = static_cast<unsigned>(std::distance(Artifacts.begin(), I));
- if (I == Artifacts.end())
- Artifacts.push_back(createArtifact(FE));
-
- return json::Object{{"uri", FileURI}, {"index", Index}};
-}
-
-static unsigned int adjustColumnPos(const SourceManager &SM, SourceLocation Loc,
- unsigned int TokenLen = 0) {
- assert(!Loc.isInvalid() && "invalid Loc when adjusting column position");
-
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedExpansionLoc(Loc);
- assert(LocInfo.second > SM.getExpansionColumnNumber(Loc) &&
- "position in file is before column number?");
-
- Optional<MemoryBufferRef> Buf = SM.getBufferOrNone(LocInfo.first);
- assert(Buf && "got an invalid buffer for the location's file");
- assert(Buf->getBufferSize() >= (LocInfo.second + TokenLen) &&
- "token extends past end of buffer?");
-
- // Adjust the offset to be the start of the line, since we'll be counting
- // Unicode characters from there until our column offset.
- unsigned int Off = LocInfo.second - (SM.getExpansionColumnNumber(Loc) - 1);
- unsigned int Ret = 1;
- while (Off < (LocInfo.second + TokenLen)) {
- Off += getNumBytesForUTF8(Buf->getBuffer()[Off]);
- Ret++;
- }
-
- return Ret;
-}
-
-static json::Object createTextRegion(const LangOptions &LO, SourceRange R,
- const SourceManager &SM) {
- json::Object Region{
- {"startLine", SM.getExpansionLineNumber(R.getBegin())},
- {"startColumn", adjustColumnPos(SM, R.getBegin())},
- };
- if (R.getBegin() == R.getEnd()) {
- Region["endColumn"] = adjustColumnPos(SM, R.getBegin());
- } else {
- Region["endLine"] = SM.getExpansionLineNumber(R.getEnd());
- Region["endColumn"] = adjustColumnPos(
- SM, R.getEnd(),
- Lexer::MeasureTokenLength(R.getEnd(), SM, LO));
- }
- return Region;
-}
-
-static json::Object createPhysicalLocation(const LangOptions &LO,
- SourceRange R, const FileEntry &FE,
- const SourceManager &SMgr,
- json::Array &Artifacts) {
- return json::Object{
- {{"artifactLocation", createArtifactLocation(FE, Artifacts)},
- {"region", createTextRegion(LO, R, SMgr)}}};
-}
-
-enum class Importance { Important, Essential, Unimportant };
-
-static StringRef importanceToStr(Importance I) {
- switch (I) {
- case Importance::Important:
- return "important";
- case Importance::Essential:
- return "essential";
- case Importance::Unimportant:
- return "unimportant";
- }
- llvm_unreachable("Fully covered switch is not so fully covered");
-}
-
-static json::Object createThreadFlowLocation(json::Object &&Location,
- Importance I) {
- return json::Object{{"location", std::move(Location)},
- {"importance", importanceToStr(I)}};
-}
-
-static json::Object createMessage(StringRef Text) {
- return json::Object{{"text", Text.str()}};
-}
-
-static json::Object createLocation(json::Object &&PhysicalLocation,
- StringRef Message = "") {
- json::Object Ret{{"physicalLocation", std::move(PhysicalLocation)}};
- if (!Message.empty())
- Ret.insert({"message", createMessage(Message)});
- return Ret;
-}
-
-static Importance calculateImportance(const PathDiagnosticPiece &Piece) {
- switch (Piece.getKind()) {
- case PathDiagnosticPiece::Call:
- case PathDiagnosticPiece::Macro:
- case PathDiagnosticPiece::Note:
- case PathDiagnosticPiece::PopUp:
- // FIXME: What should be reported here?
- break;
- case PathDiagnosticPiece::Event:
- return Piece.getTagStr() == "ConditionBRVisitor" ? Importance::Important
- : Importance::Essential;
- case PathDiagnosticPiece::ControlFlow:
- return Importance::Unimportant;
- }
- return Importance::Unimportant;
-}
-
-static json::Object createThreadFlow(const LangOptions &LO,
- const PathPieces &Pieces,
- 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(
- LO, P.asRange(),
- *P.asLocation().getExpansionLoc().getFileEntry(),
- SMgr, Artifacts),
- Piece->getString()),
- calculateImportance(*Piece)));
- }
- return json::Object{{"locations", std::move(Locations)}};
-}
-
-static json::Object createCodeFlow(const LangOptions &LO,
- const PathPieces &Pieces,
- json::Array &Artifacts) {
- return json::Object{
- {"threadFlows", json::Array{createThreadFlow(LO, Pieces, Artifacts)}}};
-}
-
-static json::Object createResult(const LangOptions &LO,
- 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.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(LO, Path, Artifacts)}},
- {"locations",
- json::Array{createLocation(createPhysicalLocation(
- LO, Diag.getLocation().asRange(),
- *Diag.getLocation().asLocation().getExpansionLoc().getFileEntry(),
- SMgr, Artifacts))}},
- {"ruleIndex", Iter->getValue()},
- {"ruleId", Diag.getCheckerName()}};
-}
-
static StringRef getRuleDescription(StringRef CheckName) {
return llvm::StringSwitch<StringRef>(CheckName)
#define GET_CHECKERS
@@ -322,60 +88,99 @@ static StringRef getRuleHelpURIStr(StringRef CheckName) {
;
}
-static json::Object createRule(const PathDiagnostic &Diag) {
- StringRef CheckName = Diag.getCheckerName();
- json::Object Ret{
- {"fullDescription", createMessage(getRuleDescription(CheckName))},
- {"name", CheckName},
- {"id", CheckName}};
-
- std::string RuleURI = std::string(getRuleHelpURIStr(CheckName));
- if (!RuleURI.empty())
- Ret["helpUri"] = RuleURI;
-
- return Ret;
+static ThreadFlowImportance
+calculateImportance(const PathDiagnosticPiece &Piece) {
+ switch (Piece.getKind()) {
+ case PathDiagnosticPiece::Call:
+ case PathDiagnosticPiece::Macro:
+ case PathDiagnosticPiece::Note:
+ case PathDiagnosticPiece::PopUp:
+ // FIXME: What should be reported here?
+ break;
+ case PathDiagnosticPiece::Event:
+ return Piece.getTagStr() == "ConditionBRVisitor"
+ ? ThreadFlowImportance::Important
+ : ThreadFlowImportance::Essential;
+ case PathDiagnosticPiece::ControlFlow:
+ return ThreadFlowImportance::Unimportant;
+ }
+ return ThreadFlowImportance::Unimportant;
+}
+
+/// Accepts a SourceRange corresponding to a pair of the first and last tokens
+/// and converts to a Character granular CharSourceRange.
+static CharSourceRange convertTokenRangeToCharRange(const SourceRange &R,
+ const SourceManager &SM,
+ const LangOptions &LO) {
+ // Caret diagnostics have the first and last locations pointed at the same
+ // location, return these as-is.
+ if (R.getBegin() == R.getEnd())
+ return CharSourceRange::getCharRange(R);
+
+ SourceLocation BeginCharLoc = R.getBegin();
+ // For token ranges, the raw end SLoc points at the first character of the
+ // last token in the range. This must be moved to one past the end of the
+ // last character using the lexer.
+ SourceLocation EndCharLoc =
+ Lexer::getLocForEndOfToken(R.getEnd(), /* Offset = */ 0, SM, LO);
+ return CharSourceRange::getCharRange(BeginCharLoc, EndCharLoc);
+}
+
+static SmallVector<ThreadFlow, 8> createThreadFlows(const PathDiagnostic *Diag,
+ const LangOptions &LO) {
+ SmallVector<ThreadFlow, 8> Flows;
+ const PathPieces &Pieces = Diag->path.flatten(false);
+ for (const auto &Piece : Pieces) {
+ auto Range = convertTokenRangeToCharRange(
+ Piece->getLocation().asRange(), Piece->getLocation().getManager(), LO);
+ auto Flow = ThreadFlow::create()
+ .setImportance(calculateImportance(*Piece))
+ .setRange(Range)
+ .setMessage(Piece->getString());
+ Flows.push_back(Flow);
+ }
+ return Flows;
}
-static json::Array createRules(std::vector<const PathDiagnostic *> &Diags,
- StringMap<unsigned> &RuleMapping) {
- json::Array Rules;
+static StringMap<uint32_t>
+createRuleMapping(const std::vector<const PathDiagnostic *> &Diags,
+ SarifDocumentWriter &SarifWriter) {
+ StringMap<uint32_t> RuleMapping;
llvm::StringSet<> Seen;
for (const PathDiagnostic *D : Diags) {
- StringRef RuleID = D->getCheckerName();
- std::pair<llvm::StringSet<>::iterator, bool> P = Seen.insert(RuleID);
+ StringRef CheckName = D->getCheckerName();
+ std::pair<llvm::StringSet<>::iterator, bool> P = Seen.insert(CheckName);
if (P.second) {
- RuleMapping[RuleID] = Rules.size(); // Maps RuleID to an Array Index.
- Rules.push_back(createRule(*D));
+ auto Rule = SarifRule::create()
+ .setName(CheckName)
+ .setRuleId(CheckName)
+ .setDescription(getRuleDescription(CheckName))
+ .setHelpURI(getRuleHelpURIStr(CheckName));
+ size_t RuleIdx = SarifWriter.createRule(Rule);
+ RuleMapping[CheckName] = RuleIdx;
}
}
-
- return Rules;
+ return 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(const LangOptions &LO,
- std::vector<const PathDiagnostic *> &Diags) {
- json::Array Results, Artifacts;
- StringMap<unsigned> RuleMapping;
- json::Object Tool = createTool(Diags, RuleMapping);
+static SarifResult createResult(const PathDiagnostic *Diag,
+ const StringMap<uint32_t> &RuleMapping,
+ const LangOptions &LO) {
- for (const PathDiagnostic *D : Diags)
- Results.push_back(createResult(LO, *D, Artifacts, RuleMapping));
+ StringRef CheckName = Diag->getCheckerName();
+ uint32_t RuleIdx = RuleMapping.lookup(CheckName);
+ auto Range = convertTokenRangeToCharRange(
+ Diag->getLocation().asRange(), Diag->getLocation().getManager(), LO);
- return json::Object{{"tool", std::move(Tool)},
- {"results", std::move(Results)},
- {"artifacts", std::move(Artifacts)},
- {"columnKind", "unicodeCodePoints"}};
+ SmallVector<ThreadFlow, 8> Flows = createThreadFlows(Diag, LO);
+ auto Result = SarifResult::create(RuleIdx)
+ .setRuleId(CheckName)
+ .setDiagnosticMessage(Diag->getVerboseDescription())
+ .setDiagnosticLevel(SarifResultLevel::Warning)
+ .setLocations({Range})
+ .setThreadFlows(Flows);
+ return Result;
}
void SarifDiagnostics::FlushDiagnosticsImpl(
@@ -391,10 +196,14 @@ void SarifDiagnostics::FlushDiagnosticsImpl(
llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
return;
}
- json::Object Sarif{
- {"$schema",
- "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"},
- {"version", "2.1.0"},
- {"runs", json::Array{createRun(LO, Diags)}}};
- OS << llvm::formatv("{0:2}\n", json::Value(std::move(Sarif)));
+
+ std::string ToolVersion = getClangFullVersion();
+ SarifWriter.createRun("clang", "clang static analyzer", ToolVersion);
+ StringMap<uint32_t> RuleMapping = createRuleMapping(Diags, SarifWriter);
+ for (const PathDiagnostic *D : Diags) {
+ SarifResult Result = createResult(D, RuleMapping, LO);
+ SarifWriter.appendResult(Result);
+ }
+ auto Document = SarifWriter.createDocument();
+ OS << llvm::formatv("{0:2}\n", json::Value(std::move(Document)));
}
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index dcb6043e9df3..3286d7f468f0 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include <optional>
namespace clang {
@@ -26,7 +27,7 @@ ProgramStateRef SimpleConstraintManager::assumeInternal(ProgramStateRef State,
DefinedSVal Cond,
bool Assumption) {
// If we have a Loc value, cast it to a bool NonLoc first.
- if (Optional<Loc> LV = Cond.getAs<Loc>()) {
+ if (std::optional<Loc> LV = Cond.getAs<Loc>()) {
SValBuilder &SVB = State->getStateManager().getSValBuilder();
QualType T;
const MemRegion *MR = LV->getAsRegion();
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 762ecc18ecea..58d360a2e2db 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -348,9 +349,9 @@ static bool shouldRearrange(ProgramStateRef State, BinaryOperator::Opcode Op,
isWithinConstantOverflowBounds(Int)));
}
-static Optional<NonLoc> tryRearrange(ProgramStateRef State,
- BinaryOperator::Opcode Op, NonLoc Lhs,
- NonLoc Rhs, QualType ResultTy) {
+static std::optional<NonLoc> tryRearrange(ProgramStateRef State,
+ BinaryOperator::Opcode Op, NonLoc Lhs,
+ NonLoc Rhs, QualType ResultTy) {
ProgramStateManager &StateMgr = State->getStateManager();
SValBuilder &SVB = StateMgr.getSValBuilder();
@@ -361,35 +362,35 @@ static Optional<NonLoc> tryRearrange(ProgramStateRef State,
// rearrange additive operations but rearrange comparisons only if
// option is set.
if (!SVB.getAnalyzerOptions().ShouldAggressivelySimplifyBinaryOperation)
- return None;
+ return std::nullopt;
SymbolRef LSym = Lhs.getAsSymbol();
if (!LSym)
- return None;
+ return std::nullopt;
if (BinaryOperator::isComparisonOp(Op)) {
SingleTy = LSym->getType();
if (ResultTy != SVB.getConditionType())
- return None;
+ return std::nullopt;
// Initialize SingleTy later with a symbol's type.
} else if (BinaryOperator::isAdditiveOp(Op)) {
SingleTy = ResultTy;
if (LSym->getType() != SingleTy)
- return None;
+ return std::nullopt;
} else {
// Don't rearrange other operations.
- return None;
+ return std::nullopt;
}
assert(!SingleTy.isNull() && "We should have figured out the type by now!");
// Rearrange signed symbolic expressions only
if (!SingleTy->isSignedIntegerOrEnumerationType())
- return None;
+ return std::nullopt;
SymbolRef RSym = Rhs.getAsSymbol();
if (!RSym || RSym->getType() != SingleTy)
- return None;
+ return std::nullopt;
BasicValueFactory &BV = State->getBasicVals();
llvm::APSInt LInt, RInt;
@@ -397,7 +398,7 @@ static Optional<NonLoc> tryRearrange(ProgramStateRef State,
std::tie(RSym, RInt) = decomposeSymbol(RSym, BV);
if (!shouldRearrange(State, Op, LSym, LInt, SingleTy) ||
!shouldRearrange(State, Op, RSym, RInt, SingleTy))
- return None;
+ return std::nullopt;
// We know that no overflows can occur anymore.
return doRearrangeUnchecked(State, Op, LSym, LInt, RSym, RInt);
@@ -544,7 +545,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
case BO_LE:
case BO_GE:
op = BinaryOperator::reverseComparisonOp(op);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case BO_EQ:
case BO_NE:
case BO_Add:
@@ -558,7 +559,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
// (~0)>>a
if (LHSValue.isAllOnes() && LHSValue.isSigned())
return evalCast(lhs, resultTy, QualType{});
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case BO_Shl:
// 0<<a and 0>>a
if (LHSValue == 0)
@@ -570,7 +571,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
// 0 % x == 0
if (LHSValue == 0)
return makeZeroVal(resultTy);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return makeSymExprValNN(op, InputLHS, InputRHS, resultTy);
}
@@ -680,7 +681,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
if (const llvm::APSInt *RHSValue = getConstValue(state, rhs))
return MakeSymIntVal(Sym, op, *RHSValue, resultTy);
- if (Optional<NonLoc> V = tryRearrange(state, op, lhs, rhs, resultTy))
+ if (std::optional<NonLoc> V = tryRearrange(state, op, lhs, rhs, resultTy))
return *V;
// Give up -- this is not a symbolic expression we can handle.
@@ -843,7 +844,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
}
// If both operands are constants, just perform the operation.
- if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
+ if (std::optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
assert(BinaryOperator::isComparisonOp(op) || op == BO_Sub);
if (const auto *ResultInt =
@@ -877,7 +878,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
return UnknownVal();
}
case loc::MemRegionValKind: {
- if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
+ if (std::optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
// If one of the operands is a symbol and the other is a constant,
// build an expression for use by the constraint manager.
if (SymbolRef lSym = lhs.getAsLocSymbol(true)) {
@@ -974,7 +975,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// Get the left index and cast it to the correct type.
// If the index is unknown or undefined, bail out here.
SVal LeftIndexVal = LeftER->getIndex();
- Optional<NonLoc> LeftIndex = LeftIndexVal.getAs<NonLoc>();
+ std::optional<NonLoc> LeftIndex = LeftIndexVal.getAs<NonLoc>();
if (!LeftIndex)
return UnknownVal();
LeftIndexVal = evalCast(*LeftIndex, ArrayIndexTy, QualType{});
@@ -984,7 +985,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// Do the same for the right index.
SVal RightIndexVal = RightER->getIndex();
- Optional<NonLoc> RightIndex = RightIndexVal.getAs<NonLoc>();
+ std::optional<NonLoc> RightIndex = RightIndexVal.getAs<NonLoc>();
if (!RightIndex)
return UnknownVal();
RightIndexVal = evalCast(*RightIndex, ArrayIndexTy, QualType{});
@@ -1092,8 +1093,10 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// We are dealing with pointer arithmetic.
// Handle pointer arithmetic on constant values.
- if (Optional<nonloc::ConcreteInt> rhsInt = rhs.getAs<nonloc::ConcreteInt>()) {
- if (Optional<loc::ConcreteInt> lhsInt = lhs.getAs<loc::ConcreteInt>()) {
+ if (std::optional<nonloc::ConcreteInt> rhsInt =
+ rhs.getAs<nonloc::ConcreteInt>()) {
+ if (std::optional<loc::ConcreteInt> lhsInt =
+ lhs.getAs<loc::ConcreteInt>()) {
const llvm::APSInt &leftI = lhsInt->getValue();
assert(leftI.isUnsigned());
llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true);
@@ -1157,7 +1160,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
if (elementType->isVoidType())
elementType = getContext().CharTy;
- if (Optional<NonLoc> indexV = index.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> indexV = index.getAs<NonLoc>()) {
return loc::MemRegionVal(MemMgr.getElementRegion(elementType, *indexV,
superR, getContext()));
}
@@ -1170,10 +1173,10 @@ const llvm::APSInt *SimpleSValBuilder::getConstValue(ProgramStateRef state,
if (V.isUnknownOrUndef())
return nullptr;
- if (Optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>())
+ if (std::optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>())
return &X->getValue();
- if (Optional<nonloc::ConcreteInt> X = V.getAs<nonloc::ConcreteInt>())
+ if (std::optional<nonloc::ConcreteInt> X = V.getAs<nonloc::ConcreteInt>())
return &X->getValue();
if (SymbolRef Sym = V.getAsSymbol())
diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp
index 96e8878da616..fe1fa22af7ab 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -29,12 +29,12 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <cstdint>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -71,8 +71,8 @@ const ElementRegion *StoreManager::GetElementZeroRegion(const SubRegion *R,
return MRMgr.getElementRegion(T, idx, R, Ctx);
}
-Optional<const MemRegion *> StoreManager::castRegion(const MemRegion *R,
- QualType CastToTy) {
+std::optional<const MemRegion *> StoreManager::castRegion(const MemRegion *R,
+ QualType CastToTy) {
ASTContext &Ctx = StateMgr.getContext();
// Handle casts to Objective-C objects.
@@ -89,7 +89,7 @@ Optional<const MemRegion *> StoreManager::castRegion(const MemRegion *R,
// We don't know what to make of it. Return a NULL region, which
// will be interpreted as UnknownVal.
- return None;
+ return std::nullopt;
}
// Now assume we are casting from pointer to pointer. Other cases should
@@ -175,7 +175,7 @@ Optional<const MemRegion *> StoreManager::castRegion(const MemRegion *R,
// If we cannot compute a raw offset, throw up our hands and return
// a NULL MemRegion*.
if (!baseR)
- return None;
+ return std::nullopt;
CharUnits off = rawOff.getOffset();
@@ -314,7 +314,8 @@ static const CXXRecordDecl *getCXXRecordType(const MemRegion *MR) {
return nullptr;
}
-Optional<SVal> StoreManager::evalBaseToDerived(SVal Base, QualType TargetType) {
+std::optional<SVal> StoreManager::evalBaseToDerived(SVal Base,
+ QualType TargetType) {
const MemRegion *MR = Base.getAsRegion();
if (!MR)
return UnknownVal();
@@ -390,7 +391,7 @@ Optional<SVal> StoreManager::evalBaseToDerived(SVal Base, QualType TargetType) {
// We failed if the region we ended up with has perfect type info.
if (isa<TypedValueRegion>(MR))
- return None;
+ return std::nullopt;
return UnknownVal();
}
diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 2227bd324adc..3e97f0c95fc3 100644
--- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -411,10 +411,14 @@ void SymbolReaper::markLive(SymbolRef sym) {
}
void SymbolReaper::markLive(const MemRegion *region) {
- RegionRoots.insert(region->getBaseRegion());
+ LiveRegionRoots.insert(region->getBaseRegion());
markElementIndicesLive(region);
}
+void SymbolReaper::markLazilyCopied(const clang::ento::MemRegion *region) {
+ LazilyCopiedRegionRoots.insert(region->getBaseRegion());
+}
+
void SymbolReaper::markElementIndicesLive(const MemRegion *region) {
for (auto SR = dyn_cast<SubRegion>(region); SR;
SR = dyn_cast<SubRegion>(SR->getSuperRegion())) {
@@ -437,8 +441,7 @@ bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
// is not used later in the path, we can diagnose a leak of a value within
// that field earlier than, say, the variable that contains the field dies.
MR = MR->getBaseRegion();
-
- if (RegionRoots.count(MR))
+ if (LiveRegionRoots.count(MR))
return true;
if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
@@ -454,6 +457,15 @@ bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
return isa<AllocaRegion, CXXThisRegion, MemSpaceRegion, CodeTextRegion>(MR);
}
+bool SymbolReaper::isLazilyCopiedRegion(const MemRegion *MR) const {
+ // TODO: See comment in isLiveRegion.
+ return LazilyCopiedRegionRoots.count(MR->getBaseRegion());
+}
+
+bool SymbolReaper::isReadableRegion(const MemRegion *MR) {
+ return isLiveRegion(MR) || isLazilyCopiedRegion(MR);
+}
+
bool SymbolReaper::isLive(SymbolRef sym) {
if (TheLiving.count(sym)) {
markDependentsLive(sym);
@@ -464,7 +476,7 @@ bool SymbolReaper::isLive(SymbolRef sym) {
switch (sym->getKind()) {
case SymExpr::SymbolRegionValueKind:
- KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
+ KnownLive = isReadableRegion(cast<SymbolRegionValue>(sym)->getRegion());
break;
case SymExpr::SymbolConjuredKind:
KnownLive = false;
diff --git a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
index 48c82cfb82b2..05f4d19ebda0 100644
--- a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp
@@ -31,8 +31,8 @@ using namespace ento;
using namespace tooling;
namespace {
-/// Emitsd minimal diagnostics (report message + notes) for the 'none' output
-/// type to the standard error, or to to compliment many others. Emits detailed
+/// Emits minimal diagnostics (report message + notes) for the 'none' output
+/// type to the standard error, or to complement many others. Emits detailed
/// diagnostics in textual format for the 'text' output type.
class TextDiagnostics : public PathDiagnosticConsumer {
PathDiagnosticConsumerOptions DiagOpts;
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index ca0a66f54ced..54e0f4bee5eb 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -27,7 +27,6 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
index 9ee6ef4f9519..4618d17577dd 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -15,7 +15,6 @@
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DynamicLibrary.h"
diff --git a/clang/lib/Support/RISCVVIntrinsicUtils.cpp b/clang/lib/Support/RISCVVIntrinsicUtils.cpp
index 513e6376f5ae..25084dd98e5c 100644
--- a/clang/lib/Support/RISCVVIntrinsicUtils.cpp
+++ b/clang/lib/Support/RISCVVIntrinsicUtils.cpp
@@ -8,16 +8,15 @@
#include "clang/Support/RISCVVIntrinsicUtils.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <numeric>
-#include <set>
-#include <unordered_map>
+#include <optional>
using namespace llvm;
@@ -67,7 +66,7 @@ VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {
}
// Illegal vscale result would be less than 1
if (Log2ScaleResult < 0)
- return llvm::None;
+ return std::nullopt;
return 1 << Log2ScaleResult;
}
@@ -114,7 +113,7 @@ bool RVVType::verifyType() const {
return false;
if (isFloat() && ElementBitwidth == 8)
return false;
- unsigned V = Scale.value();
+ unsigned V = *Scale;
switch (ElementBitwidth) {
case 1:
case 8:
@@ -364,7 +363,8 @@ void RVVType::applyBasicType() {
assert(ElementBitwidth != 0 && "Bad element bitwidth!");
}
-Optional<PrototypeDescriptor> PrototypeDescriptor::parsePrototypeDescriptor(
+std::optional<PrototypeDescriptor>
+PrototypeDescriptor::parsePrototypeDescriptor(
llvm::StringRef PrototypeDescriptorStr) {
PrototypeDescriptor PD;
BaseTypeModifier PT = BaseTypeModifier::Invalid;
@@ -435,7 +435,7 @@ Optional<PrototypeDescriptor> PrototypeDescriptor::parsePrototypeDescriptor(
uint32_t Log2EEW;
if (ComplexTT.second.getAsInteger(10, Log2EEW)) {
llvm_unreachable("Invalid Log2EEW value!");
- return None;
+ return std::nullopt;
}
switch (Log2EEW) {
case 3:
@@ -452,13 +452,13 @@ Optional<PrototypeDescriptor> PrototypeDescriptor::parsePrototypeDescriptor(
break;
default:
llvm_unreachable("Invalid Log2EEW value, should be [3-6]");
- return None;
+ return std::nullopt;
}
} else if (ComplexTT.first == "FixedSEW") {
uint32_t NewSEW;
if (ComplexTT.second.getAsInteger(10, NewSEW)) {
llvm_unreachable("Invalid FixedSEW value!");
- return None;
+ return std::nullopt;
}
switch (NewSEW) {
case 8:
@@ -475,13 +475,13 @@ Optional<PrototypeDescriptor> PrototypeDescriptor::parsePrototypeDescriptor(
break;
default:
llvm_unreachable("Invalid FixedSEW value, should be 8, 16, 32 or 64");
- return None;
+ return std::nullopt;
}
} else if (ComplexTT.first == "LFixedLog2LMUL") {
int32_t Log2LMUL;
if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
llvm_unreachable("Invalid LFixedLog2LMUL value!");
- return None;
+ return std::nullopt;
}
switch (Log2LMUL) {
case -3:
@@ -507,13 +507,13 @@ Optional<PrototypeDescriptor> PrototypeDescriptor::parsePrototypeDescriptor(
break;
default:
llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
- return None;
+ return std::nullopt;
}
} else if (ComplexTT.first == "SFixedLog2LMUL") {
int32_t Log2LMUL;
if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {
llvm_unreachable("Invalid SFixedLog2LMUL value!");
- return None;
+ return std::nullopt;
}
switch (Log2LMUL) {
case -3:
@@ -539,7 +539,7 @@ Optional<PrototypeDescriptor> PrototypeDescriptor::parsePrototypeDescriptor(
break;
default:
llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");
- return None;
+ return std::nullopt;
}
} else {
@@ -785,20 +785,20 @@ void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {
Scale = LMUL.getScale(ElementBitwidth);
}
-Optional<RVVTypes>
-RVVType::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
- ArrayRef<PrototypeDescriptor> Prototype) {
+std::optional<RVVTypes>
+RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
+ ArrayRef<PrototypeDescriptor> Prototype) {
// LMUL x NF must be less than or equal to 8.
if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8)
- return llvm::None;
+ return std::nullopt;
RVVTypes Types;
for (const PrototypeDescriptor &Proto : Prototype) {
auto T = computeType(BT, Log2LMUL, Proto);
if (!T)
- return llvm::None;
+ return std::nullopt;
// Record legal type index
- Types.push_back(T.value());
+ Types.push_back(*T);
}
return Types;
}
@@ -816,11 +816,8 @@ static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,
((uint64_t)(Proto.VTM & 0xff) << 32);
}
-Optional<RVVTypePtr> RVVType::computeType(BasicType BT, int Log2LMUL,
- PrototypeDescriptor Proto) {
- // Concat BasicType, LMUL and Proto as key
- static std::unordered_map<uint64_t, RVVType> LegalTypes;
- static std::set<uint64_t> IllegalTypes;
+std::optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,
+ PrototypeDescriptor Proto) {
uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);
// Search first
auto It = LegalTypes.find(Idx);
@@ -828,34 +825,38 @@ Optional<RVVTypePtr> RVVType::computeType(BasicType BT, int Log2LMUL,
return &(It->second);
if (IllegalTypes.count(Idx))
- return llvm::None;
+ return std::nullopt;
// Compute type and record the result.
RVVType T(BT, Log2LMUL, Proto);
if (T.isValid()) {
// Record legal type index and value.
- LegalTypes.insert({Idx, T});
- return &(LegalTypes[Idx]);
+ std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>
+ InsertResult = LegalTypes.insert({Idx, T});
+ return &(InsertResult.first->second);
}
// Record illegal type index.
IllegalTypes.insert(Idx);
- return llvm::None;
+ return std::nullopt;
}
//===----------------------------------------------------------------------===//
// RVVIntrinsic implementation
//===----------------------------------------------------------------------===//
-RVVIntrinsic::RVVIntrinsic(
- StringRef NewName, StringRef Suffix, StringRef NewOverloadedName,
- StringRef OverloadedSuffix, StringRef IRName, bool IsMasked,
- bool HasMaskedOffOperand, bool HasVL, PolicyScheme Scheme,
- bool HasUnMaskedOverloaded, bool HasBuiltinAlias, StringRef ManualCodegen,
- const RVVTypes &OutInTypes, const std::vector<int64_t> &NewIntrinsicTypes,
- const std::vector<StringRef> &RequiredFeatures, unsigned NF)
- : IRName(IRName), IsMasked(IsMasked), HasVL(HasVL), Scheme(Scheme),
- HasUnMaskedOverloaded(HasUnMaskedOverloaded),
- HasBuiltinAlias(HasBuiltinAlias), ManualCodegen(ManualCodegen.str()),
- NF(NF) {
+RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
+ StringRef NewOverloadedName,
+ StringRef OverloadedSuffix, StringRef IRName,
+ bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
+ PolicyScheme Scheme, bool SupportOverloading,
+ bool HasBuiltinAlias, StringRef ManualCodegen,
+ const RVVTypes &OutInTypes,
+ const std::vector<int64_t> &NewIntrinsicTypes,
+ const std::vector<StringRef> &RequiredFeatures,
+ unsigned NF, Policy NewPolicyAttrs)
+ : IRName(IRName), IsMasked(IsMasked),
+ HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), Scheme(Scheme),
+ SupportOverloading(SupportOverloading), HasBuiltinAlias(HasBuiltinAlias),
+ ManualCodegen(ManualCodegen.str()), NF(NF), PolicyAttrs(NewPolicyAttrs) {
// Init BuiltinName, Name and OverloadedName
BuiltinName = NewName.str();
@@ -868,10 +869,9 @@ RVVIntrinsic::RVVIntrinsic(
Name += "_" + Suffix.str();
if (!OverloadedSuffix.empty())
OverloadedName += "_" + OverloadedSuffix.str();
- if (IsMasked) {
- BuiltinName += "_m";
- Name += "_m";
- }
+
+ updateNamesAndPolicy(IsMasked, hasPolicy(), Name, BuiltinName, OverloadedName,
+ PolicyAttrs);
// Init OutputType and InputTypes
OutputType = OutInTypes[0];
@@ -880,7 +880,7 @@ RVVIntrinsic::RVVIntrinsic(
// IntrinsicTypes is unmasked TA version index. Need to update it
// if there is merge operand (It is always in first operand).
IntrinsicTypes = NewIntrinsicTypes;
- if ((IsMasked && HasMaskedOffOperand) ||
+ if ((IsMasked && hasMaskedOffOperand()) ||
(!IsMasked && hasPassthruOperand())) {
for (auto &I : IntrinsicTypes) {
if (I >= 0)
@@ -899,36 +899,37 @@ std::string RVVIntrinsic::getBuiltinTypeStr() const {
}
std::string RVVIntrinsic::getSuffixStr(
- BasicType Type, int Log2LMUL,
+ RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {
SmallVector<std::string> SuffixStrs;
for (auto PD : PrototypeDescriptors) {
- auto T = RVVType::computeType(Type, Log2LMUL, PD);
+ auto T = TypeCache.computeType(Type, Log2LMUL, PD);
SuffixStrs.push_back((*T)->getShortStr());
}
return join(SuffixStrs, "_");
}
-llvm::SmallVector<PrototypeDescriptor>
-RVVIntrinsic::computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
- bool IsMasked, bool HasMaskedOffOperand,
- bool HasVL, unsigned NF) {
+llvm::SmallVector<PrototypeDescriptor> RVVIntrinsic::computeBuiltinTypes(
+ llvm::ArrayRef<PrototypeDescriptor> Prototype, bool IsMasked,
+ bool HasMaskedOffOperand, bool HasVL, unsigned NF,
+ PolicyScheme DefaultScheme, Policy PolicyAttrs) {
SmallVector<PrototypeDescriptor> NewPrototype(Prototype.begin(),
Prototype.end());
+ bool HasPassthruOp = DefaultScheme == PolicyScheme::HasPassthruOperand;
if (IsMasked) {
- // If HasMaskedOffOperand, insert result type as first input operand.
- if (HasMaskedOffOperand) {
+ // If HasMaskedOffOperand, insert result type as first input operand if
+ // need.
+ if (HasMaskedOffOperand && !PolicyAttrs.isTAMAPolicy()) {
if (NF == 1) {
NewPrototype.insert(NewPrototype.begin() + 1, NewPrototype[0]);
- } else {
+ } else if (NF > 1) {
// Convert
// (void, op0 address, op1 address, ...)
// to
// (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
PrototypeDescriptor MaskoffType = NewPrototype[1];
MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
- for (unsigned I = 0; I < NF; ++I)
- NewPrototype.insert(NewPrototype.begin() + NF + 1, MaskoffType);
+ NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
}
}
if (HasMaskedOffOperand && NF > 1) {
@@ -943,7 +944,21 @@ RVVIntrinsic::computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
// If IsMasked, insert PrototypeDescriptor:Mask as first input operand.
NewPrototype.insert(NewPrototype.begin() + 1, PrototypeDescriptor::Mask);
}
- }
+ } else {
+ if (NF == 1) {
+ if (PolicyAttrs.isTUPolicy() && HasPassthruOp)
+ NewPrototype.insert(NewPrototype.begin(), NewPrototype[0]);
+ } else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {
+ // NF > 1 cases for segment load operations.
+ // Convert
+ // (void, op0 address, op1 address, ...)
+ // to
+ // (void, op0 address, op1 address, maskedoff0, maskedoff1, ...)
+ PrototypeDescriptor MaskoffType = Prototype[1];
+ MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
+ NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);
+ }
+ }
// If HasVL, append PrototypeDescriptor:VL to last operand
if (HasVL)
@@ -951,6 +966,99 @@ RVVIntrinsic::computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
return NewPrototype;
}
+llvm::SmallVector<Policy>
+RVVIntrinsic::getSupportedUnMaskedPolicies(bool HasTailPolicy,
+ bool HasMaskPolicy) {
+ return {
+ Policy(Policy::PolicyType::Undisturbed, HasTailPolicy,
+ HasMaskPolicy), // TU
+ Policy(Policy::PolicyType::Agnostic, HasTailPolicy, HasMaskPolicy)}; // TA
+}
+
+llvm::SmallVector<Policy>
+RVVIntrinsic::getSupportedMaskedPolicies(bool HasTailPolicy,
+ bool HasMaskPolicy) {
+ if (HasTailPolicy && HasMaskPolicy)
+ return {
+ Policy(Policy::PolicyType::Undisturbed, Policy::PolicyType::Agnostic,
+ HasTailPolicy, HasMaskPolicy), // TUMA
+ Policy(Policy::PolicyType::Agnostic, Policy::PolicyType::Agnostic,
+ HasTailPolicy, HasMaskPolicy), // TAMA
+ Policy(Policy::PolicyType::Undisturbed, Policy::PolicyType::Undisturbed,
+ HasTailPolicy, HasMaskPolicy), // TUMU
+ Policy(Policy::PolicyType::Agnostic, Policy::PolicyType::Undisturbed,
+ HasTailPolicy, HasMaskPolicy)}; // TAMU
+ if (HasTailPolicy && !HasMaskPolicy)
+ return {Policy(Policy::PolicyType::Undisturbed,
+ Policy::PolicyType::Agnostic, HasTailPolicy,
+ HasMaskPolicy), // TUM
+ Policy(Policy::PolicyType::Agnostic, Policy::PolicyType::Agnostic,
+ HasTailPolicy, HasMaskPolicy)}; // TAM
+ if (!HasTailPolicy && HasMaskPolicy)
+ return {Policy(Policy::PolicyType::Agnostic, Policy::PolicyType::Agnostic,
+ HasTailPolicy, HasMaskPolicy), // MA
+ Policy(Policy::PolicyType::Agnostic,
+ Policy::PolicyType::Undisturbed, HasTailPolicy,
+ HasMaskPolicy)}; // MU
+ llvm_unreachable("An RVV instruction should not be without both tail policy "
+ "and mask policy");
+}
+
+void RVVIntrinsic::updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
+ std::string &Name,
+ std::string &BuiltinName,
+ std::string &OverloadedName,
+ Policy &PolicyAttrs) {
+
+ auto appendPolicySuffix = [&](const std::string &suffix) {
+ Name += suffix;
+ BuiltinName += suffix;
+ OverloadedName += suffix;
+ };
+
+ if (PolicyAttrs.isUnspecified()) {
+ PolicyAttrs.IsUnspecified = false;
+ if (IsMasked) {
+ Name += "_m";
+ if (HasPolicy)
+ BuiltinName += "_tama";
+ else
+ BuiltinName += "_m";
+ } else {
+ if (HasPolicy)
+ BuiltinName += "_ta";
+ }
+ } else {
+ if (IsMasked) {
+ if (PolicyAttrs.isTUMAPolicy() && !PolicyAttrs.hasMaskPolicy())
+ appendPolicySuffix("_tum");
+ else if (PolicyAttrs.isTAMAPolicy() && !PolicyAttrs.hasMaskPolicy())
+ appendPolicySuffix("_tam");
+ else if (PolicyAttrs.isMUPolicy() && !PolicyAttrs.hasTailPolicy())
+ appendPolicySuffix("_mu");
+ else if (PolicyAttrs.isMAPolicy() && !PolicyAttrs.hasTailPolicy())
+ appendPolicySuffix("_ma");
+ else if (PolicyAttrs.isTUMUPolicy())
+ appendPolicySuffix("_tumu");
+ else if (PolicyAttrs.isTAMUPolicy())
+ appendPolicySuffix("_tamu");
+ else if (PolicyAttrs.isTUMAPolicy())
+ appendPolicySuffix("_tuma");
+ else if (PolicyAttrs.isTAMAPolicy())
+ appendPolicySuffix("_tama");
+ else
+ llvm_unreachable("Unhandled policy condition");
+ } else {
+ if (PolicyAttrs.isTUPolicy())
+ appendPolicySuffix("_tu");
+ else if (PolicyAttrs.isTAPolicy())
+ appendPolicySuffix("_ta");
+ else
+ llvm_unreachable("Unhandled policy condition");
+ }
+ }
+}
+
SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {
SmallVector<PrototypeDescriptor> PrototypeDescriptors;
const StringRef Primaries("evwqom0ztul");
@@ -993,6 +1101,10 @@ raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
OS << (int)Record.HasMasked << ",";
OS << (int)Record.HasVL << ",";
OS << (int)Record.HasMaskedOffOperand << ",";
+ OS << (int)Record.HasTailPolicy << ",";
+ OS << (int)Record.HasMaskPolicy << ",";
+ OS << (int)Record.UnMaskedPolicyScheme << ",";
+ OS << (int)Record.MaskedPolicyScheme << ",";
OS << "},\n";
return OS;
}
diff --git a/clang/lib/Testing/TestAST.cpp b/clang/lib/Testing/TestAST.cpp
index 5817230f4b09..8c79fcd7d636 100644
--- a/clang/lib/Testing/TestAST.cpp
+++ b/clang/lib/Testing/TestAST.cpp
@@ -114,7 +114,8 @@ TestAST::TestAST(const TestInputs &In) {
// Running the FrontendAction creates the other components: SourceManager,
// Preprocessor, ASTContext, Sema. Preprocessor needs TargetInfo to be set.
EXPECT_TRUE(Clang->createTarget());
- Action = std::make_unique<SyntaxOnlyAction>();
+ Action =
+ In.MakeAction ? In.MakeAction() : std::make_unique<SyntaxOnlyAction>();
const FrontendInputFile &Main = Clang->getFrontendOpts().Inputs.front();
if (!Action->BeginSourceFile(*Clang, Main)) {
ADD_FAILURE() << "Failed to BeginSourceFile()";
diff --git a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
index 0821863adcc6..52e57976ac09 100644
--- a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
+++ b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -19,6 +19,7 @@
#include <limits>
#include <memory>
+#include <optional>
#include <unordered_set>
using namespace llvm;
@@ -117,13 +118,11 @@ public:
Impl(SyntaxTree *Parent, Stmt *N, ASTContext &AST);
template <class T>
Impl(SyntaxTree *Parent,
- std::enable_if_t<std::is_base_of<Stmt, T>::value, T> *Node,
- ASTContext &AST)
+ std::enable_if_t<std::is_base_of_v<Stmt, T>, T> *Node, ASTContext &AST)
: Impl(Parent, dyn_cast<Stmt>(Node), AST) {}
template <class T>
Impl(SyntaxTree *Parent,
- std::enable_if_t<std::is_base_of<Decl, T>::value, T> *Node,
- ASTContext &AST)
+ std::enable_if_t<std::is_base_of_v<Decl, T>, T> *Node, ASTContext &AST)
: Impl(Parent, dyn_cast<Decl>(Node), AST) {}
SyntaxTree *Parent;
@@ -688,20 +687,20 @@ ASTNodeKind Node::getType() const { return ASTNode.getNodeKind(); }
StringRef Node::getTypeLabel() const { return getType().asStringRef(); }
-llvm::Optional<std::string> Node::getQualifiedIdentifier() const {
+std::optional<std::string> Node::getQualifiedIdentifier() const {
if (auto *ND = ASTNode.get<NamedDecl>()) {
if (ND->getDeclName().isIdentifier())
return ND->getQualifiedNameAsString();
}
- return llvm::None;
+ return std::nullopt;
}
-llvm::Optional<StringRef> Node::getIdentifier() const {
+std::optional<StringRef> Node::getIdentifier() const {
if (auto *ND = ASTNode.get<NamedDecl>()) {
if (ND->getDeclName().isIdentifier())
return ND->getName();
}
- return llvm::None;
+ return std::nullopt;
}
namespace {
diff --git a/clang/lib/Tooling/AllTUsExecution.cpp b/clang/lib/Tooling/AllTUsExecution.cpp
index 5565da9b548a..f327d0139941 100644
--- a/clang/lib/Tooling/AllTUsExecution.cpp
+++ b/clang/lib/Tooling/AllTUsExecution.cpp
@@ -121,7 +121,7 @@ llvm::Error AllTUsToolExecutor::execute(
[&](std::string Path) {
Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
"] Processing file " + Path);
- // Each thread gets an indepent copy of a VFS to allow different
+ // Each thread gets an independent copy of a VFS to allow different
// concurrent working directories.
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
llvm::vfs::createPhysicalFileSystem();
diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp
index 7f5dc4d62f11..e40df6257378 100644
--- a/clang/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp
@@ -122,7 +122,7 @@ ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra,
CommandLineArguments::iterator I;
if (Pos == ArgumentInsertPosition::END) {
- I = std::find(Return.begin(), Return.end(), "--");
+ I = llvm::find(Return, "--");
} else {
I = Return.begin();
++I; // To leave the program name in place
diff --git a/clang/lib/Tooling/CommonOptionsParser.cpp b/clang/lib/Tooling/CommonOptionsParser.cpp
index 7d48dd505464..59ef47cc0166 100644
--- a/clang/lib/Tooling/CommonOptionsParser.cpp
+++ b/clang/lib/Tooling/CommonOptionsParser.cpp
@@ -86,21 +86,21 @@ llvm::Error CommonOptionsParser::init(
static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
cl::Optional, cl::cat(Category),
- cl::sub(*cl::AllSubCommands));
+ cl::sub(cl::SubCommand::getAll()));
static cl::list<std::string> SourcePaths(
cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag,
- cl::cat(Category), cl::sub(*cl::AllSubCommands));
+ cl::cat(Category), cl::sub(cl::SubCommand::getAll()));
static cl::list<std::string> ArgsAfter(
"extra-arg",
cl::desc("Additional argument to append to the compiler command line"),
- cl::cat(Category), cl::sub(*cl::AllSubCommands));
+ cl::cat(Category), cl::sub(cl::SubCommand::getAll()));
static cl::list<std::string> ArgsBefore(
"extra-arg-before",
cl::desc("Additional argument to prepend to the compiler command line"),
- cl::cat(Category), cl::sub(*cl::AllSubCommands));
+ cl::cat(Category), cl::sub(cl::SubCommand::getAll()));
cl::ResetAllOptionOccurrences();
diff --git a/clang/lib/Tooling/Core/Replacement.cpp b/clang/lib/Tooling/Core/Replacement.cpp
index aca2afceea44..020ad08a65e7 100644
--- a/clang/lib/Tooling/Core/Replacement.cpp
+++ b/clang/lib/Tooling/Core/Replacement.cpp
@@ -270,7 +270,7 @@ llvm::Error Replacements::add(const Replacement &R) {
assert(R.getLength() == 0);
// `I` is also an insertion, `R` and `I` conflict.
if (I->getLength() == 0) {
- // Check if two insertions are order-indepedent: if inserting them in
+ // Check if two insertions are order-independent: if inserting them in
// either order produces the same text, they are order-independent.
if ((R.getReplacementText() + I->getReplacementText()).str() !=
(I->getReplacementText() + R.getReplacementText()).str())
@@ -319,7 +319,7 @@ llvm::Error Replacements::add(const Replacement &R) {
Replaces.insert(R);
} else {
// `I` overlaps with `R`. We need to check `R` against all overlapping
- // replacements to see if they are order-indepedent. If they are, merge `R`
+ // replacements to see if they are order-independent. If they are, merge `R`
// with them and replace them with the merged replacements.
auto MergeBegin = I;
auto MergeEnd = std::next(I);
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
index 026bdfe03f28..97b41fc68917 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
@@ -10,6 +10,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SmallVectorMemoryBuffer.h"
#include "llvm/Support/Threading.h"
+#include <optional>
using namespace clang;
using namespace tooling;
@@ -67,7 +68,7 @@ EntryRef DependencyScanningWorkerFilesystem::scanForDirectivesIfNecessary(
Directives)) {
Contents->DepDirectiveTokens.clear();
// FIXME: Propagate the diagnostic if desired by the client.
- Contents->DepDirectives.store(new Optional<DependencyDirectivesTy>());
+ Contents->DepDirectives.store(new std::optional<DependencyDirectivesTy>());
return EntryRef(Filename, Entry);
}
@@ -76,7 +77,7 @@ EntryRef DependencyScanningWorkerFilesystem::scanForDirectivesIfNecessary(
// threads may skip the
// critical section (`DepDirectives != nullptr`), leading to a data race.
Contents->DepDirectives.store(
- new Optional<DependencyDirectivesTy>(std::move(Directives)));
+ new std::optional<DependencyDirectivesTy>(std::move(Directives)));
return EntryRef(Filename, Entry);
}
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
index cda3e2dd8550..6dccb3d131cd 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
@@ -14,10 +14,10 @@ using namespace tooling;
using namespace dependencies;
DependencyScanningService::DependencyScanningService(
- ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager,
- bool OptimizeArgs)
- : Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager),
- OptimizeArgs(OptimizeArgs) {
+ ScanningMode Mode, ScanningOutputFormat Format, bool OptimizeArgs,
+ bool EagerLoadModules)
+ : Mode(Mode), Format(Format), OptimizeArgs(OptimizeArgs),
+ EagerLoadModules(EagerLoadModules) {
// Initialize targets for object file support.
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 411fd9676ffd..3fcef00a5780 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -8,32 +8,18 @@
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "clang/Frontend/Utils.h"
+#include <optional>
using namespace clang;
using namespace tooling;
using namespace dependencies;
-std::vector<std::string> FullDependencies::getCommandLine(
- llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
- LookupModuleOutput) const {
- std::vector<std::string> Ret = getCommandLineWithoutModulePaths();
-
- for (ModuleID MID : ClangModuleDeps) {
- auto PCM = LookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
- Ret.push_back("-fmodule-file=" + PCM);
- }
-
- return Ret;
-}
-
-std::vector<std::string>
-FullDependencies::getCommandLineWithoutModulePaths() const {
+static std::vector<std::string>
+makeTUCommandLineWithoutPaths(ArrayRef<std::string> OriginalCommandLine) {
std::vector<std::string> Args = OriginalCommandLine;
Args.push_back("-fno-implicit-modules");
Args.push_back("-fno-implicit-module-maps");
- for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps)
- Args.push_back("-fmodule-file=" + PMD.PCMFile);
// These arguments are unused in explicit compiles.
llvm::erase_if(Args, [](StringRef Arg) {
@@ -56,10 +42,12 @@ DependencyScanningTool::DependencyScanningTool(
llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
const std::vector<std::string> &CommandLine, StringRef CWD,
- llvm::Optional<StringRef> ModuleName) {
+ std::optional<StringRef> ModuleName) {
/// Prints out all of the gathered dependencies into a string.
class MakeDependencyPrinterConsumer : public DependencyConsumer {
public:
+ void handleBuildCommand(Command) override {}
+
void
handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
@@ -81,6 +69,11 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
void handleContextHash(std::string Hash) override {}
+ std::string lookupModuleOutput(const ModuleID &ID,
+ ModuleOutputKind Kind) override {
+ llvm::report_fatal_error("unexpected call to lookupModuleOutput");
+ }
+
void printDependencies(std::string &S) {
assert(Opts && "Handled dependency output options.");
@@ -122,77 +115,98 @@ llvm::Expected<FullDependenciesResult>
DependencyScanningTool::getFullDependencies(
const std::vector<std::string> &CommandLine, StringRef CWD,
const llvm::StringSet<> &AlreadySeen,
- llvm::Optional<StringRef> ModuleName) {
- class FullDependencyPrinterConsumer : public DependencyConsumer {
- public:
- FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen)
- : AlreadySeen(AlreadySeen) {}
-
- void
- handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {}
-
- void handleFileDependency(StringRef File) override {
- Dependencies.push_back(std::string(File));
- }
+ LookupModuleOutputCallback LookupModuleOutput,
+ std::optional<StringRef> ModuleName) {
+ FullDependencyConsumer Consumer(AlreadySeen, LookupModuleOutput,
+ Worker.shouldEagerLoadModules());
+ llvm::Error Result =
+ Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
+ if (Result)
+ return std::move(Result);
+ return Consumer.takeFullDependencies();
+}
- void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
- PrebuiltModuleDeps.emplace_back(std::move(PMD));
- }
+llvm::Expected<FullDependenciesResult>
+DependencyScanningTool::getFullDependenciesLegacyDriverCommand(
+ const std::vector<std::string> &CommandLine, StringRef CWD,
+ const llvm::StringSet<> &AlreadySeen,
+ LookupModuleOutputCallback LookupModuleOutput,
+ std::optional<StringRef> ModuleName) {
+ FullDependencyConsumer Consumer(AlreadySeen, LookupModuleOutput,
+ Worker.shouldEagerLoadModules());
+ llvm::Error Result =
+ Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
+ if (Result)
+ return std::move(Result);
+ return Consumer.getFullDependenciesLegacyDriverCommand(CommandLine);
+}
- void handleModuleDependency(ModuleDeps MD) override {
- ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD);
- }
+FullDependenciesResult FullDependencyConsumer::takeFullDependencies() {
+ FullDependenciesResult FDR;
+ FullDependencies &FD = FDR.FullDeps;
+
+ FD.ID.ContextHash = std::move(ContextHash);
+ FD.FileDeps = std::move(Dependencies);
+ FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
+ FD.Commands = std::move(Commands);
+
+ for (auto &&M : ClangModuleDeps) {
+ auto &MD = M.second;
+ if (MD.ImportedByMainFile)
+ FD.ClangModuleDeps.push_back(MD.ID);
+ // TODO: Avoid handleModuleDependency even being called for modules
+ // we've already seen.
+ if (AlreadySeen.count(M.first))
+ continue;
+ FDR.DiscoveredModules.push_back(std::move(MD));
+ }
- void handleContextHash(std::string Hash) override {
- ContextHash = std::move(Hash);
- }
+ return FDR;
+}
- FullDependenciesResult getFullDependencies(
- const std::vector<std::string> &OriginalCommandLine) const {
- FullDependencies FD;
+FullDependenciesResult
+FullDependencyConsumer::getFullDependenciesLegacyDriverCommand(
+ const std::vector<std::string> &OriginalCommandLine) const {
+ FullDependencies FD;
- FD.OriginalCommandLine =
- ArrayRef<std::string>(OriginalCommandLine).slice(1);
+ FD.DriverCommandLine = makeTUCommandLineWithoutPaths(
+ ArrayRef<std::string>(OriginalCommandLine).slice(1));
- FD.ID.ContextHash = std::move(ContextHash);
+ FD.ID.ContextHash = std::move(ContextHash);
- FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
+ FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
- for (auto &&M : ClangModuleDeps) {
- auto &MD = M.second;
- if (MD.ImportedByMainFile)
- FD.ClangModuleDeps.push_back(MD.ID);
+ for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps)
+ FD.DriverCommandLine.push_back("-fmodule-file=" + PMD.PCMFile);
+
+ for (auto &&M : ClangModuleDeps) {
+ auto &MD = M.second;
+ if (MD.ImportedByMainFile) {
+ FD.ClangModuleDeps.push_back(MD.ID);
+ auto PCMPath = LookupModuleOutput(MD.ID, ModuleOutputKind::ModuleFile);
+ if (EagerLoadModules) {
+ FD.DriverCommandLine.push_back("-fmodule-file=" + PCMPath);
+ } else {
+ FD.DriverCommandLine.push_back("-fmodule-map-file=" +
+ MD.ClangModuleMapFile);
+ FD.DriverCommandLine.push_back("-fmodule-file=" + MD.ID.ModuleName +
+ "=" + PCMPath);
}
+ }
+ }
- FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
-
- FullDependenciesResult FDR;
-
- for (auto &&M : ClangModuleDeps) {
- // TODO: Avoid handleModuleDependency even being called for modules
- // we've already seen.
- if (AlreadySeen.count(M.first))
- continue;
- FDR.DiscoveredModules.push_back(std::move(M.second));
- }
+ FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
- FDR.FullDeps = std::move(FD);
- return FDR;
- }
+ FullDependenciesResult FDR;
- private:
- std::vector<std::string> Dependencies;
- std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
- llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>> ClangModuleDeps;
- std::string ContextHash;
- std::vector<std::string> OutputPaths;
- const llvm::StringSet<> &AlreadySeen;
- };
+ for (auto &&M : ClangModuleDeps) {
+ // TODO: Avoid handleModuleDependency even being called for modules
+ // we've already seen.
+ if (AlreadySeen.count(M.first))
+ continue;
+ FDR.DiscoveredModules.push_back(std::move(M.second));
+ }
- FullDependencyPrinterConsumer Consumer(AlreadySeen);
- llvm::Error Result =
- Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
- if (Result)
- return std::move(Result);
- return Consumer.getFullDependencies(CommandLine);
+ FDR.FullDeps = std::move(FD);
+ return FDR;
}
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 474808d888ec..b54b8de9157e 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -7,7 +7,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
@@ -17,6 +22,8 @@
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Host.h"
+#include <optional>
using namespace clang;
using namespace tooling;
@@ -28,8 +35,9 @@ namespace {
class DependencyConsumerForwarder : public DependencyFileGenerator {
public:
DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
- DependencyConsumer &C)
- : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), C(C) {}
+ StringRef WorkingDirectory, DependencyConsumer &C)
+ : DependencyFileGenerator(*Opts), WorkingDirectory(WorkingDirectory),
+ Opts(std::move(Opts)), C(C) {}
void finishedMainFile(DiagnosticsEngine &Diags) override {
C.handleDependencyOutputOpts(*Opts);
@@ -37,11 +45,13 @@ public:
for (const auto &File : getDependencies()) {
CanonPath = File;
llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
+ llvm::sys::fs::make_absolute(WorkingDirectory, CanonPath);
C.handleFileDependency(CanonPath);
}
}
private:
+ StringRef WorkingDirectory;
std::unique_ptr<DependencyOutputOptions> Opts;
DependencyConsumer &C;
};
@@ -94,7 +104,7 @@ static void visitPrebuiltModule(StringRef PrebuiltModuleFilename,
while (!Worklist.empty())
ASTReader::readASTFileControlBlock(
- Worklist.pop_back_val(), CI.getFileManager(),
+ Worklist.pop_back_val(), CI.getFileManager(), CI.getModuleCache(),
CI.getPCHContainerReader(),
/*FindModuleFileExtensions=*/false, Listener,
/*ValidateDiagnosticOptions=*/false);
@@ -126,8 +136,8 @@ static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) {
DiagOpts.ShowCarets = false;
// Don't write out diagnostic file.
DiagOpts.DiagnosticSerializationFile.clear();
- // Don't treat warnings as errors.
- DiagOpts.Warnings.push_back("no-error");
+ // Don't emit warnings as errors (and all other warnings too).
+ DiagOpts.IgnoreWarnings = true;
}
/// A clang tool that runs the preprocessor in a mode that's optimized for
@@ -137,11 +147,12 @@ public:
DependencyScanningAction(
StringRef WorkingDirectory, DependencyConsumer &Consumer,
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
- ScanningOutputFormat Format, bool OptimizeArgs, bool DisableFree,
- llvm::Optional<StringRef> ModuleName = None)
+ ScanningOutputFormat Format, bool OptimizeArgs, bool EagerLoadModules,
+ bool DisableFree, std::optional<StringRef> ModuleName = std::nullopt)
: WorkingDirectory(WorkingDirectory), Consumer(Consumer),
DepFS(std::move(DepFS)), Format(Format), OptimizeArgs(OptimizeArgs),
- DisableFree(DisableFree), ModuleName(ModuleName) {}
+ EagerLoadModules(EagerLoadModules), DisableFree(DisableFree),
+ ModuleName(ModuleName) {}
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
FileManager *FileMgr,
@@ -152,8 +163,20 @@ public:
// Restore the value of DisableFree, which may be modified by Tooling.
OriginalInvocation.getFrontendOpts().DisableFree = DisableFree;
+ if (Scanned) {
+ // Scanning runs once for the first -cc1 invocation in a chain of driver
+ // jobs. For any dependent jobs, reuse the scanning result and just
+ // update the LastCC1Arguments to correspond to the new invocation.
+ // FIXME: to support multi-arch builds, each arch requires a separate scan
+ setLastCC1Arguments(std::move(OriginalInvocation));
+ return true;
+ }
+
+ Scanned = true;
+
// Create a compiler instance to handle the actual work.
- CompilerInstance ScanInstance(std::move(PCHContainerOps));
+ ScanInstanceStorage.emplace(std::move(PCHContainerOps));
+ CompilerInstance &ScanInstance = *ScanInstanceStorage;
ScanInstance.setInvocation(std::move(Invocation));
// Create the compiler's actual diagnostics engine.
@@ -167,9 +190,14 @@ public:
ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false;
ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false;
+ ScanInstance.getFrontendOpts().ModulesShareFileManager = false;
- FileMgr->getFileSystemOpts().WorkingDir = std::string(WorkingDirectory);
ScanInstance.setFileManager(FileMgr);
+ // Support for virtual file system overlays.
+ FileMgr->setVirtualFileSystem(createVFSFromCompilerInvocation(
+ ScanInstance.getInvocation(), ScanInstance.getDiagnostics(),
+ FileMgr->getVirtualFileSystemPtr()));
+
ScanInstance.createSourceManager(*FileMgr);
llvm::StringSet<> PrebuiltModulesInputFiles;
@@ -184,20 +212,15 @@ public:
// Use the dependency scanning optimized file system if requested to do so.
if (DepFS) {
- // Support for virtual file system overlays on top of the caching
- // filesystem.
- FileMgr->setVirtualFileSystem(createVFSFromCompilerInvocation(
- ScanInstance.getInvocation(), ScanInstance.getDiagnostics(), DepFS));
-
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> LocalDepFS =
DepFS;
ScanInstance.getPreprocessorOpts().DependencyDirectivesForFile =
[LocalDepFS = std::move(LocalDepFS)](FileEntryRef File)
- -> Optional<ArrayRef<dependency_directives_scan::Directive>> {
+ -> std::optional<ArrayRef<dependency_directives_scan::Directive>> {
if (llvm::ErrorOr<EntryRef> Entry =
LocalDepFS->getOrCreateFileSystemEntry(File.getName()))
return Entry->getDirectiveTokens();
- return None;
+ return std::nullopt;
};
}
@@ -221,13 +244,14 @@ public:
switch (Format) {
case ScanningOutputFormat::Make:
ScanInstance.addDependencyCollector(
- std::make_shared<DependencyConsumerForwarder>(std::move(Opts),
- Consumer));
+ std::make_shared<DependencyConsumerForwarder>(
+ std::move(Opts), WorkingDirectory, Consumer));
break;
case ScanningOutputFormat::Full:
- ScanInstance.addDependencyCollector(std::make_shared<ModuleDepCollector>(
- std::move(Opts), ScanInstance, Consumer,
- std::move(OriginalInvocation), OptimizeArgs));
+ MDC = std::make_shared<ModuleDepCollector>(
+ std::move(Opts), ScanInstance, Consumer, OriginalInvocation,
+ OptimizeArgs, EagerLoadModules);
+ ScanInstance.addDependencyCollector(MDC);
break;
}
@@ -246,19 +270,44 @@ public:
Action = std::make_unique<ReadPCHAndPreprocessAction>();
const bool Result = ScanInstance.ExecuteAction(*Action);
- if (!DepFS)
- FileMgr->clearStatCache();
+
+ if (Result)
+ setLastCC1Arguments(std::move(OriginalInvocation));
+
return Result;
}
+ bool hasScanned() const { return Scanned; }
+
+ /// Take the cc1 arguments corresponding to the most recent invocation used
+ /// with this action. Any modifications implied by the discovered dependencies
+ /// will have already been applied.
+ std::vector<std::string> takeLastCC1Arguments() {
+ std::vector<std::string> Result;
+ std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty.
+ return Result;
+ }
+
+private:
+ void setLastCC1Arguments(CompilerInvocation &&CI) {
+ if (MDC)
+ MDC->applyDiscoveredDependencies(CI);
+ LastCC1Arguments = CI.getCC1CommandLine();
+ }
+
private:
StringRef WorkingDirectory;
DependencyConsumer &Consumer;
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
ScanningOutputFormat Format;
bool OptimizeArgs;
+ bool EagerLoadModules;
bool DisableFree;
- llvm::Optional<StringRef> ModuleName;
+ std::optional<StringRef> ModuleName;
+ std::optional<CompilerInstance> ScanInstanceStorage;
+ std::shared_ptr<ModuleDepCollector> MDC;
+ std::vector<std::string> LastCC1Arguments;
+ bool Scanned = false;
};
} // end anonymous namespace
@@ -266,7 +315,8 @@ private:
DependencyScanningWorker::DependencyScanningWorker(
DependencyScanningService &Service,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
- : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()) {
+ : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()),
+ EagerLoadModules(Service.shouldEagerLoadModules()) {
PCHContainerOps = std::make_shared<PCHContainerOperations>();
PCHContainerOps->registerReader(
std::make_unique<ObjectFilePCHContainerReader>());
@@ -275,80 +325,151 @@ DependencyScanningWorker::DependencyScanningWorker(
PCHContainerOps->registerWriter(
std::make_unique<ObjectFilePCHContainerWriter>());
- auto OverlayFS =
- llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(std::move(FS));
- InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
- OverlayFS->pushOverlay(InMemoryFS);
- RealFS = OverlayFS;
-
- if (Service.getMode() == ScanningMode::DependencyDirectivesScan)
- DepFS = new DependencyScanningWorkerFilesystem(Service.getSharedCache(),
- RealFS);
- if (Service.canReuseFileManager())
- Files = new FileManager(FileSystemOptions(), RealFS);
+ switch (Service.getMode()) {
+ case ScanningMode::DependencyDirectivesScan:
+ DepFS =
+ new DependencyScanningWorkerFilesystem(Service.getSharedCache(), FS);
+ BaseFS = DepFS;
+ break;
+ case ScanningMode::CanonicalPreprocessing:
+ DepFS = nullptr;
+ BaseFS = FS;
+ break;
+ }
}
-static llvm::Error
-runWithDiags(DiagnosticOptions *DiagOpts,
- llvm::function_ref<bool(DiagnosticConsumer &, DiagnosticOptions &)>
- BodyShouldSucceed) {
+llvm::Error DependencyScanningWorker::computeDependencies(
+ StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
+ DependencyConsumer &Consumer, std::optional<StringRef> ModuleName) {
+ std::vector<const char *> CLI;
+ for (const std::string &Arg : CommandLine)
+ CLI.push_back(Arg.c_str());
+ auto DiagOpts = CreateAndPopulateDiagOpts(CLI);
sanitizeDiagOpts(*DiagOpts);
// 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);
+ TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
- if (BodyShouldSucceed(DiagPrinter, *DiagOpts))
+ if (computeDependencies(WorkingDirectory, CommandLine, Consumer, DiagPrinter,
+ ModuleName))
return llvm::Error::success();
return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
llvm::inconvertibleErrorCode());
}
-llvm::Error DependencyScanningWorker::computeDependencies(
+static bool forEachDriverJob(
+ ArrayRef<std::string> Args, DiagnosticsEngine &Diags, FileManager &FM,
+ llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
+ std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
+ Args[0], llvm::sys::getDefaultTargetTriple(), Diags,
+ "clang LLVM compiler", &FM.getVirtualFileSystem());
+ Driver->setTitle("clang_based_tool");
+
+ std::vector<const char *> Argv;
+ for (const std::string &Arg : Args)
+ Argv.push_back(Arg.c_str());
+
+ const std::unique_ptr<driver::Compilation> Compilation(
+ Driver->BuildCompilation(llvm::ArrayRef(Argv)));
+ if (!Compilation)
+ return false;
+
+ for (const driver::Command &Job : Compilation->getJobs()) {
+ if (!Callback(Job))
+ return false;
+ }
+ return true;
+}
+
+bool DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
- DependencyConsumer &Consumer, llvm::Optional<StringRef> ModuleName) {
+ DependencyConsumer &Consumer, DiagnosticConsumer &DC,
+ std::optional<StringRef> ModuleName) {
// Reset what might have been modified in the previous worker invocation.
- RealFS->setCurrentWorkingDirectory(WorkingDirectory);
- if (Files)
- Files->setVirtualFileSystem(RealFS);
-
- llvm::IntrusiveRefCntPtr<FileManager> CurrentFiles =
- Files ? Files : new FileManager(FileSystemOptions(), RealFS);
+ BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
- Optional<std::vector<std::string>> ModifiedCommandLine;
+ std::optional<std::vector<std::string>> ModifiedCommandLine;
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> ModifiedFS;
if (ModuleName) {
ModifiedCommandLine = CommandLine;
- InMemoryFS->addFile(*ModuleName, 0, llvm::MemoryBuffer::getMemBuffer(""));
ModifiedCommandLine->emplace_back(*ModuleName);
+
+ auto OverlayFS =
+ llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(BaseFS);
+ auto InMemoryFS =
+ llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
+ InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
+ InMemoryFS->addFile(*ModuleName, 0, llvm::MemoryBuffer::getMemBuffer(""));
+ OverlayFS->pushOverlay(InMemoryFS);
+ ModifiedFS = OverlayFS;
}
const std::vector<std::string> &FinalCommandLine =
ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
+ FileSystemOptions FSOpts;
+ FSOpts.WorkingDir = WorkingDirectory.str();
+ auto FileMgr = llvm::makeIntrusiveRefCnt<FileManager>(
+ FSOpts, ModifiedFS ? ModifiedFS : BaseFS);
+
std::vector<const char *> FinalCCommandLine(CommandLine.size(), nullptr);
llvm::transform(CommandLine, FinalCCommandLine.begin(),
[](const std::string &Str) { return Str.c_str(); });
- return runWithDiags(CreateAndPopulateDiagOpts(FinalCCommandLine).release(),
- [&](DiagnosticConsumer &DC, DiagnosticOptions &DiagOpts) {
- // DisableFree is modified by Tooling for running
- // in-process; preserve the original value, which is
- // always true for a driver invocation.
- bool DisableFree = true;
- DependencyScanningAction Action(
- WorkingDirectory, Consumer, DepFS, Format,
- OptimizeArgs, DisableFree, ModuleName);
- // Create an invocation 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.
- ToolInvocation Invocation(FinalCommandLine, &Action,
- CurrentFiles.get(),
- PCHContainerOps);
- Invocation.setDiagnosticConsumer(&DC);
- Invocation.setDiagnosticOptions(&DiagOpts);
- return Invocation.run();
- });
+ auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine);
+ sanitizeDiagOpts(*DiagOpts);
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
+ CompilerInstance::createDiagnostics(DiagOpts.release(), &DC,
+ /*ShouldOwnClient=*/false);
+
+ // Although `Diagnostics` are used only for command-line parsing, the
+ // custom `DiagConsumer` might expect a `SourceManager` to be present.
+ SourceManager SrcMgr(*Diags, *FileMgr);
+ Diags->setSourceManager(&SrcMgr);
+ // DisableFree is modified by Tooling for running
+ // in-process; preserve the original value, which is
+ // always true for a driver invocation.
+ bool DisableFree = true;
+ DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, Format,
+ OptimizeArgs, EagerLoadModules, DisableFree,
+ ModuleName);
+ bool Success = forEachDriverJob(
+ FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) {
+ if (StringRef(Cmd.getCreator().getName()) != "clang") {
+ // Non-clang command. Just pass through to the dependency
+ // consumer.
+ Consumer.handleBuildCommand(
+ {Cmd.getExecutable(),
+ {Cmd.getArguments().begin(), Cmd.getArguments().end()}});
+ return true;
+ }
+
+ std::vector<std::string> Argv;
+ Argv.push_back(Cmd.getExecutable());
+ Argv.insert(Argv.end(), Cmd.getArguments().begin(),
+ Cmd.getArguments().end());
+
+ // Create an invocation 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.
+ ToolInvocation Invocation(std::move(Argv), &Action, &*FileMgr,
+ PCHContainerOps);
+ Invocation.setDiagnosticConsumer(Diags->getClient());
+ Invocation.setDiagnosticOptions(&Diags->getDiagnosticOptions());
+ if (!Invocation.run())
+ return false;
+
+ std::vector<std::string> Args = Action.takeLastCC1Arguments();
+ Consumer.handleBuildCommand({Cmd.getExecutable(), std::move(Args)});
+ return true;
+ });
+
+ if (Success && !Action.hasScanned())
+ Diags->Report(diag::err_fe_expected_compiler_job)
+ << llvm::join(FinalCommandLine, " ");
+ return Success && Action.hasScanned();
}
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index 725bb2c318ac..cb1c66b8d63f 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -12,7 +12,9 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+#include "llvm/Support/BLAKE3.h"
#include "llvm/Support/StringSaver.h"
+#include <optional>
using namespace clang;
using namespace tooling;
@@ -41,124 +43,260 @@ static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts,
Opts.UserEntries.push_back(Entries[Idx]);
}
-CompilerInvocation ModuleDepCollector::makeInvocationForModuleBuildWithoutPaths(
+static std::vector<std::string> splitString(std::string S, char Separator) {
+ SmallVector<StringRef> Segments;
+ StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ std::vector<std::string> Result;
+ Result.reserve(Segments.size());
+ for (StringRef Segment : Segments)
+ Result.push_back(Segment.str());
+ return Result;
+}
+
+void ModuleDepCollector::addOutputPaths(CompilerInvocation &CI,
+ ModuleDeps &Deps) {
+ CI.getFrontendOpts().OutputFile =
+ Consumer.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile);
+ if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
+ CI.getDiagnosticOpts().DiagnosticSerializationFile =
+ Consumer.lookupModuleOutput(
+ Deps.ID, ModuleOutputKind::DiagnosticSerializationFile);
+ if (!CI.getDependencyOutputOpts().OutputFile.empty()) {
+ CI.getDependencyOutputOpts().OutputFile =
+ Consumer.lookupModuleOutput(Deps.ID, ModuleOutputKind::DependencyFile);
+ CI.getDependencyOutputOpts().Targets =
+ splitString(Consumer.lookupModuleOutput(
+ Deps.ID, ModuleOutputKind::DependencyTargets),
+ '\0');
+ if (!CI.getDependencyOutputOpts().OutputFile.empty() &&
+ CI.getDependencyOutputOpts().Targets.empty()) {
+ // Fallback to -o as dependency target, as in the driver.
+ SmallString<128> Target;
+ quoteMakeTarget(CI.getFrontendOpts().OutputFile, Target);
+ CI.getDependencyOutputOpts().Targets.push_back(std::string(Target));
+ }
+ }
+}
+
+CompilerInvocation
+ModuleDepCollector::makeInvocationForModuleBuildWithoutOutputs(
const ModuleDeps &Deps,
llvm::function_ref<void(CompilerInvocation &)> Optimize) const {
// Make a deep copy of the original Clang invocation.
CompilerInvocation CI(OriginalInvocation);
- CI.getLangOpts()->resetNonModularOptions();
- CI.getPreprocessorOpts().resetNonModularOptions();
+ CI.resetNonModularOptions();
+ CI.clearImplicitModuleBuildOptions();
// Remove options incompatible with explicit module build or are likely to
// differ between identical modules discovered from different translation
// units.
CI.getFrontendOpts().Inputs.clear();
CI.getFrontendOpts().OutputFile.clear();
+
+ // TODO: Figure out better way to set options to their default value.
CI.getCodeGenOpts().MainFileName.clear();
CI.getCodeGenOpts().DwarfDebugFlags.clear();
- CI.getDiagnosticOpts().DiagnosticSerializationFile.clear();
- CI.getDependencyOutputOpts().OutputFile.clear();
+ if (!CI.getLangOpts()->ModulesCodegen) {
+ CI.getCodeGenOpts().DebugCompilationDir.clear();
+ CI.getCodeGenOpts().CoverageCompilationDir.clear();
+ }
+
+ // Map output paths that affect behaviour to "-" so their existence is in the
+ // context hash. The final path will be computed in addOutputPaths.
+ if (!CI.getDiagnosticOpts().DiagnosticSerializationFile.empty())
+ CI.getDiagnosticOpts().DiagnosticSerializationFile = "-";
+ if (!CI.getDependencyOutputOpts().OutputFile.empty())
+ CI.getDependencyOutputOpts().OutputFile = "-";
CI.getDependencyOutputOpts().Targets.clear();
CI.getFrontendOpts().ProgramAction = frontend::GenerateModule;
CI.getLangOpts()->ModuleName = Deps.ID.ModuleName;
CI.getFrontendOpts().IsSystemModule = Deps.IsSystem;
- // Disable implicit modules and canonicalize options that are only used by
- // implicit modules.
- CI.getLangOpts()->ImplicitModules = false;
- CI.getHeaderSearchOpts().ImplicitModuleMaps = false;
- CI.getHeaderSearchOpts().ModuleCachePath.clear();
- CI.getHeaderSearchOpts().ModulesValidateOncePerBuildSession = false;
- CI.getHeaderSearchOpts().BuildSessionTimestamp = 0;
- // The specific values we canonicalize to for pruning don't affect behaviour,
- /// so use the default values so they will be dropped from the command-line.
- CI.getHeaderSearchOpts().ModuleCachePruneInterval = 7 * 24 * 60 * 60;
- CI.getHeaderSearchOpts().ModuleCachePruneAfter = 31 * 24 * 60 * 60;
+ // Inputs
+ InputKind ModuleMapInputKind(CI.getFrontendOpts().DashX.getLanguage(),
+ InputKind::Format::ModuleMap);
+ CI.getFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile,
+ ModuleMapInputKind);
+
+ auto CurrentModuleMapEntry =
+ ScanInstance.getFileManager().getFile(Deps.ClangModuleMapFile);
+ assert(CurrentModuleMapEntry && "module map file entry not found");
+
+ auto DepModuleMapFiles = collectModuleMapFiles(Deps.ClangModuleDeps);
+ for (StringRef ModuleMapFile : Deps.ModuleMapFileDeps) {
+ // TODO: Track these as `FileEntryRef` to simplify the equality check below.
+ auto ModuleMapEntry = ScanInstance.getFileManager().getFile(ModuleMapFile);
+ assert(ModuleMapEntry && "module map file entry not found");
+
+ // Don't report module maps describing eagerly-loaded dependency. This
+ // information will be deserialized from the PCM.
+ // TODO: Verify this works fine when modulemap for module A is eagerly
+ // loaded from A.pcm, and module map passed on the command line contains
+ // definition of a submodule: "explicit module A.Private { ... }".
+ if (EagerLoadModules && DepModuleMapFiles.contains(*ModuleMapEntry))
+ continue;
+
+ // Don't report module map file of the current module unless it also
+ // describes a dependency (for symmetry).
+ if (*ModuleMapEntry == *CurrentModuleMapEntry &&
+ !DepModuleMapFiles.contains(*ModuleMapEntry))
+ continue;
+
+ CI.getFrontendOpts().ModuleMapFiles.emplace_back(ModuleMapFile);
+ }
// Report the prebuilt modules this module uses.
for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps)
CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile);
- CI.getFrontendOpts().ModuleMapFiles = Deps.ModuleMapFileDeps;
+ // Add module file inputs from dependencies.
+ addModuleFiles(CI, Deps.ClangModuleDeps);
+
+ // Remove any macro definitions that are explicitly ignored.
+ if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) {
+ llvm::erase_if(
+ CI.getPreprocessorOpts().Macros,
+ [&CI](const std::pair<std::string, bool> &Def) {
+ StringRef MacroDef = Def.first;
+ return CI.getHeaderSearchOpts().ModulesIgnoreMacros.contains(
+ llvm::CachedHashString(MacroDef.split('=').first));
+ });
+ // Remove the now unused option.
+ CI.getHeaderSearchOpts().ModulesIgnoreMacros.clear();
+ }
Optimize(CI);
- // The original invocation probably didn't have strict context hash enabled.
- // We will use the context hash of this invocation to distinguish between
- // multiple incompatible versions of the same module and will use it when
- // reporting dependencies to the clients. Let's make sure we're using
- // **strict** context hash in order to prevent accidental sharing of
- // incompatible modules (e.g. with differences in search paths).
- CI.getHeaderSearchOpts().ModulesStrictContextHash = true;
-
return CI;
}
-static std::vector<std::string>
-serializeCompilerInvocation(const CompilerInvocation &CI) {
- // Set up string allocator.
- llvm::BumpPtrAllocator Alloc;
- llvm::StringSaver Strings(Alloc);
- auto SA = [&Strings](const Twine &Arg) { return Strings.save(Arg).data(); };
+llvm::DenseSet<const FileEntry *> ModuleDepCollector::collectModuleMapFiles(
+ ArrayRef<ModuleID> ClangModuleDeps) const {
+ llvm::DenseSet<const FileEntry *> ModuleMapFiles;
+ for (const ModuleID &MID : ClangModuleDeps) {
+ ModuleDeps *MD = ModuleDepsByID.lookup(MID);
+ assert(MD && "Inconsistent dependency info");
+ // TODO: Track ClangModuleMapFile as `FileEntryRef`.
+ auto FE = ScanInstance.getFileManager().getFile(MD->ClangModuleMapFile);
+ assert(FE && "Missing module map file that was previously found");
+ ModuleMapFiles.insert(*FE);
+ }
+ return ModuleMapFiles;
+}
- // Synthesize full command line from the CompilerInvocation, including "-cc1".
- SmallVector<const char *, 32> Args{"-cc1"};
- CI.generateCC1CommandLine(Args, SA);
+void ModuleDepCollector::addModuleMapFiles(
+ CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
+ if (EagerLoadModules)
+ return; // Only pcm is needed for eager load.
- // Convert arguments to the return type.
- return std::vector<std::string>{Args.begin(), Args.end()};
+ for (const ModuleID &MID : ClangModuleDeps) {
+ ModuleDeps *MD = ModuleDepsByID.lookup(MID);
+ assert(MD && "Inconsistent dependency info");
+ CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile);
+ }
}
-static std::vector<std::string> splitString(std::string S, char Separator) {
- SmallVector<StringRef> Segments;
- StringRef(S).split(Segments, Separator, /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- std::vector<std::string> Result;
- Result.reserve(Segments.size());
- for (StringRef Segment : Segments)
- Result.push_back(Segment.str());
- return Result;
+void ModuleDepCollector::addModuleFiles(
+ CompilerInvocation &CI, ArrayRef<ModuleID> ClangModuleDeps) const {
+ for (const ModuleID &MID : ClangModuleDeps) {
+ std::string PCMPath =
+ Consumer.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile);
+ if (EagerLoadModules)
+ CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath));
+ else
+ CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert(
+ {MID.ModuleName, std::move(PCMPath)});
+ }
+}
+
+static bool needsModules(FrontendInputFile FIF) {
+ switch (FIF.getKind().getLanguage()) {
+ case Language::Unknown:
+ case Language::Asm:
+ case Language::LLVM_IR:
+ return false;
+ default:
+ return true;
+ }
}
-std::vector<std::string> ModuleDeps::getCanonicalCommandLine(
- llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
- LookupModuleOutput) const {
- CompilerInvocation CI(BuildInvocation);
- FrontendOptions &FrontendOpts = CI.getFrontendOpts();
+void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
+ CI.clearImplicitModuleBuildOptions();
- InputKind ModuleMapInputKind(FrontendOpts.DashX.getLanguage(),
- InputKind::Format::ModuleMap);
- FrontendOpts.Inputs.emplace_back(ClangModuleMapFile, ModuleMapInputKind);
- FrontendOpts.OutputFile =
- LookupModuleOutput(ID, ModuleOutputKind::ModuleFile);
- if (HadSerializedDiagnostics)
- CI.getDiagnosticOpts().DiagnosticSerializationFile =
- LookupModuleOutput(ID, ModuleOutputKind::DiagnosticSerializationFile);
- if (HadDependencyFile) {
- DependencyOutputOptions &DepOpts = CI.getDependencyOutputOpts();
- DepOpts.OutputFile =
- LookupModuleOutput(ID, ModuleOutputKind::DependencyFile);
- DepOpts.Targets = splitString(
- LookupModuleOutput(ID, ModuleOutputKind::DependencyTargets), '\0');
- if (!DepOpts.OutputFile.empty() && DepOpts.Targets.empty()) {
- // Fallback to -o as dependency target, as in the driver.
- SmallString<128> Target;
- quoteMakeTarget(FrontendOpts.OutputFile, Target);
- DepOpts.Targets.push_back(std::string(Target));
- }
+ if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
+ Preprocessor &PP = ScanInstance.getPreprocessor();
+ if (Module *CurrentModule = PP.getCurrentModuleImplementation())
+ if (OptionalFileEntryRef CurrentModuleMap =
+ PP.getHeaderSearchInfo()
+ .getModuleMap()
+ .getModuleMapFileForUniquing(CurrentModule))
+ CI.getFrontendOpts().ModuleMapFiles.emplace_back(
+ CurrentModuleMap->getName());
+
+ SmallVector<ModuleID> DirectDeps;
+ for (const auto &KV : ModularDeps)
+ if (KV.second->ImportedByMainFile)
+ DirectDeps.push_back(KV.second->ID);
+
+ // TODO: Report module maps the same way it's done for modular dependencies.
+ addModuleMapFiles(CI, DirectDeps);
+
+ addModuleFiles(CI, DirectDeps);
+
+ for (const auto &KV : DirectPrebuiltModularDeps)
+ CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
+ }
+}
+
+static std::string getModuleContextHash(const ModuleDeps &MD,
+ const CompilerInvocation &CI,
+ bool EagerLoadModules) {
+ llvm::HashBuilder<llvm::TruncatedBLAKE3<16>,
+ llvm::support::endianness::native>
+ HashBuilder;
+ SmallString<32> Scratch;
+
+ // Hash the compiler version and serialization version to ensure the module
+ // will be readable.
+ HashBuilder.add(getClangFullRepositoryVersion());
+ HashBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR);
+
+ // Hash the BuildInvocation without any input files.
+ SmallVector<const char *, 32> DummyArgs;
+ CI.generateCC1CommandLine(DummyArgs, [&](const Twine &Arg) {
+ Scratch.clear();
+ StringRef Str = Arg.toStringRef(Scratch);
+ HashBuilder.add(Str);
+ return "<unused>";
+ });
+
+ // Hash the module dependencies. These paths may differ even if the invocation
+ // is identical if they depend on the contents of the files in the TU -- for
+ // example, case-insensitive paths to modulemap files. Usually such a case
+ // would indicate a missed optimization to canonicalize, but it may be
+ // difficult to canonicalize all cases when there is a VFS.
+ for (const auto &ID : MD.ClangModuleDeps) {
+ HashBuilder.add(ID.ModuleName);
+ HashBuilder.add(ID.ContextHash);
}
- for (ModuleID MID : ClangModuleDeps)
- FrontendOpts.ModuleFiles.push_back(
- LookupModuleOutput(MID, ModuleOutputKind::ModuleFile));
+ HashBuilder.add(EagerLoadModules);
- return serializeCompilerInvocation(CI);
+ llvm::BLAKE3Result<16> Hash = HashBuilder.final();
+ std::array<uint64_t, 2> Words;
+ static_assert(sizeof(Hash) == sizeof(Words), "Hash must match Words");
+ std::memcpy(Words.data(), Hash.data(), sizeof(Hash));
+ return toString(llvm::APInt(sizeof(Words) * 8, Words), 36, /*Signed=*/false);
}
-std::vector<std::string>
-ModuleDeps::getCanonicalCommandLineWithoutModulePaths() const {
- return serializeCompilerInvocation(BuildInvocation);
+void ModuleDepCollector::associateWithContextHash(const CompilerInvocation &CI,
+ ModuleDeps &Deps) {
+ Deps.ID.ContextHash = getModuleContextHash(Deps, CI, EagerLoadModules);
+ bool Inserted = ModuleDepsByID.insert({Deps.ID, &Deps}).second;
+ (void)Inserted;
+ assert(Inserted && "duplicate module mapping");
}
void ModuleDepCollectorPP::FileChanged(SourceLocation Loc,
@@ -180,21 +318,20 @@ void ModuleDepCollectorPP::FileChanged(SourceLocation Loc,
// 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!
- if (Optional<StringRef> Filename =
+ if (std::optional<StringRef> Filename =
SM.getNonBuiltinFilenameForID(SM.getFileID(SM.getExpansionLoc(Loc))))
- MDC.FileDeps.push_back(
- std::string(llvm::sys::path::remove_leading_dotslash(*Filename)));
+ MDC.addFileDep(llvm::sys::path::remove_leading_dotslash(*Filename));
}
void ModuleDepCollectorPP::InclusionDirective(
SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
- bool IsAngled, CharSourceRange FilenameRange, Optional<FileEntryRef> File,
+ bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
StringRef SearchPath, StringRef RelativePath, const Module *Imported,
SrcMgr::CharacteristicKind FileType) {
if (!File && !Imported) {
// This is a non-modular include that HeaderSearch failed to find. Add it
// here as `FileChanged` will never see it.
- MDC.FileDeps.push_back(std::string(FileName));
+ MDC.addFileDep(FileName);
}
handleImport(Imported);
}
@@ -212,7 +349,8 @@ void ModuleDepCollectorPP::handleImport(const Module *Imported) {
const Module *TopLevelModule = Imported->getTopLevelModule();
if (MDC.isPrebuiltModule(TopLevelModule))
- DirectPrebuiltModularDeps.insert(TopLevelModule);
+ MDC.DirectPrebuiltModularDeps.insert(
+ {TopLevelModule, PrebuiltModuleDep{TopLevelModule}});
else
DirectModularDeps.insert(TopLevelModule);
}
@@ -224,18 +362,15 @@ void ModuleDepCollectorPP::EndOfMainFile() {
->getName());
if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty())
- MDC.FileDeps.push_back(
- MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
-
- for (const Module *M : DirectModularDeps) {
- // A top-level module might not be actually imported as a module when
- // -fmodule-name is used to compile a translation unit that imports this
- // module. In that case it can be skipped. The appropriate header
- // dependencies will still be reported as expected.
- if (!M->getASTFile())
- continue;
+ MDC.addFileDep(MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude);
+
+ for (const Module *M :
+ MDC.ScanInstance.getPreprocessor().getAffectingClangModules())
+ if (!MDC.isPrebuiltModule(M))
+ DirectModularDeps.insert(M);
+
+ for (const Module *M : DirectModularDeps)
handleTopLevelModule(M);
- }
MDC.Consumer.handleDependencyOutputOpts(*MDC.Opts);
@@ -245,13 +380,21 @@ void ModuleDepCollectorPP::EndOfMainFile() {
for (auto &&I : MDC.FileDeps)
MDC.Consumer.handleFileDependency(I);
- for (auto &&I : DirectPrebuiltModularDeps)
- MDC.Consumer.handlePrebuiltModuleDependency(PrebuiltModuleDep{I});
+ for (auto &&I : MDC.DirectPrebuiltModularDeps)
+ MDC.Consumer.handlePrebuiltModuleDependency(I.second);
}
-ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
+std::optional<ModuleID>
+ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
assert(M == M->getTopLevelModule() && "Expected top level module!");
+ // A top-level module might not be actually imported as a module when
+ // -fmodule-name is used to compile a translation unit that imports this
+ // module. In that case it can be skipped. The appropriate header
+ // dependencies will still be reported as expected.
+ if (!M->getASTFile())
+ return {};
+
// If this module has been handled already, just return its ID.
auto ModI = MDC.ModularDeps.insert({M, nullptr});
if (!ModI.second)
@@ -262,18 +405,16 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
MD.ID.ModuleName = M->getFullModuleName();
MD.ImportedByMainFile = DirectModularDeps.contains(M);
- MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName());
MD.IsSystem = M->IsSystem;
- const FileEntry *ModuleMap = MDC.ScanInstance.getPreprocessor()
- .getHeaderSearchInfo()
- .getModuleMap()
- .getModuleMapFileForUniquing(M);
+ ModuleMap &ModMapInfo =
+ MDC.ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+
+ OptionalFileEntryRef ModuleMap = ModMapInfo.getModuleMapFileForUniquing(M);
if (ModuleMap) {
- StringRef Path = ModuleMap->tryGetRealPathName();
- if (Path.empty())
- Path = ModuleMap->getName();
+ SmallString<128> Path = ModuleMap->getNameAsRequested();
+ ModMapInfo.canonicalizeModuleMapPath(Path);
MD.ClangModuleMapFile = std::string(Path);
}
@@ -288,70 +429,37 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
// handle it like normal. With explicitly built modules we don't need
// to play VFS tricks, so replace it with the correct module map.
if (IF.getFile()->getName().endswith("__inferred_module.map")) {
- MD.FileDeps.insert(ModuleMap->getName());
+ MDC.addFileDep(MD, ModuleMap->getName());
return;
}
- MD.FileDeps.insert(IF.getFile()->getName());
+ MDC.addFileDep(MD, IF.getFile()->getName());
});
- // We usually don't need to list the module map files of our dependencies when
- // building a module explicitly: their semantics will be deserialized from PCM
- // files.
- //
- // However, some module maps loaded implicitly during the dependency scan can
- // describe anti-dependencies. That happens when this module, let's call it
- // M1, is marked as '[no_undeclared_includes]' and tries to access a header
- // "M2/M2.h" from another module, M2, but doesn't have a 'use M2;'
- // declaration. The explicit build needs the module map for M2 so that it
- // knows that textually including "M2/M2.h" is not allowed.
- // E.g., '__has_include("M2/M2.h")' should return false, but without M2's
- // module map the explicit build would return true.
- //
- // An alternative approach would be to tell the explicit build what its
- // textual dependencies are, instead of having it re-discover its
- // anti-dependencies. For example, we could create and use an `-ivfs-overlay`
- // with `fall-through: false` that explicitly listed the dependencies.
- // However, that's more complicated to implement and harder to reason about.
- if (M->NoUndeclaredIncludes) {
- // We don't have a good way to determine which module map described the
- // anti-dependency (let alone what's the corresponding top-level module
- // map). We simply specify all the module maps in the order they were loaded
- // during the implicit build during scan.
- // TODO: Resolve this by serializing and only using Module::UndeclaredUses.
- MDC.ScanInstance.getASTReader()->visitTopLevelModuleMaps(
- *MF, [&](const FileEntry *FE) {
- if (FE->getName().endswith("__inferred_module.map"))
- return;
- // The top-level modulemap of this module will be the input file. We
- // don't need to specify it as a module map.
- if (FE == ModuleMap)
- return;
- MD.ModuleMapFileDeps.push_back(FE->getName().str());
- });
- }
+ llvm::DenseSet<const Module *> SeenDeps;
+ addAllSubmodulePrebuiltDeps(M, MD, SeenDeps);
+ addAllSubmoduleDeps(M, MD, SeenDeps);
+ addAllAffectingClangModules(M, MD, SeenDeps);
- // Add direct prebuilt module dependencies now, so that we can use them when
- // creating a CompilerInvocation and computing context hash for this
- // ModuleDeps instance.
- llvm::DenseSet<const Module *> SeenModules;
- addAllSubmodulePrebuiltDeps(M, MD, SeenModules);
+ MDC.ScanInstance.getASTReader()->visitTopLevelModuleMaps(
+ *MF, [&](FileEntryRef FE) {
+ if (FE.getNameAsRequested().endswith("__inferred_module.map"))
+ return;
+ MD.ModuleMapFileDeps.emplace_back(FE.getNameAsRequested());
+ });
- MD.BuildInvocation = MDC.makeInvocationForModuleBuildWithoutPaths(
+ CompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs(
MD, [&](CompilerInvocation &BuildInvocation) {
if (MDC.OptimizeArgs)
optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(),
*MDC.ScanInstance.getASTReader(), *MF);
});
- MD.HadSerializedDiagnostics = !MDC.OriginalInvocation.getDiagnosticOpts()
- .DiagnosticSerializationFile.empty();
- MD.HadDependencyFile =
- !MDC.OriginalInvocation.getDependencyOutputOpts().OutputFile.empty();
- // FIXME: HadSerializedDiagnostics and HadDependencyFile should be included in
- // the context hash since it can affect the command-line.
- MD.ID.ContextHash = MD.BuildInvocation.getModuleHash();
- llvm::DenseSet<const Module *> AddedModules;
- addAllSubmoduleDeps(M, MD, AddedModules);
+ MDC.associateWithContextHash(CI, MD);
+
+ // Finish the compiler invocation. Requires dependencies and the context hash.
+ MDC.addOutputPaths(CI, MD);
+
+ MD.BuildArguments = CI.getCC1CommandLine();
return MD.ID;
}
@@ -406,9 +514,33 @@ void ModuleDepCollectorPP::addModuleDep(
for (const Module *Import : M->Imports) {
if (Import->getTopLevelModule() != M->getTopLevelModule() &&
!MDC.isPrebuiltModule(Import)) {
- ModuleID ImportID = handleTopLevelModule(Import->getTopLevelModule());
- if (AddedModules.insert(Import->getTopLevelModule()).second)
- MD.ClangModuleDeps.push_back(ImportID);
+ if (auto ImportID = handleTopLevelModule(Import->getTopLevelModule()))
+ if (AddedModules.insert(Import->getTopLevelModule()).second)
+ MD.ClangModuleDeps.push_back(*ImportID);
+ }
+ }
+}
+
+void ModuleDepCollectorPP::addAllAffectingClangModules(
+ const Module *M, ModuleDeps &MD,
+ llvm::DenseSet<const Module *> &AddedModules) {
+ addAffectingClangModule(M, MD, AddedModules);
+
+ for (const Module *SubM : M->submodules())
+ addAllAffectingClangModules(SubM, MD, AddedModules);
+}
+
+void ModuleDepCollectorPP::addAffectingClangModule(
+ const Module *M, ModuleDeps &MD,
+ llvm::DenseSet<const Module *> &AddedModules) {
+ for (const Module *Affecting : M->AffectingClangModules) {
+ assert(Affecting == Affecting->getTopLevelModule() &&
+ "Not quite import not top-level module");
+ if (Affecting != M->getTopLevelModule() &&
+ !MDC.isPrebuiltModule(Affecting)) {
+ if (auto ImportID = handleTopLevelModule(Affecting))
+ if (AddedModules.insert(Affecting).second)
+ MD.ClangModuleDeps.push_back(*ImportID);
}
}
}
@@ -416,9 +548,10 @@ void ModuleDepCollectorPP::addModuleDep(
ModuleDepCollector::ModuleDepCollector(
std::unique_ptr<DependencyOutputOptions> Opts,
CompilerInstance &ScanInstance, DependencyConsumer &C,
- CompilerInvocation &&OriginalCI, bool OptimizeArgs)
+ CompilerInvocation OriginalCI, bool OptimizeArgs, bool EagerLoadModules)
: ScanInstance(ScanInstance), Consumer(C), Opts(std::move(Opts)),
- OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs) {}
+ OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs),
+ EagerLoadModules(EagerLoadModules) {}
void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
@@ -437,3 +570,26 @@ bool ModuleDepCollector::isPrebuiltModule(const Module *M) {
PrebuiltModuleFileIt->second == M->getASTFile()->getName());
return true;
}
+
+static StringRef makeAbsoluteAndPreferred(CompilerInstance &CI, StringRef Path,
+ SmallVectorImpl<char> &Storage) {
+ if (llvm::sys::path::is_absolute(Path) &&
+ !llvm::sys::path::is_style_windows(llvm::sys::path::Style::native))
+ return Path;
+ Storage.assign(Path.begin(), Path.end());
+ CI.getFileManager().makeAbsolutePath(Storage);
+ llvm::sys::path::make_preferred(Storage);
+ return StringRef(Storage.data(), Storage.size());
+}
+
+void ModuleDepCollector::addFileDep(StringRef Path) {
+ llvm::SmallString<256> Storage;
+ Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
+ FileDeps.push_back(std::string(Path));
+}
+
+void ModuleDepCollector::addFileDep(ModuleDeps &MD, StringRef Path) {
+ llvm::SmallString<256> Storage;
+ Path = makeAbsoluteAndPreferred(ScanInstance, Path, Storage);
+ MD.FileDeps.insert(Path);
+}
diff --git a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
index 2f97067f6171..42691d556d98 100644
--- a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
+++ b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
@@ -161,7 +161,7 @@ CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
optionally(
isDerivedFrom(cxxRecordDecl(hasName("clang::TypeLoc"))
.bind("typeLocBase"))))),
- returns(asString(TypeString)))
+ returns(hasCanonicalType(asString(TypeString))))
.bind("classMethod")),
*ASTClass, *Result.Context);
diff --git a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
index 05c4f92676e8..5f2b48173f28 100644
--- a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
+++ b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
@@ -35,7 +35,7 @@ public:
private:
void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
- llvm::Optional<TraversalKind> getCheckTraversalKind() const override {
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}
diff --git a/clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp b/clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp
index 9c825428f2ea..e67ffb037095 100644
--- a/clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp
+++ b/clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp
@@ -116,7 +116,7 @@ int main(int argc, const char **argv) {
"ast-api-dump-tool", OFS);
std::unique_ptr<clang::driver::Compilation> Comp(
- Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
+ Driver->BuildCompilation(llvm::ArrayRef(Argv)));
if (!Comp)
return 1;
diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
index 75d0d50d851f..88d20ba3957d 100644
--- a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
+++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
@@ -60,9 +60,12 @@ private:
if (!SeenRSPFile)
continue;
llvm::BumpPtrAllocator Alloc;
- llvm::StringSaver Saver(Alloc);
- llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, false,
- llvm::StringRef(Cmd.Directory), *FS);
+ llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer);
+ llvm::Error Err = ECtx.setVFS(FS.get())
+ .setCurrentDir(Cmd.Directory)
+ .expandResponseFiles(Argv);
+ if (Err)
+ llvm::errs() << Err;
// Don't assign directly, Argv aliases CommandLine.
std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end());
Cmd.CommandLine = std::move(ExpandedArgv);
diff --git a/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp b/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
new file mode 100644
index 000000000000..49d23908d33b
--- /dev/null
+++ b/clang/lib/Tooling/Inclusions/HeaderAnalysis.cpp
@@ -0,0 +1,119 @@
+//===--- HeaderAnalysis.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/Inclusions/HeaderAnalysis.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/HeaderSearch.h"
+
+namespace clang::tooling {
+namespace {
+
+// Is Line an #if or #ifdef directive?
+// FIXME: This makes headers with #ifdef LINUX/WINDOWS/MACOS marked as non
+// self-contained and is probably not what we want.
+bool isIf(llvm::StringRef Line) {
+ Line = Line.ltrim();
+ if (!Line.consume_front("#"))
+ return false;
+ Line = Line.ltrim();
+ return Line.startswith("if");
+}
+
+// Is Line an #error directive mentioning includes?
+bool isErrorAboutInclude(llvm::StringRef Line) {
+ Line = Line.ltrim();
+ if (!Line.consume_front("#"))
+ return false;
+ Line = Line.ltrim();
+ if (!Line.startswith("error"))
+ return false;
+ return Line.contains_insensitive(
+ "includ"); // Matches "include" or "including".
+}
+
+// Heuristically headers that only want to be included via an umbrella.
+bool isDontIncludeMeHeader(StringRef Content) {
+ llvm::StringRef Line;
+ // Only sniff up to 100 lines or 10KB.
+ Content = Content.take_front(100 * 100);
+ for (unsigned I = 0; I < 100 && !Content.empty(); ++I) {
+ std::tie(Line, Content) = Content.split('\n');
+ if (isIf(Line) && isErrorAboutInclude(Content.split('\n').first))
+ return true;
+ }
+ return false;
+}
+
+bool isImportLine(llvm::StringRef Line) {
+ Line = Line.ltrim();
+ if (!Line.consume_front("#"))
+ return false;
+ Line = Line.ltrim();
+ return Line.startswith("import");
+}
+
+llvm::StringRef getFileContents(const FileEntry *FE, const SourceManager &SM) {
+ return const_cast<SourceManager &>(SM)
+ .getMemoryBufferForFileOrNone(FE)
+ .value_or(llvm::MemoryBufferRef())
+ .getBuffer();
+}
+
+} // namespace
+
+bool isSelfContainedHeader(const FileEntry *FE, const SourceManager &SM,
+ HeaderSearch &HeaderInfo) {
+ assert(FE);
+ if (!HeaderInfo.isFileMultipleIncludeGuarded(FE) &&
+ !HeaderInfo.hasFileBeenImported(FE) &&
+ // Any header that contains #imports is supposed to be #import'd so no
+ // need to check for anything but the main-file.
+ (SM.getFileEntryForID(SM.getMainFileID()) != FE ||
+ !codeContainsImports(getFileContents(FE, SM))))
+ return false;
+ // This pattern indicates that a header can't be used without
+ // particular preprocessor state, usually set up by another header.
+ return !isDontIncludeMeHeader(getFileContents(FE, SM));
+}
+
+bool codeContainsImports(llvm::StringRef Code) {
+ // Only sniff up to 100 lines or 10KB.
+ Code = Code.take_front(100 * 100);
+ llvm::StringRef Line;
+ for (unsigned I = 0; I < 100 && !Code.empty(); ++I) {
+ std::tie(Line, Code) = Code.split('\n');
+ if (isImportLine(Line))
+ return true;
+ }
+ return false;
+}
+
+std::optional<StringRef> parseIWYUPragma(const char *Text) {
+ // Skip the comment start, // or /*.
+ if (Text[0] != '/' || (Text[1] != '/' && Text[1] != '*'))
+ return std::nullopt;
+ bool BlockComment = Text[1] == '*';
+ Text += 2;
+
+ // Per spec, direcitves are whitespace- and case-sensitive.
+ constexpr llvm::StringLiteral IWYUPragma = " IWYU pragma: ";
+ if (strncmp(Text, IWYUPragma.data(), IWYUPragma.size()))
+ return std::nullopt;
+ Text += IWYUPragma.size();
+ const char *End = Text;
+ while (*End != 0 && *End != '\n')
+ ++End;
+ StringRef Rest(Text, End - Text);
+ // Strip off whitespace and comment markers to avoid confusion. This isn't
+ // fully-compatible with IWYU, which splits into whitespace-delimited tokens.
+ if (BlockComment)
+ Rest.consume_back("*/");
+ return Rest.trim();
+}
+
+} // namespace clang::tooling
diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
index fc8773e60c58..172eff1bf6ab 100644
--- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
+++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
@@ -10,9 +10,9 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Path.h"
+#include <optional>
namespace clang {
namespace tooling {
@@ -58,7 +58,7 @@ unsigned getOffsetAfterTokenSequence(
// (second) raw_identifier name is checked.
bool checkAndConsumeDirectiveWithName(
Lexer &Lex, StringRef Name, Token &Tok,
- llvm::Optional<StringRef> RawIDName = llvm::None) {
+ std::optional<StringRef> RawIDName = std::nullopt) {
bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
Tok.is(tok::raw_identifier) &&
Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
@@ -266,6 +266,8 @@ bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const {
return false;
}
+const llvm::Regex HeaderIncludes::IncludeRegex(IncludeRegexPattern);
+
HeaderIncludes::HeaderIncludes(StringRef FileName, StringRef Code,
const IncludeStyle &Style)
: FileName(FileName), Code(Code), FirstIncludeOffset(-1),
@@ -274,8 +276,7 @@ HeaderIncludes::HeaderIncludes(StringRef FileName, StringRef Code,
MaxInsertOffset(MinInsertOffset +
getMaxHeaderInsertionOffset(
FileName, Code.drop_front(MinInsertOffset), Style)),
- Categories(Style, FileName),
- IncludeRegex(llvm::Regex(IncludeRegexPattern)) {
+ Categories(Style, FileName) {
// Add 0 for main header and INT_MAX for headers that are not in any
// category.
Priorities = {0, INT_MAX};
@@ -295,7 +296,9 @@ HeaderIncludes::HeaderIncludes(StringRef FileName, StringRef Code,
addExistingInclude(
Include(Matches[2],
tooling::Range(
- Offset, std::min(Line.size() + 1, Code.size() - Offset))),
+ Offset, std::min(Line.size() + 1, Code.size() - Offset)),
+ Matches[1] == "import" ? tooling::IncludeDirective::Import
+ : tooling::IncludeDirective::Include),
NextLineOffset);
}
Offset = NextLineOffset;
@@ -340,18 +343,21 @@ void HeaderIncludes::addExistingInclude(Include IncludeToAdd,
}
}
-llvm::Optional<tooling::Replacement>
-HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled) const {
+std::optional<tooling::Replacement>
+HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled,
+ IncludeDirective Directive) const {
assert(IncludeName == trimInclude(IncludeName));
// If a <header> ("header") already exists in code, "header" (<header>) with
- // different quotation will still be inserted.
+ // different quotation and/or directive will still be inserted.
// FIXME: figure out if this is the best behavior.
auto It = ExistingIncludes.find(IncludeName);
- if (It != ExistingIncludes.end())
+ if (It != ExistingIncludes.end()) {
for (const auto &Inc : It->second)
- if ((IsAngled && StringRef(Inc.Name).startswith("<")) ||
- (!IsAngled && StringRef(Inc.Name).startswith("\"")))
- return llvm::None;
+ if (Inc.Directive == Directive &&
+ ((IsAngled && StringRef(Inc.Name).startswith("<")) ||
+ (!IsAngled && StringRef(Inc.Name).startswith("\""))))
+ return std::nullopt;
+ }
std::string Quoted =
std::string(llvm::formatv(IsAngled ? "<{0}>" : "\"{0}\"", IncludeName));
StringRef QuotedName = Quoted;
@@ -370,8 +376,10 @@ HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled) const {
}
}
assert(InsertOffset <= Code.size());
+ llvm::StringRef DirectiveSpelling =
+ Directive == IncludeDirective::Include ? "include" : "import";
std::string NewInclude =
- std::string(llvm::formatv("#include {0}\n", QuotedName));
+ llvm::formatv("#{0} {1}\n", DirectiveSpelling, QuotedName);
// When inserting headers at end of the code, also append '\n' to the code
// if it does not end with '\n'.
// FIXME: when inserting multiple #includes at the end of code, only one
diff --git a/clang/lib/Tooling/Inclusions/StandardLibrary.cpp b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp
index 8fb0c8474e64..9e5e421fdebc 100644
--- a/clang/lib/Tooling/Inclusions/StandardLibrary.cpp
+++ b/clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Inclusions/StandardLibrary.h"
-#include "llvm/ADT/Optional.h"
+#include "clang/AST/Decl.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
@@ -76,17 +76,17 @@ static void ensureInitialized() {
(void)Dummy;
}
-llvm::Optional<Header> Header::named(llvm::StringRef Name) {
+std::optional<Header> Header::named(llvm::StringRef Name) {
ensureInitialized();
auto It = HeaderIDs->find(Name);
if (It == HeaderIDs->end())
- return llvm::None;
+ return std::nullopt;
return Header(It->second);
}
llvm::StringRef Header::name() const { return HeaderNames[ID]; }
llvm::StringRef Symbol::scope() const { return SymbolNames[ID].first; }
llvm::StringRef Symbol::name() const { return SymbolNames[ID].second; }
-llvm::Optional<Symbol> Symbol::named(llvm::StringRef Scope,
+std::optional<Symbol> Symbol::named(llvm::StringRef Scope,
llvm::StringRef Name) {
ensureInitialized();
if (NSSymbolMap *NSSymbols = NamespaceSymbols->lookup(Scope)) {
@@ -94,7 +94,7 @@ llvm::Optional<Symbol> Symbol::named(llvm::StringRef Scope,
if (It != NSSymbols->end())
return Symbol(It->second);
}
- return llvm::None;
+ return std::nullopt;
}
Header Symbol::header() const { return Header(SymbolHeaderIDs[ID]); }
llvm::SmallVector<Header> Symbol::headers() const {
@@ -123,7 +123,7 @@ NSSymbolMap *Recognizer::namespaceSymbols(const NamespaceDecl *D) {
return Result;
}
-llvm::Optional<Symbol> Recognizer::operator()(const Decl *D) {
+std::optional<Symbol> Recognizer::operator()(const Decl *D) {
// If D is std::vector::iterator, `vector` is the outer symbol to look up.
// We keep all the candidate DCs as some may turn out to be anon enums.
// Do this resolution lazily as we may turn out not to have a std namespace.
@@ -136,7 +136,7 @@ llvm::Optional<Symbol> Recognizer::operator()(const Decl *D) {
}
NSSymbolMap *Symbols = namespaceSymbols(cast_or_null<NamespaceDecl>(DC));
if (!Symbols)
- return llvm::None;
+ return std::nullopt;
llvm::StringRef Name = [&]() -> llvm::StringRef {
for (const auto *SymDC : llvm::reverse(IntermediateDecl)) {
@@ -152,11 +152,11 @@ llvm::Optional<Symbol> Recognizer::operator()(const Decl *D) {
return "";
}();
if (Name.empty())
- return llvm::None;
+ return std::nullopt;
auto It = Symbols->find(Name);
if (It == Symbols->end())
- return llvm::None;
+ return std::nullopt;
return Symbol(It->second);
}
diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
index 0143b5f8df6b..ff9cb4b62073 100644
--- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -49,9 +49,7 @@
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Debug.h"
@@ -59,6 +57,7 @@
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
+#include <optional>
namespace clang {
namespace tooling {
@@ -129,7 +128,7 @@ struct TransferableCommand {
// Flags that should not apply to all files are stripped from CommandLine.
CompileCommand Cmd;
// Language detected from -x or the filename. Never TY_INVALID.
- Optional<types::ID> Type;
+ std::optional<types::ID> Type;
// Standard specified by -std.
LangStandard::Kind Std = LangStandard::lang_unspecified;
// Whether the command line is for the cl-compatible driver.
@@ -148,7 +147,7 @@ struct TransferableCommand {
TmpArgv.push_back(S.c_str());
ClangCLMode = !TmpArgv.empty() &&
driver::IsClangCL(driver::getDriverMode(
- TmpArgv.front(), llvm::makeArrayRef(TmpArgv).slice(1)));
+ TmpArgv.front(), llvm::ArrayRef(TmpArgv).slice(1)));
ArgList = {TmpArgv.begin(), TmpArgv.end()};
}
@@ -165,8 +164,8 @@ struct TransferableCommand {
const unsigned OldPos = Pos;
std::unique_ptr<llvm::opt::Arg> Arg(OptTable.ParseOneArg(
ArgList, Pos,
- /* Include */ ClangCLMode ? CoreOption | CLOption : 0,
- /* Exclude */ ClangCLMode ? 0 : CLOption));
+ /* Include */ ClangCLMode ? CoreOption | CLOption | CLDXCOption : 0,
+ /* Exclude */ ClangCLMode ? 0 : CLOption | CLDXCOption));
if (!Arg)
continue;
@@ -208,7 +207,7 @@ struct TransferableCommand {
Type = foldType(*Type);
// The contract is to store None instead of TY_INVALID.
if (Type == types::TY_INVALID)
- Type = llvm::None;
+ Type = std::nullopt;
}
// Produce a CompileCommand for \p filename, based on this one.
@@ -280,7 +279,7 @@ private:
}
// Try to interpret the argument as a type specifier, e.g. '-x'.
- Optional<types::ID> tryParseTypeArg(const llvm::opt::Arg &Arg) {
+ std::optional<types::ID> tryParseTypeArg(const llvm::opt::Arg &Arg) {
const llvm::opt::Option &Opt = Arg.getOption();
using namespace driver::options;
if (ClangCLMode) {
@@ -292,15 +291,15 @@ private:
if (Opt.matches(driver::options::OPT_x))
return types::lookupTypeForTypeSpecifier(Arg.getValue());
}
- return None;
+ return std::nullopt;
}
// Try to interpret the argument as '-std='.
- Optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
+ 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 LangStandard::getLangKind(Arg.getValue());
- return None;
+ return std::nullopt;
}
};
diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp
index 5e18d7a576c0..cdda587d0925 100644
--- a/clang/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp
@@ -15,7 +15,6 @@
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -34,6 +33,7 @@
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <memory>
+#include <optional>
#include <string>
#include <system_error>
#include <tuple>
@@ -349,7 +349,7 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
return false;
}
llvm::yaml::ScalarNode *Directory = nullptr;
- llvm::Optional<std::vector<llvm::yaml::ScalarNode *>> Command;
+ std::optional<std::vector<llvm::yaml::ScalarNode *>> Command;
llvm::yaml::ScalarNode *File = nullptr;
llvm::yaml::ScalarNode *Output = nullptr;
for (auto& NextKeyValue : *Object) {
@@ -419,14 +419,13 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
SmallString<128> NativeFilePath;
if (llvm::sys::path::is_relative(FileName)) {
SmallString<8> DirectoryStorage;
- SmallString<128> AbsolutePath(
- Directory->getValue(DirectoryStorage));
+ SmallString<128> AbsolutePath(Directory->getValue(DirectoryStorage));
llvm::sys::path::append(AbsolutePath, FileName);
- llvm::sys::path::remove_dots(AbsolutePath, /*remove_dot_dot=*/ true);
llvm::sys::path::native(AbsolutePath, NativeFilePath);
} else {
llvm::sys::path::native(FileName, NativeFilePath);
}
+ llvm::sys::path::remove_dots(NativeFilePath, /*remove_dot_dot=*/true);
auto Cmd = CompileCommandRef(Directory, File, *Command, Output);
IndexByFile[NativeFilePath].push_back(Cmd);
AllCommands.push_back(Cmd);
diff --git a/clang/lib/Tooling/Refactoring/ASTSelection.cpp b/clang/lib/Tooling/Refactoring/ASTSelection.cpp
index 9485c8bc04ad..058574d8ec1a 100644
--- a/clang/lib/Tooling/Refactoring/ASTSelection.cpp
+++ b/clang/lib/Tooling/Refactoring/ASTSelection.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/LexicallyOrderedRecursiveASTVisitor.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/SaveAndRestore.h"
+#include <optional>
using namespace clang;
using namespace tooling;
@@ -50,12 +51,12 @@ public:
SourceSelectionKind::None));
}
- Optional<SelectedASTNode> getSelectedASTNode() {
+ std::optional<SelectedASTNode> getSelectedASTNode() {
assert(SelectionStack.size() == 1 && "stack was not popped");
SelectedASTNode Result = std::move(SelectionStack.back());
SelectionStack.pop_back();
if (Result.Children.empty())
- return None;
+ return std::nullopt;
return std::move(Result);
}
@@ -63,14 +64,14 @@ public:
// Avoid traversing the semantic expressions. They should be handled by
// looking through the appropriate opaque expressions in order to build
// a meaningful selection tree.
- llvm::SaveAndRestore<bool> LookThrough(LookThroughOpaqueValueExprs, true);
+ llvm::SaveAndRestore LookThrough(LookThroughOpaqueValueExprs, true);
return TraverseStmt(E->getSyntacticForm());
}
bool TraverseOpaqueValueExpr(OpaqueValueExpr *E) {
if (!LookThroughOpaqueValueExprs)
return true;
- llvm::SaveAndRestore<bool> LookThrough(LookThroughOpaqueValueExprs, false);
+ llvm::SaveAndRestore LookThrough(LookThroughOpaqueValueExprs, false);
return TraverseStmt(E->getSourceExpr());
}
@@ -178,7 +179,7 @@ private:
} // end anonymous namespace
-Optional<SelectedASTNode>
+std::optional<SelectedASTNode>
clang::tooling::findSelectedASTNodes(const ASTContext &Context,
SourceRange SelectionRange) {
assert(SelectionRange.isValid() &&
@@ -375,22 +376,22 @@ static void findDeepestWithKind(
findDeepestWithKind(ASTSelection, MatchingNodes, Kind, ParentStack);
}
-Optional<CodeRangeASTSelection>
+std::optional<CodeRangeASTSelection>
CodeRangeASTSelection::create(SourceRange SelectionRange,
const SelectedASTNode &ASTSelection) {
// Code range is selected when the selection range is not empty.
if (SelectionRange.getBegin() == SelectionRange.getEnd())
- return None;
+ return std::nullopt;
llvm::SmallVector<SelectedNodeWithParents, 4> ContainSelection;
findDeepestWithKind(ASTSelection, ContainSelection,
SourceSelectionKind::ContainsSelection);
// We are looking for a selection in one body of code, so let's focus on
// one matching result.
if (ContainSelection.size() != 1)
- return None;
+ return std::nullopt;
SelectedNodeWithParents &Selected = ContainSelection[0];
if (!Selected.Node.get().Node.get<Stmt>())
- return None;
+ return std::nullopt;
const Stmt *CodeRangeStmt = Selected.Node.get().Node.get<Stmt>();
if (!isa<CompoundStmt>(CodeRangeStmt)) {
Selected.canonicalize();
diff --git a/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
index 70a4df07ea67..0e052bb19768 100644
--- a/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
+++ b/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
@@ -8,6 +8,7 @@
#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
#include "clang/AST/Attr.h"
+#include <optional>
using namespace clang;
using namespace tooling;
@@ -20,7 +21,7 @@ ASTSelectionRequirement::evaluate(RefactoringRuleContext &Context) const {
if (!Range)
return Range.takeError();
- Optional<SelectedASTNode> Selection =
+ std::optional<SelectedASTNode> Selection =
findSelectedASTNodes(Context.getASTContext(), *Range);
if (!Selection)
return Context.createDiagnosticError(
@@ -37,8 +38,9 @@ Expected<CodeRangeASTSelection> CodeRangeASTSelectionRequirement::evaluate(
return ASTSelection.takeError();
std::unique_ptr<SelectedASTNode> StoredSelection =
std::make_unique<SelectedASTNode>(std::move(*ASTSelection));
- Optional<CodeRangeASTSelection> CodeRange = CodeRangeASTSelection::create(
- Context.getSelectionRange(), *StoredSelection);
+ std::optional<CodeRangeASTSelection> CodeRange =
+ CodeRangeASTSelection::create(Context.getSelectionRange(),
+ *StoredSelection);
if (!CodeRange)
return Context.createDiagnosticError(
Context.getSelectionRange().getBegin(),
diff --git a/clang/lib/Tooling/Refactoring/Extract/Extract.cpp b/clang/lib/Tooling/Refactoring/Extract/Extract.cpp
index 402b56109052..d437f4c21f47 100644
--- a/clang/lib/Tooling/Refactoring/Extract/Extract.cpp
+++ b/clang/lib/Tooling/Refactoring/Extract/Extract.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/Refactoring/Extract/SourceExtraction.h"
+#include <optional>
namespace clang {
namespace tooling {
@@ -68,7 +69,7 @@ const RefactoringDescriptor &ExtractFunction::describe() {
Expected<ExtractFunction>
ExtractFunction::initiate(RefactoringRuleContext &Context,
CodeRangeASTSelection Code,
- Optional<std::string> DeclName) {
+ std::optional<std::string> DeclName) {
// We would like to extract code out of functions/methods/blocks.
// Prohibit extraction from things like global variable / field
// initializers and other top-level expressions.
diff --git a/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp b/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
index 5d57ecf90a96..5e69fb805150 100644
--- a/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
+++ b/clang/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
+#include <optional>
using namespace clang;
@@ -100,7 +101,7 @@ ExtractionSemicolonPolicy::compute(const Stmt *S, SourceRange &ExtractedRange,
/// Other statements should generally have a trailing ';'. We can try to find
/// it and move it together it with the extracted code.
- Optional<Token> NextToken = Lexer::findNextToken(End, SM, LangOpts);
+ std::optional<Token> NextToken = Lexer::findNextToken(End, SM, LangOpts);
if (NextToken && NextToken->is(tok::semi) &&
areOnSameLine(NextToken->getLocation(), End, SM)) {
ExtractedRange.setEnd(NextToken->getLocation());
diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp
index 041cc4f939d9..cd0261989495 100644
--- a/clang/lib/Tooling/Syntax/BuildTree.cpp
+++ b/clang/lib/Tooling/Syntax/BuildTree.cpp
@@ -469,7 +469,7 @@ public:
assert(Last.isValid());
assert(First == Last ||
TBTM.sourceManager().isBeforeInTranslationUnit(First, Last));
- return llvm::makeArrayRef(findToken(First), std::next(findToken(Last)));
+ return llvm::ArrayRef(findToken(First), std::next(findToken(Last)));
}
ArrayRef<syntax::Token>
@@ -552,7 +552,7 @@ private:
assert(Tokens.back().kind() != tok::eof);
// We never consume 'eof', so looking at the next token is ok.
if (Tokens.back().kind() != tok::semi && Tokens.end()->kind() == tok::semi)
- return llvm::makeArrayRef(Tokens.begin(), Tokens.end() + 1);
+ return llvm::ArrayRef(Tokens.begin(), Tokens.end() + 1);
return Tokens;
}
@@ -768,7 +768,7 @@ public:
// Build TemplateDeclaration nodes if we had template parameters.
auto ConsumeTemplateParameters = [&](const TemplateParameterList &L) {
const auto *TemplateKW = Builder.findToken(L.getTemplateLoc());
- auto R = llvm::makeArrayRef(TemplateKW, DeclarationRange.end());
+ auto R = llvm::ArrayRef(TemplateKW, DeclarationRange.end());
Result =
foldTemplateDeclaration(R, TemplateKW, DeclarationRange, nullptr);
DeclarationRange = R;
@@ -1639,7 +1639,7 @@ private:
auto Return = Builder.getRange(ReturnedType.getSourceRange());
const auto *Arrow = Return.begin() - 1;
assert(Arrow->kind() == tok::arrow);
- auto Tokens = llvm::makeArrayRef(Arrow, Return.end());
+ auto Tokens = llvm::ArrayRef(Arrow, Return.end());
Builder.markChildToken(Arrow, syntax::NodeRole::ArrowToken);
if (ReturnDeclarator)
Builder.markChild(ReturnDeclarator, syntax::NodeRole::Declarator);
diff --git a/clang/lib/Tooling/Syntax/ComputeReplacements.cpp b/clang/lib/Tooling/Syntax/ComputeReplacements.cpp
index 08e09e4ebdbf..fe9a9df73cb3 100644
--- a/clang/lib/Tooling/Syntax/ComputeReplacements.cpp
+++ b/clang/lib/Tooling/Syntax/ComputeReplacements.cpp
@@ -31,7 +31,7 @@ void enumerateTokenSpans(const syntax::Tree *Root,
process(Root);
// Report the last span to the user.
if (SpanBegin)
- Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
+ Callback(llvm::ArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
}
private:
@@ -52,7 +52,7 @@ void enumerateTokenSpans(const syntax::Tree *Root,
}
// Report the current span to the user.
if (SpanBegin)
- Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
+ Callback(llvm::ArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
// Start recording a new span.
SpanBegin = STM.getToken(L->getTokenKey());
SpanEnd = SpanBegin + 1;
@@ -118,17 +118,17 @@ syntax::computeReplacements(const TokenBufferTokenManager &TBTM,
// We are looking at a span of original tokens.
if (NextOriginal != Tokens.begin()) {
// There is a gap, record a replacement or deletion.
- emitReplacement(llvm::makeArrayRef(NextOriginal, Tokens.begin()));
+ emitReplacement(llvm::ArrayRef(NextOriginal, Tokens.begin()));
} else {
// No gap, but we may have pending insertions. Emit them now.
- emitReplacement(llvm::makeArrayRef(NextOriginal, /*Length=*/0));
+ emitReplacement(llvm::ArrayRef(NextOriginal, /*Length=*/(size_t)0));
}
NextOriginal = Tokens.end();
});
// We might have pending replacements at the end of file. If so, emit them.
- emitReplacement(llvm::makeArrayRef(
- NextOriginal, Buffer.expandedTokens().drop_back().end()));
+ emitReplacement(
+ llvm::ArrayRef(NextOriginal, Buffer.expandedTokens().drop_back().end()));
return Replacements;
}
diff --git a/clang/lib/Tooling/Syntax/Mutations.cpp b/clang/lib/Tooling/Syntax/Mutations.cpp
index 824f1942532d..0f04acea3d04 100644
--- a/clang/lib/Tooling/Syntax/Mutations.cpp
+++ b/clang/lib/Tooling/Syntax/Mutations.cpp
@@ -15,7 +15,6 @@
#include "clang/Tooling/Syntax/Tokens.h"
#include "clang/Tooling/Syntax/Tree.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
#include <cassert>
diff --git a/clang/lib/Tooling/Syntax/Tokens.cpp b/clang/lib/Tooling/Syntax/Tokens.cpp
index e2014f965c90..b13dc9ef4aee 100644
--- a/clang/lib/Tooling/Syntax/Tokens.cpp
+++ b/clang/lib/Tooling/Syntax/Tokens.cpp
@@ -18,8 +18,6 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
@@ -28,6 +26,7 @@
#include <algorithm>
#include <cassert>
#include <iterator>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -55,45 +54,140 @@ getTokensCovering(llvm::ArrayRef<syntax::Token> Toks, SourceRange R,
return {Begin, End};
}
-// Finds the smallest expansion range that contains expanded tokens First and
-// Last, e.g.:
+// Finds the range within FID corresponding to expanded tokens [First, Last].
+// Prev precedes First and Next follows Last, these must *not* be included.
+// If no range satisfies the criteria, returns an invalid range.
+//
// #define ID(x) x
// ID(ID(ID(a1) a2))
// ~~ -> a1
// ~~ -> a2
// ~~~~~~~~~ -> a1 a2
-SourceRange findCommonRangeForMacroArgs(const syntax::Token &First,
- const syntax::Token &Last,
- const SourceManager &SM) {
- SourceRange Res;
- auto FirstLoc = First.location(), LastLoc = Last.location();
- // Keep traversing up the spelling chain as longs as tokens are part of the
- // same expansion.
- while (!FirstLoc.isFileID() && !LastLoc.isFileID()) {
- auto ExpInfoFirst = SM.getSLocEntry(SM.getFileID(FirstLoc)).getExpansion();
- auto ExpInfoLast = SM.getSLocEntry(SM.getFileID(LastLoc)).getExpansion();
- // Stop if expansions have diverged.
- if (ExpInfoFirst.getExpansionLocStart() !=
- ExpInfoLast.getExpansionLocStart())
+SourceRange spelledForExpandedSlow(SourceLocation First, SourceLocation Last,
+ SourceLocation Prev, SourceLocation Next,
+ FileID TargetFile,
+ const SourceManager &SM) {
+ // There are two main parts to this algorithm:
+ // - identifying which spelled range covers the expanded tokens
+ // - validating that this range doesn't cover any extra tokens (First/Last)
+ //
+ // We do these in order. However as we transform the expanded range into the
+ // spelled one, we adjust First/Last so the validation remains simple.
+
+ assert(SM.getSLocEntry(TargetFile).isFile());
+ // In most cases, to select First and Last we must return their expansion
+ // range, i.e. the whole of any macros they are included in.
+ //
+ // When First and Last are part of the *same macro arg* of a macro written
+ // in TargetFile, we that slice of the arg, i.e. their spelling range.
+ //
+ // Unwrap such macro calls. If the target file has A(B(C)), the
+ // SourceLocation stack of a token inside C shows us the expansion of A first,
+ // then B, then any macros inside C's body, then C itself.
+ // (This is the reverse of the order the PP applies the expansions in).
+ while (First.isMacroID() && Last.isMacroID()) {
+ auto DecFirst = SM.getDecomposedLoc(First);
+ auto DecLast = SM.getDecomposedLoc(Last);
+ auto &ExpFirst = SM.getSLocEntry(DecFirst.first).getExpansion();
+ auto &ExpLast = SM.getSLocEntry(DecLast.first).getExpansion();
+
+ if (!ExpFirst.isMacroArgExpansion() || !ExpLast.isMacroArgExpansion())
+ break;
+ // Locations are in the same macro arg if they expand to the same place.
+ // (They may still have different FileIDs - an arg can have >1 chunks!)
+ if (ExpFirst.getExpansionLocStart() != ExpLast.getExpansionLocStart())
break;
- // Do not continue into macro bodies.
- if (!ExpInfoFirst.isMacroArgExpansion() ||
- !ExpInfoLast.isMacroArgExpansion())
+ // Careful, given:
+ // #define HIDE ID(ID(a))
+ // ID(ID(HIDE))
+ // The token `a` is wrapped in 4 arg-expansions, we only want to unwrap 2.
+ // We distinguish them by whether the macro expands into the target file.
+ // Fortunately, the target file ones will always appear first.
+ auto &ExpMacro =
+ SM.getSLocEntry(SM.getFileID(ExpFirst.getExpansionLocStart()))
+ .getExpansion();
+ if (ExpMacro.getExpansionLocStart().isMacroID())
break;
- FirstLoc = SM.getImmediateSpellingLoc(FirstLoc);
- LastLoc = SM.getImmediateSpellingLoc(LastLoc);
- // Update the result afterwards, as we want the tokens that triggered the
- // expansion.
- Res = {FirstLoc, LastLoc};
+ // Replace each endpoint with its spelling inside the macro arg.
+ // (This is getImmediateSpellingLoc without repeating lookups).
+ First = ExpFirst.getSpellingLoc().getLocWithOffset(DecFirst.second);
+ Last = ExpLast.getSpellingLoc().getLocWithOffset(DecLast.second);
+
+ // Now: how do we adjust the previous/next bounds? Three cases:
+ // A) If they are also part of the same macro arg, we translate them too.
+ // This will ensure that we don't select any macros nested within the
+ // macro arg that cover extra tokens. Critical case:
+ // #define ID(X) X
+ // ID(prev target) // selecting 'target' succeeds
+ // #define LARGE ID(prev target)
+ // LARGE // selecting 'target' fails.
+ // B) They are not in the macro at all, then their expansion range is a
+ // sibling to it, and we can safely substitute that.
+ // #define PREV prev
+ // #define ID(X) X
+ // PREV ID(target) // selecting 'target' succeeds.
+ // #define LARGE PREV ID(target)
+ // LARGE // selecting 'target' fails.
+ // C) They are in a different arg of this macro, or the macro body.
+ // Now selecting the whole macro arg is fine, but the whole macro is not.
+ // Model this by setting using the edge of the macro call as the bound.
+ // #define ID2(X, Y) X Y
+ // ID2(prev, target) // selecting 'target' succeeds
+ // #define LARGE ID2(prev, target)
+ // LARGE // selecting 'target' fails
+ auto AdjustBound = [&](SourceLocation &Bound) {
+ if (Bound.isInvalid() || !Bound.isMacroID()) // Non-macro must be case B.
+ return;
+ auto DecBound = SM.getDecomposedLoc(Bound);
+ auto &ExpBound = SM.getSLocEntry(DecBound.first).getExpansion();
+ if (ExpBound.isMacroArgExpansion() &&
+ ExpBound.getExpansionLocStart() == ExpFirst.getExpansionLocStart()) {
+ // Case A: translate to (spelling) loc within the macro arg.
+ Bound = ExpBound.getSpellingLoc().getLocWithOffset(DecBound.second);
+ return;
+ }
+ while (Bound.isMacroID()) {
+ SourceRange Exp = SM.getImmediateExpansionRange(Bound).getAsRange();
+ if (Exp.getBegin() == ExpMacro.getExpansionLocStart()) {
+ // Case B: bounds become the macro call itself.
+ Bound = (&Bound == &Prev) ? Exp.getBegin() : Exp.getEnd();
+ return;
+ }
+ // Either case C, or expansion location will later find case B.
+ // We choose the upper bound for Prev and the lower one for Next:
+ // ID(prev) target ID(next)
+ // ^ ^
+ // new-prev new-next
+ Bound = (&Bound == &Prev) ? Exp.getEnd() : Exp.getBegin();
+ }
+ };
+ AdjustBound(Prev);
+ AdjustBound(Next);
}
- // Normally mapping back to expansion location here only changes FileID, as
- // we've already found some tokens expanded from the same macro argument, and
- // they should map to a consecutive subset of spelled tokens. Unfortunately
- // SourceManager::isBeforeInTranslationUnit discriminates sourcelocations
- // based on their FileID in addition to offsets. So even though we are
- // referring to same tokens, SourceManager might tell us that one is before
- // the other if they've got different FileIDs.
- return SM.getExpansionRange(CharSourceRange(Res, true)).getAsRange();
+
+ // In all remaining cases we need the full containing macros.
+ // If this overlaps Prev or Next, then no range is possible.
+ SourceRange Candidate =
+ SM.getExpansionRange(SourceRange(First, Last)).getAsRange();
+ auto DecFirst = SM.getDecomposedExpansionLoc(Candidate.getBegin());
+ auto DecLast = SM.getDecomposedLoc(Candidate.getEnd());
+ // Can end up in the wrong file due to bad input or token-pasting shenanigans.
+ if (Candidate.isInvalid() || DecFirst.first != TargetFile || DecLast.first != TargetFile)
+ return SourceRange();
+ // Check bounds, which may still be inside macros.
+ if (Prev.isValid()) {
+ auto Dec = SM.getDecomposedLoc(SM.getExpansionRange(Prev).getBegin());
+ if (Dec.first != DecFirst.first || Dec.second >= DecFirst.second)
+ return SourceRange();
+ }
+ if (Next.isValid()) {
+ auto Dec = SM.getDecomposedLoc(SM.getExpansionRange(Next).getEnd());
+ if (Dec.first != DecLast.first || Dec.second <= DecLast.second)
+ return SourceRange();
+ }
+ // Now we know that Candidate is a file range that covers [First, Last]
+ // without encroaching on {Prev, Next}. Ship it!
+ return Candidate;
}
} // namespace
@@ -331,8 +425,8 @@ TokenBuffer::expandedForSpelled(llvm::ArrayRef<syntax::Token> Spelled) const {
// Avoid returning empty ranges.
if (ExpandedBegin == ExpandedEnd)
return {};
- return {llvm::makeArrayRef(ExpandedTokens.data() + ExpandedBegin,
- ExpandedTokens.data() + ExpandedEnd)};
+ return {llvm::ArrayRef(ExpandedTokens.data() + ExpandedBegin,
+ ExpandedTokens.data() + ExpandedEnd)};
}
llvm::ArrayRef<syntax::Token> TokenBuffer::spelledTokens(FileID FID) const {
@@ -357,57 +451,54 @@ std::string TokenBuffer::Mapping::str() const {
BeginSpelled, EndSpelled, BeginExpanded, EndExpanded));
}
-llvm::Optional<llvm::ArrayRef<syntax::Token>>
+std::optional<llvm::ArrayRef<syntax::Token>>
TokenBuffer::spelledForExpanded(llvm::ArrayRef<syntax::Token> Expanded) const {
// Mapping an empty range is ambiguous in case of empty mappings at either end
// of the range, bail out in that case.
if (Expanded.empty())
- return llvm::None;
-
- const syntax::Token *BeginSpelled;
- const Mapping *BeginMapping;
- std::tie(BeginSpelled, BeginMapping) =
- spelledForExpandedToken(&Expanded.front());
-
- const syntax::Token *LastSpelled;
- const Mapping *LastMapping;
- std::tie(LastSpelled, LastMapping) =
- spelledForExpandedToken(&Expanded.back());
+ return std::nullopt;
+ const syntax::Token *First = &Expanded.front();
+ const syntax::Token *Last = &Expanded.back();
+ auto [FirstSpelled, FirstMapping] = spelledForExpandedToken(First);
+ auto [LastSpelled, LastMapping] = spelledForExpandedToken(Last);
- FileID FID = SourceMgr->getFileID(BeginSpelled->location());
+ FileID FID = SourceMgr->getFileID(FirstSpelled->location());
// FIXME: Handle multi-file changes by trying to map onto a common root.
if (FID != SourceMgr->getFileID(LastSpelled->location()))
- return llvm::None;
+ return std::nullopt;
const MarkedFile &File = Files.find(FID)->second;
- // If both tokens are coming from a macro argument expansion, try and map to
- // smallest part of the macro argument. BeginMapping && LastMapping check is
- // only for performance, they are a prerequisite for Expanded.front() and
- // Expanded.back() being part of a macro arg expansion.
- if (BeginMapping && LastMapping &&
- SourceMgr->isMacroArgExpansion(Expanded.front().location()) &&
- SourceMgr->isMacroArgExpansion(Expanded.back().location())) {
- auto CommonRange = findCommonRangeForMacroArgs(Expanded.front(),
- Expanded.back(), *SourceMgr);
- // It might be the case that tokens are arguments of different macro calls,
- // in that case we should continue with the logic below instead of returning
- // an empty range.
- if (CommonRange.isValid())
- return getTokensCovering(File.SpelledTokens, CommonRange, *SourceMgr);
+ // If the range is within one macro argument, the result may be only part of a
+ // Mapping. We must use the general (SourceManager-based) algorithm.
+ if (FirstMapping && FirstMapping == LastMapping &&
+ SourceMgr->isMacroArgExpansion(First->location()) &&
+ SourceMgr->isMacroArgExpansion(Last->location())) {
+ // We use excluded Prev/Next token for bounds checking.
+ SourceLocation Prev = (First == &ExpandedTokens.front())
+ ? SourceLocation()
+ : (First - 1)->location();
+ SourceLocation Next = (Last == &ExpandedTokens.back())
+ ? SourceLocation()
+ : (Last + 1)->location();
+ SourceRange Range = spelledForExpandedSlow(
+ First->location(), Last->location(), Prev, Next, FID, *SourceMgr);
+ if (Range.isInvalid())
+ return std::nullopt;
+ return getTokensCovering(File.SpelledTokens, Range, *SourceMgr);
}
+ // Otherwise, use the fast version based on Mappings.
// Do not allow changes that doesn't cover full expansion.
- unsigned BeginExpanded = Expanded.begin() - ExpandedTokens.data();
- unsigned EndExpanded = Expanded.end() - ExpandedTokens.data();
- if (BeginMapping && BeginExpanded != BeginMapping->BeginExpanded)
- return llvm::None;
- if (LastMapping && LastMapping->EndExpanded != EndExpanded)
- return llvm::None;
- // All is good, return the result.
- return llvm::makeArrayRef(
- BeginMapping ? File.SpelledTokens.data() + BeginMapping->BeginSpelled
- : BeginSpelled,
+ unsigned FirstExpanded = Expanded.begin() - ExpandedTokens.data();
+ unsigned LastExpanded = Expanded.end() - ExpandedTokens.data();
+ if (FirstMapping && FirstExpanded != FirstMapping->BeginExpanded)
+ return std::nullopt;
+ if (LastMapping && LastMapping->EndExpanded != LastExpanded)
+ return std::nullopt;
+ return llvm::ArrayRef(
+ FirstMapping ? File.SpelledTokens.data() + FirstMapping->BeginSpelled
+ : FirstSpelled,
LastMapping ? File.SpelledTokens.data() + LastMapping->EndSpelled
: LastSpelled + 1);
}
@@ -415,10 +506,10 @@ TokenBuffer::spelledForExpanded(llvm::ArrayRef<syntax::Token> Expanded) const {
TokenBuffer::Expansion TokenBuffer::makeExpansion(const MarkedFile &F,
const Mapping &M) const {
Expansion E;
- E.Spelled = llvm::makeArrayRef(F.SpelledTokens.data() + M.BeginSpelled,
- F.SpelledTokens.data() + M.EndSpelled);
- E.Expanded = llvm::makeArrayRef(ExpandedTokens.data() + M.BeginExpanded,
- ExpandedTokens.data() + M.EndExpanded);
+ E.Spelled = llvm::ArrayRef(F.SpelledTokens.data() + M.BeginSpelled,
+ F.SpelledTokens.data() + M.EndSpelled);
+ E.Expanded = llvm::ArrayRef(ExpandedTokens.data() + M.BeginExpanded,
+ ExpandedTokens.data() + M.EndExpanded);
return E;
}
@@ -441,7 +532,7 @@ TokenBuffer::fileForSpelled(llvm::ArrayRef<syntax::Token> Spelled) const {
return File;
}
-llvm::Optional<TokenBuffer::Expansion>
+std::optional<TokenBuffer::Expansion>
TokenBuffer::expansionStartingAt(const syntax::Token *Spelled) const {
assert(Spelled);
const auto &File = fileForSpelled(*Spelled);
@@ -451,7 +542,7 @@ TokenBuffer::expansionStartingAt(const syntax::Token *Spelled) const {
return M.BeginSpelled < SpelledIndex;
});
if (M == File.Mappings.end() || M->BeginSpelled != SpelledIndex)
- return llvm::None;
+ return std::nullopt;
return makeExpansion(File, *M);
}
@@ -483,8 +574,8 @@ syntax::spelledTokensTouching(SourceLocation Loc,
bool AcceptRight = Right != Tokens.end() && Right->location() <= Loc;
bool AcceptLeft =
Right != Tokens.begin() && (Right - 1)->endLocation() >= Loc;
- return llvm::makeArrayRef(Right - (AcceptLeft ? 1 : 0),
- Right + (AcceptRight ? 1 : 0));
+ return llvm::ArrayRef(Right - (AcceptLeft ? 1 : 0),
+ Right + (AcceptRight ? 1 : 0));
}
llvm::ArrayRef<syntax::Token>
@@ -714,7 +805,7 @@ private:
// In the simplest case, skips spelled tokens until finding one that produced
// the NextExpanded token, and creates an empty mapping for them.
// If Drain is provided, skips remaining tokens from that file instead.
- void discard(llvm::Optional<FileID> Drain = llvm::None) {
+ void discard(std::optional<FileID> Drain = std::nullopt) {
SourceLocation Target =
Drain ? SM.getLocForEndOfFile(*Drain)
: SM.getExpansionLoc(
@@ -751,7 +842,7 @@ private:
SpelledTokens[NextSpelled].location() <= KnownEnd)
++NextSpelled;
FlushMapping(); // Emits [NextSpelled, KnownEnd]
- // Now the loop contitues and will emit (KnownEnd, Target).
+ // Now the loop continues and will emit (KnownEnd, Target).
} else {
++NextSpelled;
}
@@ -891,7 +982,7 @@ std::string TokenBuffer::dumpForTests() const {
OS << "expanded tokens:\n"
<< " ";
// (!) we do not show '<eof>'.
- DumpTokens(OS, llvm::makeArrayRef(ExpandedTokens).drop_back());
+ DumpTokens(OS, llvm::ArrayRef(ExpandedTokens).drop_back());
OS << "\n";
std::vector<FileID> Keys;
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 6314615f83c8..8966c12ef7c1 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -98,7 +98,7 @@ static bool ignoreExtraCC1Commands(const driver::Compilation *Compilation) {
OffloadCompilation = true;
if (Jobs.size() > 1) {
- for (auto A : Actions){
+ for (auto *A : Actions){
// On MacOSX real actions may end up being wrapped in BindArchAction
if (isa<driver::BindArchAction>(A))
A = *A->input_begin();
@@ -161,7 +161,7 @@ getCC1Arguments(DiagnosticsEngine *Diagnostics,
/// Returns a clang build invocation initialized from the CC1 flags.
CompilerInvocation *newInvocation(DiagnosticsEngine *Diagnostics,
- const llvm::opt::ArgStringList &CC1Args,
+ ArrayRef<const char *> CC1Args,
const char *const BinaryName) {
assert(!CC1Args.empty() && "Must at least contain the program name!");
CompilerInvocation *Invocation = new CompilerInvocation;
@@ -339,7 +339,7 @@ ToolInvocation::~ToolInvocation() {
}
bool ToolInvocation::run() {
- std::vector<const char*> Argv;
+ llvm::opt::ArgStringList Argv;
for (const std::string &Str : CommandLine)
Argv.push_back(Str.c_str());
const char *const BinaryName = Argv[0];
@@ -362,6 +362,17 @@ bool ToolInvocation::run() {
SourceManager SrcMgr(*Diagnostics, *Files);
Diagnostics->setSourceManager(&SrcMgr);
+ // We already have a cc1, just create an invocation.
+ if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") {
+ ArrayRef<const char *> CC1Args = ArrayRef(Argv).drop_front();
+ std::unique_ptr<CompilerInvocation> Invocation(
+ newInvocation(&*Diagnostics, CC1Args, BinaryName));
+ if (Diagnostics->hasErrorOccurred())
+ return false;
+ return Action->runInvocation(std::move(Invocation), Files,
+ std::move(PCHContainerOps), DiagConsumer);
+ }
+
const std::unique_ptr<driver::Driver> Driver(
newDriver(&*Diagnostics, BinaryName, &Files->getVirtualFileSystem()));
// The "input file not found" diagnostics from the driver are useful.
@@ -371,7 +382,7 @@ bool ToolInvocation::run() {
if (!Files->getFileSystemOpts().WorkingDir.empty())
Driver->setCheckInputsExist(false);
const std::unique_ptr<driver::Compilation> Compilation(
- Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
+ Driver->BuildCompilation(llvm::ArrayRef(Argv)));
if (!Compilation)
return false;
const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments(
diff --git a/clang/lib/Tooling/Transformer/Parsing.cpp b/clang/lib/Tooling/Transformer/Parsing.cpp
index 4f41e2e90def..53a78e8df22a 100644
--- a/clang/lib/Tooling/Transformer/Parsing.cpp
+++ b/clang/lib/Tooling/Transformer/Parsing.cpp
@@ -14,11 +14,11 @@
#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Transformer/RangeSelector.h"
#include "clang/Tooling/Transformer/SourceCode.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -46,7 +46,7 @@ struct ParseState {
};
// Represents an intermediate result returned by a parsing function. Functions
-// that don't generate values should use `llvm::None`
+// that don't generate values should use `std::nullopt`
template <typename ResultType> struct ParseProgress {
ParseState State;
// Intermediate result generated by the Parser.
@@ -120,11 +120,11 @@ getBinaryRangeSelectors() {
}
template <typename Element>
-llvm::Optional<Element> findOptional(const llvm::StringMap<Element> &Map,
- llvm::StringRef Key) {
+std::optional<Element> findOptional(const llvm::StringMap<Element> &Map,
+ llvm::StringRef Key) {
auto it = Map.find(Key);
if (it == Map.end())
- return llvm::None;
+ return std::nullopt;
return it->second;
}
@@ -152,12 +152,12 @@ static StringRef consumeWhitespace(StringRef S) {
// Parses a single expected character \c c from \c State, skipping preceding
// whitespace. Error if the expected character isn't found.
-static ExpectedProgress<llvm::NoneType> parseChar(char c, ParseState State) {
+static ExpectedProgress<std::nullopt_t> parseChar(char c, ParseState State) {
State.Input = consumeWhitespace(State.Input);
if (State.Input.empty() || State.Input.front() != c)
return makeParseError(State,
("expected char not found: " + llvm::Twine(c)).str());
- return makeParseProgress(advance(State, 1), llvm::None);
+ return makeParseProgress(advance(State, 1), std::nullopt);
}
// Parses an identitifer "token" -- handles preceding whitespace.
diff --git a/clang/lib/Tooling/Transformer/RewriteRule.cpp b/clang/lib/Tooling/Transformer/RewriteRule.cpp
index 3e76489782f3..eefddc349404 100644
--- a/clang/lib/Tooling/Transformer/RewriteRule.cpp
+++ b/clang/lib/Tooling/Transformer/RewriteRule.cpp
@@ -13,7 +13,6 @@
#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"
@@ -39,8 +38,8 @@ translateEdits(const MatchResult &Result, ArrayRef<ASTEdit> ASTEdits) {
Expected<CharSourceRange> Range = E.TargetRange(Result);
if (!Range)
return Range.takeError();
- llvm::Optional<CharSourceRange> EditRange =
- tooling::getRangeForEdit(*Range, *Result.Context);
+ std::optional<CharSourceRange> EditRange =
+ tooling::getFileRangeForEdit(*Range, *Result.Context);
// FIXME: let user specify whether to treat this case as an error or ignore
// it as is currently done. This behavior is problematic in that it hides
// failures from bad ranges. Also, the behavior here differs from
@@ -50,17 +49,27 @@ translateEdits(const MatchResult &Result, ArrayRef<ASTEdit> ASTEdits) {
// produces a bad range, whereas the latter will simply ignore A.
if (!EditRange)
return SmallVector<Edit, 0>();
- auto Replacement = E.Replacement->eval(Result);
- if (!Replacement)
- return Replacement.takeError();
- auto Metadata = E.Metadata(Result);
- if (!Metadata)
- return Metadata.takeError();
transformer::Edit T;
T.Kind = E.Kind;
T.Range = *EditRange;
- T.Replacement = std::move(*Replacement);
- T.Metadata = std::move(*Metadata);
+ if (E.Replacement) {
+ auto Replacement = E.Replacement->eval(Result);
+ if (!Replacement)
+ return Replacement.takeError();
+ T.Replacement = std::move(*Replacement);
+ }
+ if (E.Note) {
+ auto Note = E.Note->eval(Result);
+ if (!Note)
+ return Note.takeError();
+ T.Note = std::move(*Note);
+ }
+ if (E.Metadata) {
+ auto Metadata = E.Metadata(Result);
+ if (!Metadata)
+ return Metadata.takeError();
+ T.Metadata = std::move(*Metadata);
+ }
Edits.push_back(std::move(T));
}
return Edits;
@@ -121,6 +130,13 @@ ASTEdit transformer::changeTo(RangeSelector Target, TextGenerator Replacement) {
return E;
}
+ASTEdit transformer::note(RangeSelector Anchor, TextGenerator Note) {
+ ASTEdit E;
+ E.TargetRange = transformer::before(Anchor);
+ E.Note = std::move(Note);
+ return E;
+}
+
namespace {
/// A \c TextGenerator that always returns a fixed string.
class SimpleTextGenerator : public MatchComputation<std::string> {
@@ -433,7 +449,7 @@ SourceLocation transformer::detail::getRuleMatchLoc(const MatchResult &Result) {
auto &NodesMap = Result.Nodes.getMap();
auto Root = NodesMap.find(RootID);
assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
- llvm::Optional<CharSourceRange> RootRange = tooling::getRangeForEdit(
+ std::optional<CharSourceRange> RootRange = tooling::getFileRangeForEdit(
CharSourceRange::getTokenRange(Root->second.getSourceRange()),
*Result.Context);
if (RootRange)
diff --git a/clang/lib/Tooling/Transformer/SourceCode.cpp b/clang/lib/Tooling/Transformer/SourceCode.cpp
index 26b204851f05..35edc261ef09 100644
--- a/clang/lib/Tooling/Transformer/SourceCode.cpp
+++ b/clang/lib/Tooling/Transformer/SourceCode.cpp
@@ -50,8 +50,9 @@ CharSourceRange clang::tooling::maybeExtendRange(CharSourceRange Range,
return CharSourceRange::getTokenRange(Range.getBegin(), Tok.getLocation());
}
-llvm::Error clang::tooling::validateEditRange(const CharSourceRange &Range,
- const SourceManager &SM) {
+static llvm::Error validateRange(const CharSourceRange &Range,
+ const SourceManager &SM,
+ bool AllowSystemHeaders) {
if (Range.isInvalid())
return llvm::make_error<StringError>(errc::invalid_argument,
"Invalid range");
@@ -60,10 +61,12 @@ llvm::Error clang::tooling::validateEditRange(const CharSourceRange &Range,
return llvm::make_error<StringError>(
errc::invalid_argument, "Range starts or ends in a macro expansion");
- if (SM.isInSystemHeader(Range.getBegin()) ||
- SM.isInSystemHeader(Range.getEnd()))
- return llvm::make_error<StringError>(errc::invalid_argument,
- "Range is in system header");
+ if (!AllowSystemHeaders) {
+ if (SM.isInSystemHeader(Range.getBegin()) ||
+ SM.isInSystemHeader(Range.getEnd()))
+ return llvm::make_error<StringError>(errc::invalid_argument,
+ "Range is in system header");
+ }
std::pair<FileID, unsigned> BeginInfo = SM.getDecomposedLoc(Range.getBegin());
std::pair<FileID, unsigned> EndInfo = SM.getDecomposedLoc(Range.getEnd());
@@ -72,33 +75,74 @@ llvm::Error clang::tooling::validateEditRange(const CharSourceRange &Range,
errc::invalid_argument, "Range begins and ends in different files");
if (BeginInfo.second > EndInfo.second)
- return llvm::make_error<StringError>(
- errc::invalid_argument, "Range's begin is past its end");
+ return llvm::make_error<StringError>(errc::invalid_argument,
+ "Range's begin is past its end");
return llvm::Error::success();
}
-llvm::Optional<CharSourceRange>
-clang::tooling::getRangeForEdit(const CharSourceRange &EditRange,
+llvm::Error clang::tooling::validateEditRange(const CharSourceRange &Range,
+ const SourceManager &SM) {
+ return validateRange(Range, SM, /*AllowSystemHeaders=*/false);
+}
+
+static bool spelledInMacroDefinition(SourceLocation Loc,
+ const SourceManager &SM) {
+ while (Loc.isMacroID()) {
+ const auto &Expansion = SM.getSLocEntry(SM.getFileID(Loc)).getExpansion();
+ if (Expansion.isMacroArgExpansion()) {
+ // Check the spelling location of the macro arg, in case the arg itself is
+ // in a macro expansion.
+ Loc = Expansion.getSpellingLoc();
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+static CharSourceRange getRange(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);
+ const LangOptions &LangOpts,
+ bool IncludeMacroExpansion) {
+ CharSourceRange Range;
+ if (IncludeMacroExpansion) {
+ Range = Lexer::makeFileCharRange(EditRange, SM, LangOpts);
+ } else {
+ if (spelledInMacroDefinition(EditRange.getBegin(), SM) ||
+ spelledInMacroDefinition(EditRange.getEnd(), SM))
+ return {};
+
+ auto B = SM.getSpellingLoc(EditRange.getBegin());
+ auto E = SM.getSpellingLoc(EditRange.getEnd());
+ if (EditRange.isTokenRange())
+ E = Lexer::getLocForEndOfToken(E, 0, SM, LangOpts);
+ Range = CharSourceRange::getCharRange(B, E);
+ }
+ return Range;
+}
+
+std::optional<CharSourceRange> clang::tooling::getFileRangeForEdit(
+ const CharSourceRange &EditRange, const SourceManager &SM,
+ const LangOptions &LangOpts, bool IncludeMacroExpansion) {
+ CharSourceRange Range =
+ getRange(EditRange, SM, LangOpts, IncludeMacroExpansion);
bool IsInvalid = llvm::errorToBool(validateEditRange(Range, SM));
if (IsInvalid)
- return llvm::None;
+ return std::nullopt;
return Range;
+}
+std::optional<CharSourceRange> clang::tooling::getFileRange(
+ const CharSourceRange &EditRange, const SourceManager &SM,
+ const LangOptions &LangOpts, bool IncludeMacroExpansion) {
+ CharSourceRange Range =
+ getRange(EditRange, SM, LangOpts, IncludeMacroExpansion);
+ bool IsInvalid =
+ llvm::errorToBool(validateRange(Range, SM, /*AllowSystemHeaders=*/true));
+ if (IsInvalid)
+ return std::nullopt;
+ return Range;
}
static bool startsWithNewline(const SourceManager &SM, const Token &Tok) {
diff --git a/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp b/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp
index 7496e968469c..10588a383da0 100644
--- a/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp
+++ b/clang/lib/Tooling/Transformer/SourceCodeBuilders.cpp
@@ -72,17 +72,17 @@ bool tooling::isKnownPointerLikeType(QualType Ty, ASTContext &Context) {
return match(PointerLikeTy, Ty, Context).size() > 0;
}
-llvm::Optional<std::string> tooling::buildParens(const Expr &E,
- const ASTContext &Context) {
+std::optional<std::string> tooling::buildParens(const Expr &E,
+ const ASTContext &Context) {
StringRef Text = getText(E, Context);
if (Text.empty())
- return llvm::None;
+ return std::nullopt;
if (mayEverNeedParens(E))
return ("(" + Text + ")").str();
return Text.str();
}
-llvm::Optional<std::string>
+std::optional<std::string>
tooling::buildDereference(const Expr &E, const ASTContext &Context) {
if (const auto *Op = dyn_cast<UnaryOperator>(&E))
if (Op->getOpcode() == UO_AddrOf) {
@@ -90,21 +90,21 @@ tooling::buildDereference(const Expr &E, const ASTContext &Context) {
StringRef Text =
getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
if (Text.empty())
- return llvm::None;
+ return std::nullopt;
return Text.str();
}
StringRef Text = getText(E, Context);
if (Text.empty())
- return llvm::None;
+ return std::nullopt;
// Add leading '*'.
if (needParensAfterUnaryOperator(E))
return ("*(" + Text + ")").str();
return ("*" + Text).str();
}
-llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E,
- const ASTContext &Context) {
+std::optional<std::string> tooling::buildAddressOf(const Expr &E,
+ const ASTContext &Context) {
if (E.isImplicitCXXThis())
return std::string("this");
if (const auto *Op = dyn_cast<UnaryOperator>(&E))
@@ -113,13 +113,13 @@ llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E,
StringRef Text =
getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
if (Text.empty())
- return llvm::None;
+ return std::nullopt;
return Text.str();
}
// Add leading '&'.
StringRef Text = getText(E, Context);
if (Text.empty())
- return llvm::None;
+ return std::nullopt;
if (needParensAfterUnaryOperator(E)) {
return ("&(" + Text + ")").str();
}
@@ -128,7 +128,7 @@ llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E,
// Append the appropriate access operation (syntactically) to `E`, assuming `E`
// is a non-pointer value.
-static llvm::Optional<std::string>
+static std::optional<std::string>
buildAccessForValue(const Expr &E, const ASTContext &Context) {
if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
if (Op->getOpcode() == UO_Deref) {
@@ -136,7 +136,7 @@ buildAccessForValue(const Expr &E, const ASTContext &Context) {
const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
StringRef DerefText = getText(*SubExpr, Context);
if (DerefText.empty())
- return llvm::None;
+ return std::nullopt;
if (needParensBeforeDotOrArrow(*SubExpr))
return ("(" + DerefText + ")->").str();
return (DerefText + "->").str();
@@ -145,7 +145,7 @@ buildAccessForValue(const Expr &E, const ASTContext &Context) {
// Add following '.'.
StringRef Text = getText(E, Context);
if (Text.empty())
- return llvm::None;
+ return std::nullopt;
if (needParensBeforeDotOrArrow(E)) {
return ("(" + Text + ").").str();
}
@@ -154,7 +154,7 @@ buildAccessForValue(const Expr &E, const ASTContext &Context) {
// Append the appropriate access operation (syntactically) to `E`, assuming `E`
// is a pointer value.
-static llvm::Optional<std::string>
+static std::optional<std::string>
buildAccessForPointer(const Expr &E, const ASTContext &Context) {
if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
if (Op->getOpcode() == UO_AddrOf) {
@@ -162,7 +162,7 @@ buildAccessForPointer(const Expr &E, const ASTContext &Context) {
const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
StringRef DerefText = getText(*SubExpr, Context);
if (DerefText.empty())
- return llvm::None;
+ return std::nullopt;
if (needParensBeforeDotOrArrow(*SubExpr))
return ("(" + DerefText + ").").str();
return (DerefText + ".").str();
@@ -171,19 +171,19 @@ buildAccessForPointer(const Expr &E, const ASTContext &Context) {
// Add following '->'.
StringRef Text = getText(E, Context);
if (Text.empty())
- return llvm::None;
+ return std::nullopt;
if (needParensBeforeDotOrArrow(E))
return ("(" + Text + ")->").str();
return (Text + "->").str();
}
-llvm::Optional<std::string> tooling::buildDot(const Expr &E,
- const ASTContext &Context) {
+std::optional<std::string> tooling::buildDot(const Expr &E,
+ const ASTContext &Context) {
return buildAccessForValue(E, Context);
}
-llvm::Optional<std::string> tooling::buildArrow(const Expr &E,
- const ASTContext &Context) {
+std::optional<std::string> tooling::buildArrow(const Expr &E,
+ const ASTContext &Context) {
return buildAccessForPointer(E, Context);
}
@@ -210,11 +210,12 @@ static bool treatLikePointer(QualType Ty, PLTClass C, ASTContext &Context) {
// FIXME: move over the other `maybe` functionality from Stencil. Should all be
// in one place.
-llvm::Optional<std::string> tooling::buildAccess(const Expr &RawExpression,
- ASTContext &Context,
- PLTClass Classification) {
+std::optional<std::string> tooling::buildAccess(const Expr &RawExpression,
+ ASTContext &Context,
+ PLTClass Classification) {
if (RawExpression.isImplicitCXXThis())
- // Return the empty string, because `None` signifies some sort of failure.
+ // Return the empty string, because `std::nullopt` signifies some sort of
+ // failure.
return std::string();
const Expr *E = RawExpression.IgnoreImplicitAsWritten();
diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp
index 82dd4a2587b5..2198aefddc9f 100644
--- a/clang/lib/Tooling/Transformer/Stencil.cpp
+++ b/clang/lib/Tooling/Transformer/Stencil.cpp
@@ -152,7 +152,7 @@ public:
if (E == nullptr)
return llvm::make_error<StringError>(errc::invalid_argument,
"Id not bound or not Expr: " + Id);
- llvm::Optional<std::string> Source;
+ std::optional<std::string> Source;
switch (Op) {
case UnaryNodeOperator::Parens:
Source = tooling::buildParens(*E, *Match.Context);
@@ -277,7 +277,7 @@ public:
if (E == nullptr)
return llvm::make_error<StringError>(errc::invalid_argument,
"Id not bound: " + BaseId);
- llvm::Optional<std::string> S = tooling::buildAccess(*E, *Match.Context);
+ std::optional<std::string> S = tooling::buildAccess(*E, *Match.Context);
if (!S)
return llvm::make_error<StringError>(
errc::invalid_argument,